summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBilly Tetrud <billy.tetrud@gmail.com>2021-08-04 23:39:34 -0700
committerbitcoindev <bitcoindev@gnusha.org>2021-08-05 06:39:55 +0000
commitbac11352615eb45fe7b427b559667e7ed9385ba9 (patch)
treeb78a74f9307e9e1b75d92aa8ef5fb11cd5c651e7
parent5fcb7b755312e89db2d2144449494012dc802cae (diff)
downloadpi-bitcoindev-bac11352615eb45fe7b427b559667e7ed9385ba9.tar.gz
pi-bitcoindev-bac11352615eb45fe7b427b559667e7ed9385ba9.zip
Re: [bitcoin-dev] Exploring: limiting transaction output amount as a function of total input value
-rw-r--r--82/be7bdb33af1ba00d2118b97e6d472951e24eaa921
1 files changed, 921 insertions, 0 deletions
diff --git a/82/be7bdb33af1ba00d2118b97e6d472951e24eaa b/82/be7bdb33af1ba00d2118b97e6d472951e24eaa
new file mode 100644
index 000000000..517282e21
--- /dev/null
+++ b/82/be7bdb33af1ba00d2118b97e6d472951e24eaa
@@ -0,0 +1,921 @@
+Return-Path: <fresheneesz@gmail.com>
+Received: from smtp1.osuosl.org (smtp1.osuosl.org [140.211.166.138])
+ by lists.linuxfoundation.org (Postfix) with ESMTP id 21E23C000E
+ for <bitcoin-dev@lists.linuxfoundation.org>;
+ Thu, 5 Aug 2021 06:39:55 +0000 (UTC)
+Received: from localhost (localhost [127.0.0.1])
+ by smtp1.osuosl.org (Postfix) with ESMTP id 0663582BC0
+ for <bitcoin-dev@lists.linuxfoundation.org>;
+ Thu, 5 Aug 2021 06:39:55 +0000 (UTC)
+X-Virus-Scanned: amavisd-new at osuosl.org
+X-Spam-Flag: NO
+X-Spam-Score: -2.098
+X-Spam-Level:
+X-Spam-Status: No, score=-2.098 tagged_above=-999 required=5
+ tests=[BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1,
+ DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001,
+ HTML_MESSAGE=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001,
+ SPF_PASS=-0.001] autolearn=ham autolearn_force=no
+Authentication-Results: smtp1.osuosl.org (amavisd-new);
+ dkim=pass (2048-bit key) header.d=gmail.com
+Received: from smtp1.osuosl.org ([127.0.0.1])
+ by localhost (smtp1.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)
+ with ESMTP id fRKQAJtdZe2b
+ for <bitcoin-dev@lists.linuxfoundation.org>;
+ Thu, 5 Aug 2021 06:39:52 +0000 (UTC)
+X-Greylist: whitelisted by SQLgrey-1.8.0
+Received: from mail-ej1-x636.google.com (mail-ej1-x636.google.com
+ [IPv6:2a00:1450:4864:20::636])
+ by smtp1.osuosl.org (Postfix) with ESMTPS id 220DA82AF8
+ for <bitcoin-dev@lists.linuxfoundation.org>;
+ Thu, 5 Aug 2021 06:39:52 +0000 (UTC)
+Received: by mail-ej1-x636.google.com with SMTP id o5so7770123ejy.2
+ for <bitcoin-dev@lists.linuxfoundation.org>;
+ Wed, 04 Aug 2021 23:39:51 -0700 (PDT)
+DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025;
+ h=mime-version:references:in-reply-to:from:date:message-id:subject:to
+ :cc; bh=XplVH7Pa7wHDfRBd0t0QhZCPoDY5jgHvxCS3LOEeG20=;
+ b=Vjw7N4ywLxLL/Wuv3hMmviv/iJS+8FR0WLGFLIk8QgL9svkL5lWuEdWtwBw376GGzD
+ +nJSUygx/Z1mjiX6zxt7mNXft1PsF9QfCMFYnsz+uuvpBFBJiJBP/66E65WTi3ZgqFL/
+ aGy8t9Uz/qk6kkqpWgeOAmCQ5UBqaTaseofoKw7Vjrmo8hFt1hbKFiVz3GpYQYLnChPN
+ +DWifis+mfxnVzHNK9NPN+uZtiGVzoo/RdnB8rU6/jQnek9+oPfRNOQWsvS2fhYDxkHR
+ xY44upBR7hwugLVH9f+/jL1XLDMLPKNbXZu+qhQ7YTdIwM0ZTO+UE7yPzqnN9Oh9L3Wo
+ 60AQ==
+X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
+ d=1e100.net; s=20161025;
+ h=x-gm-message-state:mime-version:references:in-reply-to:from:date
+ :message-id:subject:to:cc;
+ bh=XplVH7Pa7wHDfRBd0t0QhZCPoDY5jgHvxCS3LOEeG20=;
+ b=rW7/RBOe0Lo89yWJAwnTp24AaiHD4X2JXgOyWfuI41BVhnTdt21Av9NRJDzwrl60H6
+ LkI7mHZZ/r74SZl2wreJOT7oBRYHghuVjR/tV3tnf6Ot8PHUOoSpYVZnbIjoD1K+TwTc
+ PEvSgbodiosu7sy/9K40QploQ2PUn6SQzkgc4IgFB1394NOHbx6uig546FdzkfIL4ECE
+ d4MnEAQ/xr6EtHXZIrPPuVj06oUof0n3pU8YE1I5LCsnoMA/XdGIS3TN8YxzJ0Tg5oc6
+ KHfOHqma8iDvt/cUYuJ7oG3iSFMRD8hwVXH2GFvK1k4jkv0GRTOSWg30E7BM+XxZySBI
+ 67nw==
+X-Gm-Message-State: AOAM531vBLdkU/wA5++ftOURjCuzp66W9ksZV9Yp5ly+JM6HdXqLe6Ar
+ a4o0pKfRKhVa5DRG32kSuq/FIqkwwY5coTyT2ec=
+X-Google-Smtp-Source: ABdhPJxeMnSp5HySDn/S3jygdMNQGCSH3d/Cl/ARIKHe6xuTUvdyib0LQyQ9MINFkcQlOlPy50QUKztnAhX9mLmyw9w=
+X-Received: by 2002:a17:906:4d94:: with SMTP id
+ s20mr3161402eju.152.1628145590280;
+ Wed, 04 Aug 2021 23:39:50 -0700 (PDT)
+MIME-Version: 1.0
+References: <CAJ4-pEAETy7_vOez5H32mZLg9gRpRajvoBjZyBT_v=DEqdQJvQ@mail.gmail.com>
+ <CAJ4-pEAxqvMc89xSp9NXXNwnpJ3NhMqE6p=dRbpYCAB3Gbb14g@mail.gmail.com>
+ <CAGpPWDbidOBqUXHpoteAf50WXeMi392PJZmApyT8h2Gk6n1gKQ@mail.gmail.com>
+ <CAJ4-pEAi-ooVMvJmeXhrS9J6-JVQ1jxy1On1NTQYpOSD49cbrw@mail.gmail.com>
+In-Reply-To: <CAJ4-pEAi-ooVMvJmeXhrS9J6-JVQ1jxy1On1NTQYpOSD49cbrw@mail.gmail.com>
+From: Billy Tetrud <billy.tetrud@gmail.com>
+Date: Wed, 4 Aug 2021 23:39:34 -0700
+Message-ID: <CAGpPWDZNrPT9Li_neNOr3BDGdusMorWjFodNPo6YqNC3SDaf3w@mail.gmail.com>
+To: Zac Greenwood <zachgrw@gmail.com>
+Content-Type: multipart/alternative; boundary="0000000000008d270e05c8ca2ffb"
+X-Mailman-Approved-At: Thu, 05 Aug 2021 10:16:49 +0000
+Cc: Bitcoin Protocol Discussion <bitcoin-dev@lists.linuxfoundation.org>
+Subject: Re: [bitcoin-dev] Exploring: limiting transaction output amount as
+ a function of total input value
+X-BeenThere: bitcoin-dev@lists.linuxfoundation.org
+X-Mailman-Version: 2.1.15
+Precedence: list
+List-Id: Bitcoin Protocol Discussion <bitcoin-dev.lists.linuxfoundation.org>
+List-Unsubscribe: <https://lists.linuxfoundation.org/mailman/options/bitcoin-dev>,
+ <mailto:bitcoin-dev-request@lists.linuxfoundation.org?subject=unsubscribe>
+List-Archive: <http://lists.linuxfoundation.org/pipermail/bitcoin-dev/>
+List-Post: <mailto:bitcoin-dev@lists.linuxfoundation.org>
+List-Help: <mailto:bitcoin-dev-request@lists.linuxfoundation.org?subject=help>
+List-Subscribe: <https://lists.linuxfoundation.org/mailman/listinfo/bitcoin-dev>,
+ <mailto:bitcoin-dev-request@lists.linuxfoundation.org?subject=subscribe>
+X-List-Received-Date: Thu, 05 Aug 2021 06:39:55 -0000
+
+--0000000000008d270e05c8ca2ffb
+Content-Type: text/plain; charset="UTF-8"
+
+> A maximum amount is allowed to be spent within EVERY epoch.
+
+It sounds like you're proposing an opcode that takes in epochStart and
+epochEnd as parameters. I still don't understand why its useful to specify
+those as absolute block heights. You mentioned that this enables more
+straightforward validation logic, but I don't see how. Eg, if you have a
+UTXO encumbered by rateLimit(epochStart = 800100, epochEnd = 800200, limit
+= 100k, remain = 100k), what happens if you don't spend that UTXO before
+block 800200? Is the output no longer rate limited then? Or is the opcode
+calculating 800200-800100 = 100 and applying a rate limit for the next
+epoch? If the first, then the UTXO must be spent within one epoch to remain
+rate limited. If the second, then it seems nearly identical to simply
+specifying window=100 as a parameter instead of epochStart and epochEnd.
+
+> then there must be only a single (rate-limited) output
+
+This rule would make transactions tricky if you're sending money into
+someone else's wallet that may be rate limited. If the requirement is that
+only you yourself can send money into a rate limited wallet, then this
+point is moot but it would be ideal to not have such a requirement.
+
+This is how I'd imagine creating an opcode like this:
+
+rateLimit(windowSize = 144 blocks, limit = 100k sats)
+
+This would define that the epoch is 1 day's worth of blocks. This would
+evenly divide bitcoin's retarget period and so each window would start and
+end at those dividing lines (eg the first 144 blocks of the retargetting
+period, then the second, then the third, etc).
+
+When this output is spent, it ensures that there's a maximum of 100k sats
+is sent to addresses other than the originating address. It also records
+the amount spent in the current 144 block window for that address (eg by
+simply recording the already-spent amount on the resulting UTXO and having
+an index that allows looking up UTXOs by address and adding them up). That
+way, when any output from that address is spent again, if a new 144 block
+window has started, the limit is reset, but if its still within the same
+window, the already-spent amounts for UTXOs from that address are added up
+and subtracted from the limit, and that number is the remaining limit a
+subsequent transaction needs to adhere to.
+
+This way, 3rd party could send transactions into an address like this, and
+multiple outputs can be combined and used to spend to arbitrary outputs (up
+to the rate limit of course).
+
+On Wed, Aug 4, 2021 at 3:48 AM Zac Greenwood <zachgrw@gmail.com> wrote:
+
+> > Ah I see, this is all limited to within a single epoch.
+>
+> No, that wouldn't be useful. A maximum amount is allowed to be spent
+> within EVERY epoch.
+>
+> Consider an epoch length of 100 blocks with a spend limit of 200k per
+> epoch. The following is allowed:
+>
+> epoch1 (800101 - 800200): spend 120k in block 800140. Remaining for
+> epoch1: 80k;
+> epoch1 (800101 - 800200): spend another 60k in block 800195. Remaining for
+> epoch1: 20k;
+> epoch2 (800201 - 800300): spend 160k in block 800201. Remaining for
+> epoch2: 40k.
+>
+> Since the limit pertains to each individual epoch, it is allowed to spend
+> up to the full limit at the start of any new epoch. In this example, the
+> spending was as follows:
+>
+> 800140: 120k
+> 800195: 60k
+> 800201: 160k.
+>
+> Note that in a span of 62 blocks a total of 340k sats was spent. This may
+> seem to violate the 200k limit per 100 blocks, but this is the result of
+> using a per-epoch limit. This allows a maximum of 400k to be spent in 2
+> blocks llke so: 200k in the last block of an epoch and another 200k in the
+> first block of the next epoch. However this is inconsequential for the
+> intended goal of rate-limiting which is to enable small spends over time
+> from a large amount and to prevent theft of a large amount with a single
+> transaction.
+>
+> To explain the proposed design more clearly, I have renamed the params as
+> follows:
+>
+> epochStart: block height of first block of the current epoch (was: h0);
+> epochEnd: block height of last block of the current epoch (was: h1);
+> limit: the maximum total amount allowed to be spent within the current
+> epoch (was: a);
+> remain: the remaining amount allowed to be spent within the current epoch
+> (was: a_remaining);
+>
+> Also, to illustrate that the params are specific to a transaction, I will
+> hence precede the param with the transaction name like so:
+> tx8_limit, tx31c_remain, tx42z_epochStart, ... etc.
+>
+> For simplicity, only transactions with no more than one rate-limited input
+> are considered, and with no more than two outputs: one rate-limited change
+> output, and a normal (not rate-limited) output.
+>
+> Normally, a simple transaction generates two outputs: one for a payment to
+> a third party and one for the change address. Again for simplicity, we
+> demand that a transaction which introduces rate-limiting must have only a
+> single, rate-limited output. The validation rule might be: if a transaction
+> has rate-limiting params and none of its inputs are rate-limited, then
+> there must be only a single (rate-limited) output (and no second or change
+> output).
+>
+> Consider rate limiting transactions tx1 having one or more normal (non
+> rate-limited) inputs:
+>
+> tx1 gets included at block height 800004;
+> The inputs of tx1 are not rate-limited => tx1 must have only a single
+> output which will become rate-limited;
+> params: tx1_epochStart=800001, tx1_epochEnd=800100, tx1_limit=200k,
+> tx1_remain=200k;
+> => This defines that an epoch has 100 blocks and no more than 200k sats
+> may be spent in any one epoch. Within the current epoch, 200k sats may
+> still be spent.
+>
+> This transaction begins to rate-limit a set of inputs, so it has a single
+> rate-limited output.
+> Let's explore transactions that have the output of tx1 as their input. I
+> will denote the output of tx1 as "out1".
+>
+> tx2a has out1 as its only input;
+> tx2a spends 50k sats and gets included at block height 803050;
+> tx2a specifies the following params for its change output "chg2a":
+> chg2a_epochStart=803001, chg2a_epochEnd=803100;
+> chg2a_limit=200k, chg2a_remain=150k.
+>
+> To enforce rate-limiting, the system must validate the params of the
+> change output chg2a to ensure that overspending is not allowed.
+>
+> The above params are allowed because:
+> => 1. the epoch does not become smaller than 100 blocks [(chg2a_epochEnd -
+> chg2a_epochStart) >= (tx1_epochEnd - tx1_epochStart)]
+> => 2. tx1_limit has not been increased (ch2a_limit <= tx1_limit)
+> => 3. the amount spent (50k sats) does not exceed tx1_remain AND does not
+> exceed chg2a_limit;
+> => 4. chg2a_remain" is 50k sats less than chg2a_limit.
+>
+> A transaction may also further constrain further spending like so:
+>
+> tx2b has out1as its only input;
+> tx2b spends 8k sats and gets included at block height 808105;
+> tx2b specifies the following params for its change output "chg2b":
+> chg2b_epochStart=808101, chg2b_epochEnd=808250;
+> chg2b_limit=10k, chg2b_remain=0.
+>
+> These params are allowed because:
+> => 1. the epoch does not become smaller than100 blocks. It is fine to
+> increase the epoch to 150 blocks because it does not enable exceeding the
+> original rate-limit;
+> => 2. the limit (chg2b_limit) has been decreased to 10k sats, further
+> restricting the maximum amount allowed to be spent within the current and
+> any subsequent epochs;
+> => 3. the amount spent (10k sats) does not exceed tx1_remain AND does not
+> exceed chg2b_limit;
+> => 4. chg2b_remain has been set to zero, meaning that within the current
+> epoch (block height 808101 to and including 808250), tx2b cannot be used as
+> a spending input to any transaction.
+>
+> Starting from block height 808251, a new epoch will start and the
+> rate-limited output of tx2b may again be used as an input for a subsequent
+> rate-limited transaction tx3b. This transaction tx3b must again be
+> accompanied by params that do not violate the rate-limit as defined by the
+> params of tx2b and which are stored with output out2b. So, the epoch of
+> tx3b must be at minimum 150 blocks, the maximum that is allowed to be spent
+> per epoch is at most 10k sats, and chg3b_remain must be decreased by at
+> least the amount spent by tx3b.
+>
+> From the above, the rate-limiting mechanics should hopefully be clear and
+> full set of validation rules could be defined in a more generalized way
+> with little additional effort.
+>
+> Note that I conveniently avoided talking about how to represent the
+> parameters within transactions or outputs, simply because I currently lack
+> enough understanding to reason about this. I am hoping that others may
+> offer help.
+>
+> Zac
+>
+>
+> On Tue, Aug 3, 2021 at 8:12 PM Billy Tetrud <billy.tetrud@gmail.com>
+> wrote:
+>
+>> > To enable more straightforward validation logic.
+>> > within the current epoch
+>>
+>> Ah I see, this is all limited to within a single epoch. I think that
+>> sufficiently limits the window of time in which nodes have to store
+>> information for rate limited outputs. However, I don't see how specifying
+>> block ranges simplifies the logic - wouldn't this complicate the logic with
+>> additional user-specified constraints? It also prevents the output from
+>> being able to be rate limited over the span of multiple epochs, which would
+>> seem to make it a lot more difficult to use for certain types of wallets
+>> (eg cold wallets).
+>>
+>> I think I see the logic of your 'remaining' parameter there. If you start
+>> with a single rate-limited input, you can split that into many outputs,
+>> only one of which have a 'remaining' balance. The rest can simply remain
+>> unspendable for the rest of the epoch. That way these things don't need to
+>> be tied together. However, that doesn't solve the problem of 3rd parties
+>> being able to send money into the wallet.
+>>
+>> > I don't believe that the marginal added functionality would justify the
+>> increased implementation complexity
+>>
+>> Perhaps, but I think there is a lot of benefit in allowing these kinds of
+>> things to operate as similarly as possible to normal transactions, for one
+>> because of usability reasons. If each opcode has its own quirks that are
+>> not intuitively related to their purpose (eg if a rate-limited wallet had
+>> no way to get a receiving address), it would confuse end-users (eg who
+>> wonder how to get a receiving address and how they can ask people to send
+>> money into their wallet) or require a lot of technical complexity in
+>> applications (eg to support something like cooperatively connecting with
+>> their wallet so that a transaction can be made that creates a new
+>> single-output for the wallet). A little complexity in this opcode can save
+>> a lot of external complexity here I think.
+>>
+>> > my understanding of Bitcoin is way too low to be able to write a BIP
+>> and do the implementation
+>>
+>> You might be able to find people willing to help. I would be willing to
+>> help write the BIP spec. I'm not the right person to help with the
+>> implementation, but perhaps you could find someone else who is. Even if the
+>> BIP isn't adopted, it could be a starting point or inspiration for someone
+>> else to write an improved version.
+>>
+>> On Mon, Aug 2, 2021 at 2:32 AM Zac Greenwood <zachgrw@gmail.com> wrote:
+>>
+>>> [Note: I've moved your reply to the newly started thread]
+>>>
+>>> Hi Billy,
+>>>
+>>> Thank you for your kind and encouraging feedback.
+>>>
+>>> I don't quite understand why you'd want to define a specific span of
+>>>> blocks for the rate limit. Why not just specify the size of the window (in
+>>>> blocks) to rate limit within, and the limit?
+>>>
+>>>
+>>> To enable more straightforward validation logic.
+>>>
+>>> You mentioned change addresses, however, with the parameters you
+>>>> defined, there would be no way to connect together the change address with
+>>>> the original address, meaning they would have completely separate rate
+>>>> limits, which wouldn't work since the change output would ignore the
+>>>> previous rate limit.
+>>>
+>>>
+>>> The rate-limiting parameters must be re-specified for each rate-limited
+>>> input. So, a transaction that has a rate-limited input is only valid if its
+>>> output is itself rate-limited such that it does not violate the
+>>> rate-limiting constraints of its input.
+>>>
+>>> In my thread-starter, I gave the below example of a rate-limited address
+>>> a2 that serves as input for transaction t2:
+>>>
+>>> a2: 99.8 sats at height 800100;
+>>> Rate-limit params: h0=800000, h1=800143, a=500k, a_remaining=300k;
+>>>
+>>> Transaction t2:
+>>> Included at block height 800200
+>>> Spend: 400k + fees.
+>>> Rate-limiting params: h0=800144, h1=800287, a=500k, a_remaining=100k.
+>>>
+>>> Note how transaction t2 re-specifies the rate-limiting parameters.
+>>> Validation must ensure that the re-specified parameters are within bounds,
+>>> i.e., do not allow more spending per epoch than the rate-limiting
+>>> parameters of its input address a2. Re-specifying the rate-limiting
+>>> parameters offers the flexibility to further restrict spending, or to
+>>> disable any additional spending within the current epoch by setting
+>>> a_remaining to zero.
+>>>
+>>> Result:
+>>> Value at destination address: 400k sats;
+>>> Rate limiting params at destination address: none;
+>>> Value at change address a3: 99.4m sats;
+>>> Rate limiting params at change address a3: h0=800144, h1=800287, a=500k,
+>>> a_remaining=100k.
+>>>
+>>> As a design principle I believe it makes sense if the system is able to
+>>> verify the validity of a transaction without having to consider any
+>>> transactions that precede its inputs. As a side-note, doing away with this
+>>> design principle would however enable more sophisticated rate-limiting
+>>> (such as rate-limiting per sliding window instead of rate-limiting per
+>>> epoch having a fixed start and end block), but while at the same time
+>>> reducing the size of per rate-limiting transaction (because it would enable
+>>> specifying the rate-limiting parameters more space-efficiently). To test
+>>> the waters and to keep things relatively simple, I chose not to go into
+>>> this enhanced form of rate-limiting.
+>>>
+>>> I haven't gone into how to process a transaction having multiple
+>>> rate-limited inputs. The easiest way to handle this case is to not allow
+>>> any transaction having more than one rate-limited input. One could imagine
+>>> complex logic to handle transactions having multiple rate-limited inputs by
+>>> creating multiple rate-limited change addresses. However at first glance I
+>>> don't believe that the marginal added functionality would justify the
+>>> increased implementation complexity.
+>>>
+>>> I'd be interested in seeing you write a BIP for this.
+>>>
+>>>
+>>> Thank you, but sadly my understanding of Bitcoin is way too low to be
+>>> able to write a BIP and do the implementation. However I see tremendous
+>>> value in this functionality. Favorable feedback of the list regarding the
+>>> usefulness and the technical feasibility of rate-limiting functionality
+>>> would of course be an encouragement for me to descend further down the
+>>> rabbit hole.
+>>>
+>>> Zac
+>>>
+>>>
+>>> On Sun, Aug 1, 2021 at 10:09 AM Zac Greenwood <zachgrw@gmail.com> wrote:
+>>>
+>>>> [Resubmitting to list with minor edits. My previous submission ended up
+>>>> inside an existing thread, apologies.]
+>>>>
+>>>> Hi list,
+>>>>
+>>>> I'd like to explore whether it is feasible to implement new scripting
+>>>> capabilities in Bitcoin that enable limiting the output amount of a
+>>>> transaction based on the total value of its inputs. In other words, to
+>>>> implement the ability to limit the maximum amount that can be sent from an
+>>>> address.
+>>>>
+>>>> Two use cases come to mind:
+>>>>
+>>>> UC1: enable a user to add additional protection their funds by
+>>>> rate-limiting the amount that they are allowed to send during a certain
+>>>> period (measured in blocks). A typical use case might be a user that
+>>>> intends to hodl their bitcoin, but still wishes to occasionally send small
+>>>> amounts. Rate-limiting avoids an attacker from sweeping all the users'
+>>>> funds in a single transaction, allowing the user to become aware of the
+>>>> theft and intervene to prevent further thefts.
+>>>>
+>>>> UC2: exchanges may wish to rate-limit addresses containing large
+>>>> amounts of bitcoin, adding warm- or hot-wallet functionality to a
+>>>> cold-storage address. This would enable an exchange to drastically reduce
+>>>> the number of times a cold wallet must be accessed with private keys that
+>>>> give access to the full amount.
+>>>>
+>>>> In a typical setup, I'd envision using multisig such that the user has
+>>>> two sets of private keys to their encumbered address (with a "set" of keys
+>>>> meaning "one or more" keys). One set of private keys allows only for
+>>>> sending with rate-limiting restrictions in place, and a second set of
+>>>> private keys allowing for sending any amount without rate-limiting,
+>>>> effectively overriding such restriction.
+>>>>
+>>>> The parameters that define in what way an output is rate-limited might
+>>>> be defined as follows:
+>>>>
+>>>> Param 1: a block height "h0" indicating the first block height of an
+>>>> epoch;
+>>>> Param 2: a block height "h1" indicating the last block height of an
+>>>> epoch;
+>>>> Param 3: an amount "a" in satoshi indicating the maximum amount that is
+>>>> allowed to be sent in any epoch;
+>>>> Param 4: an amount "a_remaining" (in satoshi) indicating the maximum
+>>>> amount that is allowed to be sent within the current epoch.
+>>>>
+>>>> For example, consider an input containing 100m sats (1 BTC) which has
+>>>> been rate-limited with parameters (h0, h1, a, a_remaining) of (800000,
+>>>> 800143, 500k, 500k). These parameters define that the address is
+>>>> rate-limited to sending a maximum of 500k sats in the current epoch that
+>>>> starts at block height 800000 and ends at height 800143 (or about one day
+>>>> ignoring block time variance) and that the full amount of 500k is still
+>>>> sendable. These rate-limiting parameters ensure that it takes at minimum
+>>>> 100m / 500k = 200 transactions and 200 x 144 blocks or about 200 days to
+>>>> spend the full 100m sats. As noted earlier, in a typical setup a user
+>>>> should retain the option to transact the entire amount using a second (set
+>>>> of) private key(s).
+>>>>
+>>>> For rate-limiting to work, any change output created by a transaction
+>>>> from a rate-limited address must itself be rate-limited as well. For
+>>>> instance, expanding on the above example, assume that the user spends 200k
+>>>> sats from a rate-limited address a1 containing 100m sats:
+>>>>
+>>>> Start situation:
+>>>> At block height 800000: rate-limited address a1 is created;
+>>>> Value of a1: 100.0m sats;
+>>>> Rate limiting params of a1: h0=800000, h1=800143, a=500k,
+>>>> a_remaining=500k;
+>>>>
+>>>> Transaction t1:
+>>>> Included at block height 800100;
+>>>> Spend: 200k + fee;
+>>>> Rate limiting params: h0=800000, h1=800143, a=500k, a_remaining=300k.
+>>>>
+>>>> Result:
+>>>> Value at destination address: 200k sats;
+>>>> Rate limiting params at destination address: none;
+>>>> Value at change address a2: 99.8m sats;
+>>>> Rate limiting params at change address a2: h0=800000, h1=800143,
+>>>> a=500k, a_remaining=300k.
+>>>>
+>>>> In order to properly enforce rate limiting, the change address must be
+>>>> rate-limited such that the original rate limit of 500k sats per 144 blocks
+>>>> cannot be exceeded. In this example, the change address a2 were given the
+>>>> same rate limiting parameters as the transaction that served as its input.
+>>>> As a result, from block 800100 up until and including block 800143, a
+>>>> maximum amount of 300k sats is allowed to be spent from the change address.
+>>>>
+>>>> Example continued:
+>>>> a2: 99.8 sats at height 800100;
+>>>> Rate-limit params: h0=800000, h1=800143, a=500k, a_remaining=300k;
+>>>>
+>>>> Transaction t2:
+>>>> Included at block height 800200
+>>>> Spend: 400k + fees.
+>>>> Rate-limiting params: h0=800144, h1=800287, a=500k, a_remaining=100k.
+>>>>
+>>>> Result:
+>>>> Value at destination address: 400k sats;
+>>>> Rate limiting params at destination address: none;
+>>>> Value at change address a3: 99.4m sats;
+>>>> Rate limiting params at change address a3: h0=800144, h1=800287,
+>>>> a=500k, a_remaining=100k.
+>>>>
+>>>> Transaction t2 is allowed because it falls within the next epoch
+>>>> (running from 800144 to 800287) so a spend of 400k does not violate the
+>>>> constraint of 500k per epoch.
+>>>>
+>>>> As could be seen, the rate limiting parameters are part of the
+>>>> transaction and chosen by the user (or their wallet). This means that the
+>>>> parameters must be validated to ensure that they do not violate the
+>>>> intended constraints.
+>>>>
+>>>> For instance, this transaction should not be allowed:
+>>>> a2: 99.8 sats at height 800100;
+>>>> Rate-limit params of a2: h0=800000, h1=800143, a=500k, a_remaining=300k;
+>>>>
+>>>> Transaction t2a:
+>>>> Included at block height 800200;
+>>>> Spend: 400k + fees;
+>>>> Rate-limit params: h0=800124, h1=800267, a=500k, a_remaining=100k.
+>>>>
+>>>> This transaction t2a attempts to shift the epoch forward by 20 blocks
+>>>> such that it starts at 800124 instead of 800144. Shifting the epoch forward
+>>>> like this must not be allowed because it enables spending more that the
+>>>> rate limit allows, which is 500k in any epoch of 144 blocks. It would
+>>>> enable overspending:
+>>>>
+>>>> t1: spend 200k at 800100 (epoch 1: total: 200k);
+>>>> t2a: spend 400k at 800200 (epoch 2: total: 400k);
+>>>> t3a: spend 100k at 800201 (epoch 2: total: 500k);
+>>>> t4a: spend 500k at 800268 (epoch 2: total: 1000k, overspending for
+>>>> epoch 2).
+>>>>
+>>>> Specifying the rate-limiting parameters explicitly at every transaction
+>>>> allows the user to tighten the spending limit by setting tighter limits or
+>>>> for instance by setting a_remainder to 0 if they wish to enforce not
+>>>> spending more during an epoch. A second advantage of explicitly specifying
+>>>> the four rate-limiting parameters with each transaction is that it allows
+>>>> the system to fully validate the transaction without having to consider any
+>>>> previous transactions within an epoch.
+>>>>
+>>>> I will stop here because I would like to gauge interest in this idea
+>>>> first before continuing work on other aspects. Two main pieces of work jump
+>>>> to mind:
+>>>>
+>>>> Define all validations;
+>>>> Describe aggregate behaviour of multiple (rate-limited) inputs, proof
+>>>> that two rate-limited addresses cannot spend more than the sum of their
+>>>> individual limits.
+>>>>
+>>>> Zac
+>>>>
+>>>
+
+--0000000000008d270e05c8ca2ffb
+Content-Type: text/html; charset="UTF-8"
+Content-Transfer-Encoding: quoted-printable
+
+<div dir=3D"ltr">&gt;=C2=A0
+
+=C2=A0A maximum amount is allowed to be spent within EVERY epoch.<div><br><=
+/div><div>It sounds like you&#39;re proposing an opcode that takes in epoch=
+Start and epochEnd as parameters. I still don&#39;t understand why its=C2=
+=A0useful to specify those as absolute block heights. You mentioned=C2=A0th=
+at this enables more straightforward validation logic, but I don&#39;t see =
+how. Eg, if you have a UTXO encumbered by rateLimit(epochStart =3D 800100, =
+epochEnd =3D 800200, limit =3D 100k, remain =3D 100k), what happens if you =
+don&#39;t spend that UTXO before block 800200? Is the output no longer rate=
+ limited then? Or is the opcode calculating 800200-800100 =3D 100 and apply=
+ing a rate limit for the next epoch? If the first, then the UTXO must be sp=
+ent within one epoch to remain rate limited. If the second, then it seems n=
+early identical to simply specifying window=3D100 as a parameter instead of=
+ epochStart and epochEnd.</div><div><br></div><div>&gt; then there must be =
+only a single (rate-limited) output</div><div><br></div><div>This rule woul=
+d make transactions tricky if you&#39;re sending money into someone else&#3=
+9;s wallet that may be rate limited. If the requirement is that only you yo=
+urself can send money into a rate limited wallet, then this point is moot b=
+ut it would be ideal to not have such a requirement.</div><div><br></div><d=
+iv>This is how I&#39;d imagine creating an opcode like this:</div><div><br>=
+</div><div>rateLimit(windowSize =3D 144 blocks, limit =3D 100k sats)</div><=
+div><br></div><div>This would define that the epoch is 1 day&#39;s worth of=
+ blocks. This would evenly divide bitcoin&#39;s retarget period and so each=
+ window would start and end at those dividing lines (eg the first 144 block=
+s of the retargetting period, then the second, then the third, etc).=C2=A0<=
+/div><div><br></div><div>When this output is spent, it ensures that there&#=
+39;s a maximum of 100k sats is sent to addresses other than the originating=
+ address. It also records the amount spent in the current 144 block window =
+for that address (eg by simply recording the already-spent amount on the re=
+sulting UTXO and having an index that allows looking up UTXOs by address an=
+d adding them up). That way, when any output from that address is spent aga=
+in, if a new 144 block window has started, the limit is reset, but if its s=
+till within the same window, the already-spent amounts for UTXOs from that =
+address are added up and subtracted from the limit, and that number is the =
+remaining limit a subsequent transaction needs to adhere to.=C2=A0</div><di=
+v><br></div><div>This way, 3rd party could send transactions into an addres=
+s like this, and multiple outputs can be combined and used to spend to arbi=
+trary outputs (up to the rate limit of course).</div></div><br><div class=
+=3D"gmail_quote"><div dir=3D"ltr" class=3D"gmail_attr">On Wed, Aug 4, 2021 =
+at 3:48 AM Zac Greenwood &lt;<a href=3D"mailto:zachgrw@gmail.com" target=3D=
+"_blank">zachgrw@gmail.com</a>&gt; wrote:<br></div><blockquote class=3D"gma=
+il_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,2=
+04,204);padding-left:1ex"><div dir=3D"ltr"><div dir=3D"ltr"><div>&gt; Ah I =
+see, this is all limited to within a single epoch.</div><div><br></div><div=
+>No, that wouldn&#39;t be useful. A maximum amount is allowed to be spent w=
+ithin EVERY epoch.</div><div><br></div><div>Consider an epoch length of 100=
+ blocks with a spend limit of 200k per epoch. The following is allowed:</di=
+v><div><br></div><div>epoch1 (800101 - 800200): spend 120k in block 800140.=
+ Remaining for epoch1: 80k;</div><div>epoch1 (800101 - 800200): spend anoth=
+er 60k in block 800195. Remaining for epoch1: 20k;</div><div>epoch2 (800201=
+ - 800300): spend 160k in block 800201. Remaining for epoch2: 40k.</div><di=
+v><br></div><div>Since the limit pertains to each individual epoch, it is a=
+llowed to spend up to the full limit at the start of any new epoch. In this=
+ example, the spending was as follows:</div><div><br></div><div>800140: 120=
+k</div><div>800195: 60k</div><div>800201: 160k.</div><div><br></div><div>No=
+te that in a span of 62 blocks a total of 340k sats was spent. This may see=
+m to violate the 200k limit per 100 blocks, but this is the result of using=
+ a per-epoch limit. This allows a maximum of 400k to be spent in 2 blocks l=
+lke so: 200k in the last block of an epoch and another 200k in the first bl=
+ock of the next epoch. However this is inconsequential for the intended goa=
+l of rate-limiting which is to enable small spends over time from a large a=
+mount and to prevent theft of a large amount with a single transaction.</di=
+v><div><br></div><div>To explain the proposed design more clearly, I have r=
+enamed the params as follows:</div><div><br></div><div>epochStart: block he=
+ight of first block of the current epoch (was: h0);</div><div>epochEnd: blo=
+ck height of last block of the current epoch (was: h1);</div><div>limit: th=
+e maximum total amount allowed to be spent within the current epoch (was: a=
+);</div><div>remain: the remaining amount allowed to be spent within the cu=
+rrent epoch (was: a_remaining);</div><div><br></div><div>Also, to illustrat=
+e that the params are specific to a transaction, I will hence precede the p=
+aram with the transaction name like so:</div><div>tx8_limit, tx31c_remain, =
+tx42z_epochStart, ... etc.</div><div><br></div><div>For simplicity, only tr=
+ansactions with no more than one rate-limited input are considered, and wit=
+h no more than two outputs: one rate-limited change output, and a normal (n=
+ot rate-limited) output.<br></div><div><br></div><div>Normally, a simple tr=
+ansaction generates two outputs: one for a payment to a third party and one=
+ for the change address. Again for simplicity, we demand that a transaction=
+ which introduces rate-limiting must have only a single, rate-limited outpu=
+t. The validation rule might be: if a transaction has rate-limiting params =
+and none of its inputs are rate-limited, then there must be only a single (=
+rate-limited) output (and no second or change output).<br></div><div><br></=
+div><div><div>Consider rate limiting transactions tx1 having one or more no=
+rmal (non rate-limited) inputs:</div><div><br></div><div>tx1 gets included =
+at block height 800004;</div><div>The inputs of tx1 are not rate-limited =
+=3D&gt; tx1 must have only a single output which will become rate-limited;<=
+/div><div>params: tx1_epochStart=3D800001, tx1_epochEnd=3D800100, tx1_limit=
+=3D200k, tx1_remain=3D200k;</div><div>=3D&gt; This defines that an epoch ha=
+s 100 blocks and no more than 200k sats may be spent in any one epoch. With=
+in the current epoch, 200k sats may still be spent.</div><div><br></div><di=
+v>This transaction begins to rate-limit a set of inputs, so it has a single=
+ rate-limited output.</div></div><div>Let&#39;s explore transactions that h=
+ave the output of tx1 as their input. I will denote the output of tx1 as &q=
+uot;out1&quot;.</div><div><br></div><div>tx2a has out1 as its only input;</=
+div><div>tx2a spends 50k sats and gets included at block height 803050;</di=
+v><div>tx2a specifies the following params for its change output &quot;chg2=
+a&quot;:</div><div>chg2a_epochStart=3D803001, chg2a_epochEnd=3D803100;</div=
+><div>chg2a_limit=3D200k, chg2a_remain=3D150k.</div><div><br></div><div>To =
+enforce rate-limiting, the system must validate the params of the change ou=
+tput chg2a to ensure that overspending is not allowed.</div><div><br></div>=
+<div>The above params are allowed because:</div><div>=3D&gt; 1. the epoch d=
+oes not become smaller than 100 blocks [(chg2a_epochEnd - chg2a_epochStart)=
+ &gt;=3D (tx1_epochEnd - tx1_epochStart)]</div><div>=3D&gt; 2. tx1_limit ha=
+s not been increased (ch2a_limit &lt;=3D tx1_limit)</div><div>=3D&gt; 3. th=
+e amount spent (50k sats) does not exceed tx1_remain AND does not exceed ch=
+g2a_limit;</div><div>=3D&gt; 4. chg2a_remain&quot; is 50k sats less than ch=
+g2a_limit.</div><div><br></div><div>A transaction may also further constrai=
+n further spending like so:</div><div><br></div><div>tx2b has out1as its on=
+ly input;</div><div><div>tx2b spends 8k sats and gets included at block hei=
+ght 808105;</div><div>tx2b specifies the following params for its change ou=
+tput &quot;chg2b&quot;:</div><div>chg2b_epochStart=3D808101, chg2b_epochEnd=
+=3D808250;</div><div>chg2b_limit=3D10k, chg2b_remain=3D0.<br></div><div><br=
+></div><div>These params are allowed because:<br></div><div>=3D&gt; 1. the =
+epoch does not become smaller than100 blocks. It is fine to increase the ep=
+och to 150 blocks because it does not enable exceeding the original rate-li=
+mit;</div><div>=3D&gt; 2. the limit (chg2b_limit) has been decreased to 10k=
+ sats, further restricting the maximum amount allowed to be spent within th=
+e current and any subsequent epochs;</div><div>=3D&gt; 3. the amount spent =
+(10k sats) does not exceed tx1_remain AND does not exceed chg2b_limit;</div=
+><div>=3D&gt; 4. chg2b_remain has been set to zero, meaning that within the=
+ current epoch (block height 808101 to and including 808250), tx2b cannot b=
+e used as a spending input to any transaction.</div><div><br></div></div><d=
+iv>Starting from block height 808251, a new epoch will start and the rate-l=
+imited output of tx2b may again be used as an input for a subsequent rate-l=
+imited transaction tx3b. This transaction tx3b must again be accompanied by=
+ params that do not violate the rate-limit as defined by the params of tx2b=
+ and which are stored with output out2b. So, the epoch of tx3b must be at m=
+inimum 150 blocks, the maximum that is allowed to be spent per epoch is at =
+most 10k sats, and chg3b_remain must be decreased by at least the amount sp=
+ent by tx3b.</div><div><br></div><div>From the above, the rate-limiting mec=
+hanics should hopefully be clear and full set of validation rules could be =
+defined in a more generalized way with little additional effort.</div><div>=
+<br></div><div>Note that I conveniently avoided talking about how to repres=
+ent the parameters within transactions or outputs, simply because I current=
+ly lack enough understanding to reason about this. I am hoping that others =
+may offer help.</div><div><br></div><div>Zac</div><div><br></div></div><br>=
+<div class=3D"gmail_quote"><div dir=3D"ltr" class=3D"gmail_attr">On Tue, Au=
+g 3, 2021 at 8:12 PM Billy Tetrud &lt;<a href=3D"mailto:billy.tetrud@gmail.=
+com" target=3D"_blank">billy.tetrud@gmail.com</a>&gt; wrote:<br></div><bloc=
+kquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:=
+1px solid rgb(204,204,204);padding-left:1ex"><div dir=3D"ltr">&gt; To enabl=
+e more straightforward validation logic.<div>&gt; within the current epoch<=
+/div><div><br></div><div>Ah I see, this is all limited to within a single e=
+poch. I think that sufficiently limits the window of time in which nodes ha=
+ve to store information for rate limited outputs. However, I don&#39;t see =
+how specifying block ranges simplifies the logic - wouldn&#39;t this compli=
+cate the logic with additional user-specified constraints? It also prevents=
+ the output from being able to be rate limited over the span of multiple ep=
+ochs, which would seem to make it a lot more difficult to use for certain t=
+ypes of wallets (eg cold wallets).=C2=A0</div><div><br></div><div>I think I=
+ see the logic of your &#39;remaining&#39; parameter there. If you start wi=
+th a single rate-limited input, you can split that into many outputs, only =
+one of which have a &#39;remaining&#39; balance. The rest can simply remain=
+ unspendable for the rest of the epoch. That way these things don&#39;t nee=
+d to be tied together. However, that doesn&#39;t solve the problem of 3rd p=
+arties being able to send money into the wallet.=C2=A0</div><div><br></div>=
+<div>&gt; I don&#39;t believe that the marginal added functionality would j=
+ustify the increased implementation complexity</div><div><br></div><div>Per=
+haps, but I think there is a lot of benefit in allowing these kinds of thin=
+gs to operate as similarly as possible to normal transactions, for one beca=
+use of usability reasons. If each opcode has its own quirks that are not in=
+tuitively related to their purpose (eg if a rate-limited wallet had no way =
+to get a receiving address), it would confuse end-users (eg who wonder how =
+to get a receiving address and how they can ask people to send money into t=
+heir wallet) or require a lot of technical complexity in applications (eg t=
+o support something like cooperatively connecting with their wallet so that=
+ a transaction can be made that creates a new single-output=C2=A0for the wa=
+llet). A little complexity in this opcode can save a lot of external comple=
+xity here I think.=C2=A0</div><div><br></div><div>&gt; my understanding of =
+Bitcoin is way too low to be able to write a BIP and do the implementation<=
+/div><div><br></div><div>You might be able to find people willing to help. =
+I would be willing to help write the BIP spec. I&#39;m not the right person=
+ to help with the implementation, but perhaps you could find someone else w=
+ho is. Even if the BIP isn&#39;t adopted, it could be a starting point or i=
+nspiration for someone else to write an improved version.=C2=A0</div></div>=
+<br><div class=3D"gmail_quote"><div dir=3D"ltr" class=3D"gmail_attr">On Mon=
+, Aug 2, 2021 at 2:32 AM Zac Greenwood &lt;<a href=3D"mailto:zachgrw@gmail.=
+com" target=3D"_blank">zachgrw@gmail.com</a>&gt; wrote:<br></div><blockquot=
+e class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px s=
+olid rgb(204,204,204);padding-left:1ex"><div dir=3D"ltr">[Note: I&#39;ve mo=
+ved your reply to the newly started thread]<div><br></div><div>Hi Billy,<di=
+v><br></div><div>Thank you for your kind and encouraging feedback.</div><di=
+v><br></div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0=
+.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">I don&#39;t q=
+uite understand why you&#39;d want to define a specific span of blocks for =
+the rate limit. Why not just specify the size of the window (in blocks) to =
+rate limit within, and the limit?</blockquote><div><br></div><div>To enable=
+ more straightforward validation logic.</div><div><br></div><blockquote cla=
+ss=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid =
+rgb(204,204,204);padding-left:1ex">You mentioned change addresses, however,=
+ with the parameters you defined, there would be no way to connect together=
+ the change address with the original address, meaning they would have comp=
+letely separate rate limits, which wouldn&#39;t work since the change outpu=
+t would ignore the previous rate limit.</blockquote><div><br></div><div>The=
+ rate-limiting parameters must be re-specified for each rate-limited input.=
+ So, a transaction that has a rate-limited input is only valid if its outpu=
+t is itself rate-limited such that it does not violate the rate-limiting co=
+nstraints of its input.</div><div><br></div><div>In my thread-starter, I ga=
+ve the below example of a rate-limited address a2 that serves as input for =
+transaction t2:</div><div><br></div><div><div>a2: 99.8 sats at height=C2=A0=
+800100;</div><div>Rate-limit params: h0=3D800000, h1=3D800143, a=3D500k, a_=
+remaining=3D300k;</div><div><br></div><div>Transaction t2:</div><div>Includ=
+ed at block height 800200</div><div>Spend: 400k=C2=A0+ fees.</div><div>Rate=
+-limiting params: h0=3D800144, h1=3D800287, a=3D500k, a_remaining=3D100k.<b=
+r></div><div><br></div><div>Note how transaction t2 re-specifies the rate-l=
+imiting parameters. Validation must ensure that the re-specified parameters=
+ are within bounds, i.e., do not allow more spending per epoch than the rat=
+e-limiting parameters of its input address a2. Re-specifying the rate-limit=
+ing parameters offers the flexibility to further restrict spending, or to d=
+isable any additional spending within the current epoch by setting a_remain=
+ing to zero.</div><div><br></div><div><div>Result:</div><div>Value at desti=
+nation address: 400k sats;</div><div>Rate limiting params at destination ad=
+dress: none;</div><div>Value at change address a3: 99.4m sats;</div><div>Ra=
+te limiting params at change address a3: h0=3D800144, h1=3D800287, a=3D500k=
+, a_remaining=3D100k.</div></div></div><div><br></div><div>As a design prin=
+ciple I believe it makes sense if the system is able to verify the validity=
+ of a transaction without having to consider any transactions that precede =
+its inputs. As a side-note, doing away with this design principle would how=
+ever enable more sophisticated rate-limiting (such as rate-limiting per sli=
+ding window instead of rate-limiting per epoch having a fixed start and end=
+ block), but while at the same time reducing the size of per rate-limiting =
+transaction (because it would enable specifying the rate-limiting parameter=
+s more space-efficiently). To test the waters and to keep things relatively=
+ simple, I chose not to go into this enhanced form of rate-limiting.</div><=
+div><br></div><div>I haven&#39;t gone into how to process a transaction hav=
+ing multiple rate-limited inputs. The easiest way to handle this case is to=
+ not allow any transaction having more than one rate-limited input. One cou=
+ld imagine complex logic to handle transactions having multiple rate-limite=
+d inputs by creating multiple rate-limited change addresses. However at fir=
+st glance I don&#39;t believe that the marginal added functionality would j=
+ustify the increased implementation complexity.</div><div><br></div><blockq=
+uote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1p=
+x solid rgb(204,204,204);padding-left:1ex">=C2=A0I&#39;d be interested in s=
+eeing you write a BIP for this.</blockquote><div><br></div><div>Thank you, =
+but sadly my understanding of Bitcoin is way too low to be able to write a =
+BIP and do the implementation. However I see tremendous value in this funct=
+ionality. Favorable feedback of the list regarding the usefulness and the t=
+echnical feasibility of rate-limiting functionality would of course be an e=
+ncouragement for me to descend further down the rabbit hole.</div><div><br>=
+</div><div>Zac</div></div><div><br></div></div><br><div class=3D"gmail_quot=
+e"><div dir=3D"ltr" class=3D"gmail_attr">On Sun, Aug 1, 2021 at 10:09 AM Za=
+c Greenwood &lt;<a href=3D"mailto:zachgrw@gmail.com" target=3D"_blank">zach=
+grw@gmail.com</a>&gt; wrote:<br></div><blockquote class=3D"gmail_quote" sty=
+le=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);paddi=
+ng-left:1ex"><div dir=3D"ltr"><div>[Resubmitting to list with minor edits. =
+My previous submission ended up inside an existing thread, apologies.]</div=
+><div><br></div><div>Hi list,</div><div><br></div><div>I&#39;d like to expl=
+ore whether it is feasible to implement new scripting capabilities in Bitco=
+in that enable limiting the output amount of a transaction based on the tot=
+al value of its inputs. In other words, to implement the ability to limit t=
+he maximum amount that can be sent from an address.</div><div><br></div><di=
+v>Two use cases come to mind:</div><div><br></div><div>UC1: enable a user t=
+o add additional protection their funds by rate-limiting the amount that th=
+ey are allowed to send during a certain period (measured in blocks). A typi=
+cal use case might be a user that intends to hodl their bitcoin, but still =
+wishes to occasionally send small amounts. Rate-limiting avoids an attacker=
+ from sweeping all the users&#39; funds in a single transaction, allowing t=
+he user to become aware of the theft and intervene to prevent further theft=
+s.</div><div><br></div><div>UC2: exchanges may wish to rate-limit addresses=
+ containing large amounts of bitcoin, adding warm- or hot-wallet functional=
+ity to a cold-storage address. This would enable an exchange to drastically=
+ reduce the number of times a cold wallet must be accessed with private key=
+s that give access to the full amount.</div><div><br></div><div>In a typica=
+l setup, I&#39;d envision using multisig such that the user has two sets of=
+ private keys to their encumbered address (with a &quot;set&quot; of keys m=
+eaning &quot;one or more&quot; keys). One set of private keys allows only f=
+or sending with rate-limiting restrictions in place, and a second set of pr=
+ivate keys allowing for sending any amount without rate-limiting, effective=
+ly overriding such restriction.</div><div><br></div><div>The parameters tha=
+t define in what way an output is rate-limited might be defined as follows:=
+</div><div><br></div><div>Param 1: a block height &quot;h0&quot; indicating=
+ the first block height of an epoch;</div><div><div>Param 2: a block height=
+ &quot;h1&quot; indicating the last block height of an epoch;</div><div>Par=
+am 3: an amount &quot;a&quot; in satoshi indicating the maximum amount that=
+ is allowed to be sent in any epoch;<br></div><div>Param 4: an amount &quot=
+;a_remaining&quot; (in satoshi) indicating the maximum amount that is allow=
+ed to be sent within the current epoch.</div></div><div><br></div><div>For =
+example, consider an input containing 100m sats (1 BTC) which has been rate=
+-limited with parameters (h0, h1, a, a_remaining) of (800000, 800143, 500k,=
+ 500k). These parameters define that the address is rate-limited to sending=
+ a maximum of 500k sats in the current epoch that starts at block height 80=
+0000 and ends at height 800143 (or about one day ignoring block time varian=
+ce) and that the full amount of 500k is still sendable. These rate-limiting=
+ parameters ensure that it takes at minimum 100m / 500k =3D 200 transaction=
+s and 200 x 144 blocks or about 200 days to spend the full 100m sats. As no=
+ted earlier, in a typical setup a user should retain the option to transact=
+ the entire amount using a second (set of) private key(s).</div><div><br></=
+div><div>For rate-limiting to work, any change output created by a transact=
+ion from a rate-limited address must itself be rate-limited as well. For in=
+stance, expanding on the above example, assume that the user spends 200k sa=
+ts from a rate-limited address a1 containing 100m sats:</div><div><br></div=
+><div>Start situation:</div><div>At block height 800000: rate-limited addre=
+ss a1 is created;</div><div>Value of a1: 100.0m sats;</div><div>Rate limiti=
+ng params of a1: h0=3D800000, h1=3D800143, a=3D500k, a_remaining=3D500k;</d=
+iv><div><br></div><div>Transaction t1:</div><div>Included at block height 8=
+00100;</div><div>Spend: 200k + fee;</div><div>Rate limiting params: h0=3D80=
+0000, h1=3D800143, a=3D500k, a_remaining=3D300k.</div><div><br></div><div>R=
+esult:</div><div>Value at destination address: 200k sats;</div><div>Rate li=
+miting params at destination address: none;</div><div>Value at change addre=
+ss a2: 99.8m sats;</div><div>Rate limiting params at change address a2: h0=
+=3D800000, h1=3D800143, a=3D500k, a_remaining=3D300k.</div><div><br></div><=
+div>In order to properly enforce rate limiting, the change address must be =
+rate-limited such that the original rate limit of 500k sats per 144 blocks =
+cannot be exceeded. In this example, the change address a2 were given the s=
+ame rate limiting parameters as the transaction that served as its input. A=
+s a result, from block 800100 up until and including block 800143, a maximu=
+m amount of 300k sats is allowed to be spent from the change address.</div>=
+<div><br></div><div>Example continued:</div><div>a2: 99.8 sats at height=C2=
+=A0800100;</div><div>Rate-limit params: h0=3D800000, h1=3D800143, a=3D500k,=
+ a_remaining=3D300k;</div><div><br></div><div>Transaction t2:</div><div>Inc=
+luded at block height 800200</div><div>Spend: 400k=C2=A0+ fees.</div><div>R=
+ate-limiting params: h0=3D800144, h1=3D800287, a=3D500k, a_remaining=3D100k=
+.<br></div><div><br></div><div><div>Result:</div><div>Value at destination =
+address: 400k sats;</div><div>Rate limiting params at destination address: =
+none;</div><div>Value at change address a3: 99.4m sats;</div><div>Rate limi=
+ting params at change address a3: h0=3D800144, h1=3D800287, a=3D500k, a_rem=
+aining=3D100k.</div><div><br></div><div>Transaction t2 is allowed because i=
+t falls within the next epoch (running from 800144 to 800287) so a spend of=
+ 400k does not violate the constraint of 500k per epoch.</div><div><br></di=
+v><div>As could be seen, the rate limiting parameters are part of the trans=
+action and chosen by the user (or their wallet). This means that the parame=
+ters must be validated to ensure that they do not violate the intended cons=
+traints.</div><div><br></div><div>For instance, this transaction should not=
+ be allowed:</div><div><div>a2: 99.8 sats at height=C2=A0800100;</div><div>=
+Rate-limit params of a2: h0=3D800000, h1=3D800143, a=3D500k, a_remaining=3D=
+300k;</div><div><br></div><div>Transaction t2a:</div><div>Included at block=
+ height 800200;</div><div>Spend: 400k=C2=A0+ fees;</div><div><div>Rate-limi=
+t params: h0=3D800124, h1=3D800267, a=3D500k, a_remaining=3D100k.</div><div=
+><br></div></div><div>This transaction t2a attempts to shift the epoch forw=
+ard by 20 blocks such that it starts at 800124 instead of 800144. Shifting =
+the epoch forward like this must not be allowed because it enables spending=
+ more that the rate limit allows, which is 500k in any epoch of 144 blocks.=
+ It would enable overspending:</div></div><div><br></div><div>t1: spend 200=
+k at 800100 (epoch 1: total: 200k);</div><div>t2a: spend 400k at 800200 (ep=
+och 2: total: 400k);</div><div>t3a: spend 100k at 800201 (epoch 2: total: 5=
+00k);</div><div>t4a: spend 500k at 800268 (epoch 2: total: 1000k, overspend=
+ing for epoch 2).</div><div><br></div><div>Specifying the rate-limiting par=
+ameters explicitly at every transaction allows the user to tighten the spen=
+ding limit by setting tighter limits or for instance by setting a_remainder=
+ to 0 if they wish to enforce not spending more during an epoch. A second a=
+dvantage of explicitly specifying the four rate-limiting parameters with ea=
+ch transaction is that it allows the system to fully validate the transacti=
+on without having to consider any previous transactions within an epoch.</d=
+iv><div><br></div><div>I will stop here because I would like to gauge inter=
+est in this idea first before continuing work on other aspects. Two main pi=
+eces of work jump to mind:</div><div><br></div><div>Define all validations;=
+</div><div>Describe aggregate behaviour of multiple (rate-limited) inputs, =
+proof that two rate-limited addresses cannot spend more than the sum of the=
+ir individual limits.</div><font color=3D"#888888"><div><br></div><div>Zac<=
+/div></font></div></div>
+</blockquote></div>
+</blockquote></div>
+</blockquote></div></div>
+</blockquote></div>
+
+--0000000000008d270e05c8ca2ffb--
+