public inbox for bitcoindev@googlegroups.com
 help / color / mirror / Atom feed
From: Zac Greenwood <zachgrw@gmail•com>
To: Billy Tetrud <billy.tetrud@gmail•com>
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
Date: Mon, 2 Aug 2021 11:32:36 +0200	[thread overview]
Message-ID: <CAJ4-pEAxqvMc89xSp9NXXNwnpJ3NhMqE6p=dRbpYCAB3Gbb14g@mail.gmail.com> (raw)
In-Reply-To: <CAJ4-pEAETy7_vOez5H32mZLg9gRpRajvoBjZyBT_v=DEqdQJvQ@mail.gmail.com>

[-- Attachment #1: Type: text/plain, Size: 10547 bytes --]

[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
>

[-- Attachment #2: Type: text/html, Size: 12590 bytes --]

  reply	other threads:[~2021-08-02  9:32 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-08-01  8:09 Zac Greenwood
2021-08-02  9:32 ` Zac Greenwood [this message]
2021-08-03 18:12   ` Billy Tetrud
2021-08-04 10:48     ` Zac Greenwood
2021-08-05  6:39       ` Billy Tetrud
2021-08-05 14:22         ` Zac Greenwood
2021-08-10  0:41           ` Billy Tetrud
  -- strict thread matches above, loose matches on Subject: below --
2021-07-21  5:56 [bitcoin-dev] Covenant opcode proposal OP_CONSTRAINDESTINATION (an alternative to OP_CTV) Billy Tetrud
2021-07-25  5:38 ` David A. Harding
2021-07-25 19:49   ` Billy Tetrud
2021-07-26 21:08     ` James MacWhyte
2021-07-27  0:41       ` Billy Tetrud
2021-07-27 11:18         ` Zac Greenwood
2021-07-27 17:21           ` Billy Tetrud
2021-07-28  4:57             ` Zac Greenwood
2021-07-28 17:57               ` Billy Tetrud
2021-07-31 20:01                 ` [bitcoin-dev] Exploring: limiting transaction output amount as a function of total input value Zac Greenwood
2021-08-02  4:40                   ` Billy Tetrud
2021-08-10  2:17                   ` ZmnSCPxj
2021-08-13 11:02                     ` Zac Greenwood
2021-08-14  1:50                       ` ZmnSCPxj
2021-08-16 11:17                         ` Zac Greenwood
2021-08-16 11:48                           ` ZmnSCPxj
2021-08-30 14:43                             ` Zac Greenwood
2021-08-31  9:00                               ` ZmnSCPxj
2021-08-31 14:09                                 ` Zac Greenwood
2021-08-31 14:22                                   ` ZmnSCPxj
2021-09-01 15:15                                     ` Zac Greenwood

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CAJ4-pEAxqvMc89xSp9NXXNwnpJ3NhMqE6p=dRbpYCAB3Gbb14g@mail.gmail.com' \
    --to=zachgrw@gmail$(echo .)com \
    --cc=billy.tetrud@gmail$(echo .)com \
    --cc=bitcoin-dev@lists$(echo .)linuxfoundation.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox