Transaction Aggregates
login

Transaction Aggregates

A transaction aggregate is a group of transactions that are guaranteed to all be validated and committed to the blockchain within the same block. A transaction is an atomic set of inputs and outputs, a transaction aggregate is an atomic set of transactions.

Transactions within an aggregate are bound together by aggregate signatures or script hashes. Aggregate signatures can be either a single pubkey, or muSig Schnorr signatures. Aggregate script hashes constrain spending to the execution of a script (similar to P2SH), but these scripts can introspect all transactions within the aggregation.

It is possible to have an “aggregate” of 1 transaction to take advantage of these features within a single transaction.

Purpose

Atomic (revokeable) multi-step operations

Constructing a series of transactions that are atomically committed to the blockchain is an essential feature to enable interesting “smart contract” functionality.

For those who are familiar with Ethereum smart contracting, aggregate transactions with pay-to-aggregate-script-hash can accomplish the same functionality as Solidity’s inter-contract function calls, including revertability.

In particular this is needed to implement flash loans[add ref].

However, constraining the aggregate to a signature is an interesting twist. This requires that the aggregate (or the relevant portions of it) be submitted to the entity who is capable of signing. This entity can then run off-chain analysis of the aggregate before signing.

This technique could be used as the final deployment to carefully control involvement, or it could be used during beta to add an extra off-chain validation to a system that is intended to eventually transition to a permissionless pay-to-aggregate-script-hash model.

Signature efficiency

  1. More efficiently spending many UTXOs referencing the same output constraint.
  2. Combining all input signature operations in a transaction (or N transactions) into a single multi-signature. (Note that doing so may reduce privacy, unless protocols are put into place to allow anonymous entities to do the same)

Segregated Witness

Segregated Witness AKA “SegWit” is perhaps anathema within the Bitcoin Cash community due to the attempt by Bitcoin developers to pass it off as a scaling solution, despite achieving approximately a 1.3MB block size with 50% segwit transactions as shown on fork.lol at the time of this writing, and requiring on average more bytes per transaction, resulting in only an average of 2.5k tx/block).

However, there is value in segregated witness – as a concept, rather than the specific technology deployed in Bitcoin. This value is a fundamental new piece of functionality that segregated witness enables. This functionality is the ability to construct and sign a child transaction before the parent transaction is signed. Currently, this is not possible because the child transaction’s inputs must refer to the parent by hash, and an unsigned transaction’s hash is different than a signed transaction’s hash.

This functionality is needed to enable 2 important features.

First, it is needed for any provisional or speculative transaction chain construction between contracts or entities without trust, which is a major requirement for decentralized finance applications.

Second, it is needed for most if not all of the Bitcoin “L2” technologies. Again, L2 in the form of “the Lightning network” has a bad reputation in the Bitcoin Cash community due to its failed application towards scalability. But we must recognize that a very valuable tool can be worse than no tool at all if applied to the wrong problem (for example, digging a hole with a micro-pipette).

These concepts are illustrated with an example in the “Applications: Decentralized Finance Services” section of this document.

Applications

Flash Loans

“Flash” loans are loans that are atomically offered and repaid. Transaction aggregates can be used to allow the recipient to “do something” with the loan (consisting of other transactions), yet atomically pay the loan back.

Decentralized Finance Services

Let’s say entity A wants to buy some widgets from C but C only accepts a stable coin in their local fiat currency. Entity A can tell some other financial service entity B “here is some BCH for you to do anything with, so long as there exists an output whose data field is a signed sales order by C for X widgets” (tx 1). This is done either by segregating the signature (and not actually signing), or signing with a smart contract that needs to “see” the entire transaction aggregation to enforce the described output constraint. B then creates a transaction that converts the BCH into a stable coin accepted by C via any one of many possible decentralized exchanges (tx 2, signed by B and C), and uses that stable coin as an input to purchase the product from C (tx 3).

In standard “SegWit”, entity A now signs the first transaction. However, with this formulation transaction 1, 2, and 3 are not atomic. It is possible for 1 to be issued but there be a race condition between 2 and a hidden 2’ that B created. To solve this problem, Lightning (which is accomplishing something different so this analogy can only go so far) uses some complex tricks that use transactions’ “lock time” feature to force any 2’ to be delayed, giving time for A to issue 2 and 3 to the blockchain. This technique has many problems (such as A needing to be on-line and retain state) but is certainly possible using transaction aggregation.

However, in this formulation a simpler solution exists. A signs the aggregate of all 3 transactions, rather than just transaction 1. Or, in the smart contract formulation, the smart contract must execute in the context of the aggregate (so it can see the final sales order output), and accepts the aggregate as a whole, and only as a whole, since the sales order constraint is met in transaction 3, but 3’s inputs depend on outputs of 2 which depends on 1.

The ability to engage in a speculative chain of operations where an early participant verifies some later state is a fundamental part of “DeFi” as implemented in Ethereum by allowing contracts to call other contracts wrapped in “require” and “assert” primitives. Note however, that this transaction aggregation as a technology does not replicate Ethereum DeFi – instead it would produce a different, likely more efficient, flavor of DeFi where only the “require” statements are encoded within bitcoin script. The actual “execution” (state transformations and decisions) contained within an Ethereum program occurs off-chain, and can only use state imported via UTXO, while the on-chain script only checks the validity of those state transformations. It may turn out that validating state transformations is sometimes just as expensive as calculating them. However it cannot be more expensive (or the script can simply validate the transformation by calculating it).

Construction

Transaction aggregates contain a set of transactions and an aggregate signature section that contains a vector of:

  1. an arbitrarily chosen 32 bit number called an aggregate signature identifier (ASI).
  2. signature bytes.

Satisfier scripts within transactions in an aggregate may provide an ASI rather than a signature as a parameter to CHECKSIGVERIFY or CHECKDATASIGVERIFY. A transaction that is not part of an aggregate that provides an ASI fails validation. A transaction that uses an ASI number that is not in the aggregate fails validation.

Transaction Validation

For memory-efficient operation, aggregate validation begins by initializing some memory for every ASI:

  • A SHA-256 hash state machine is initialized,
  • Space is allocated for an aggregate pubkey.

The execution model proceeds as if transactions are evaluated sequentially in an aggregate and scripts are executed sequentially within a transaction. In practice parallel script evaluation may occur, but this sequential order defines the concatenation order of the signature data when hashed (does there exist an efficient cryptographically strong commutative hash function here to remove all sequential requirements?).

During script execution, aggregate signature operations are assumed to succeed (which is why non-verify variants cannot be supported). Note that this assumption does not reduce functionality – non-verify variants are easily replaced with a verify contained within an if block as described in[3].

Whenever an aggregate signature operation is encountered, the corresponding ASI record is looked up and the pubkey is added to the aggregate pubkey (if signature aggregation is happening) and data to be signed is first prepared as per its non-aggregate algorithm (that is, some algorithm is applied that comprises 1 or more cryptographic hashes, and cached). This helps parallelization by allowing the larger raw data to be hashed in parallel. The resulting hash is then provided to the corresponding SHA-256 hash state machine. This has the effect of incrementally creating the SHA-256 hash of the data the aggregate signature will cover. This is equivalent to storing all hashes in a buffer and executing SHA-256 at the end. However, in this case it would be possible for malicious aggregate transaction to attempt to exhaust available memory by requesting aggregate signatures over a lot of data.

Once all scripts are executed, all aggregate signatures are checked against the aggregate pubkey and aggregate hash. Any failure means that the entire aggregate fails validation.

From this construction, it should be clear that it may be possible to split aggregates into disjoint smaller aggregates. Transactions in aggregates are only truly atomic if transaction dependencies and aggregate signatures bind them.

Two types of aggregate signature are supported: a single pubkey and muSig Schnorr multi-signatures[1][2].

Block format

Transaction aggregates are placed in the block as a unit in place of a single transaction, with the nVersion field equal to 2.

Discussion

Why not make a single transaction?

One could imagine taking all the inputs and outputs of a transaction aggregation and creating a single transaction containing those inputs and outputs. This construction renders the concept of a transaction aggregation unnecessary. This is true in theory, but there are two practical problems. 1. each transaction has a potentially different nLockTime, and 2. current sighash specifications do not allow signatures to specify an arbitrary set of transaction inputs and outputs to sign.

Additionally, to enable full “defi” functionality, such a single transaction would need to be able to spend its own outputs. The purpose of this is to allow a 3rd party to independently construct the final transaction, which may be comprised of a dependent sequence of transactions. Involving the original party in the “transitive simplification” (eliminating outputs that are spent as inputs, and input and outputs that equal each other) of the transaction would leak information that would allow the original party to either prevent, suppliant, or front-run the 3rd party’s effort. For example, “flash loan” uses and other atomic arbitrage opportunities could be hijacked by the liquidity provider.

As an aside, It is very possible that a cryptocurrency would see this as a feature. It may seek to eliminate these as a class of operations – its unclear where the balance of subjectively “good” (accomplishing economic activity) verses “bad” (manipulating smart contracts in ways their authors did not intend to extract value) applications lie. I do not think we understand enough about this technology to make such a determination. But what is interesting to consider is how disallowing transactions that spend their own outputs would therefore require first party involvement in the required transitive simplification to combine transactions. So this technique can be used to force disclosure of “bad” (and “good”) contracts before they can be executed. And another possibility is eliminating the pay-to-aggregate-script concept, so any “aggregate” constraints must be evaluated “off-chain” by being “packed” into an aggregate signature. For more background information about these issues in Ethereum see these references[4][5].

However, if these issues were solved then aggregating inputs and outputs into a single transaction is indeed equivalent to this proposal, might be considered the cleaner implementation.

State Constraints

Unlike other decentralized finance (smart contract capable) blockchains, this system retains the efficiency properties offered by the UTXO model – in particular, transaction aggregate scripts and signatures can be validated once, out-of-band. Once validated, inclusion in a block candidate (as a miner) or validation of an entire block can occur simply by ensuring that input UTXOs are not spent.

References

[1]: Multi-Signatures in the Plain Public-Key Model and a General Forking Lemma. Bellare and Neven. https://cseweb.ucsd.edu/~mihir/papers/multisignatures-ccs.pdf

[2]: Simple Schnorr Multi-Signatures
with Applications to Bitcoin. Maxwell, Poelstra, Seurin, and Wuille. https://eprint.iacr.org/2018/068

[3]: DATASIGVERIFY. Stone.

[4]: Ethereum is a Dark Forest. A horror story. Robinson.

[5]: Ethology: A Safari Tour in Ethereum’s Dark Forest. Manuskin.