mirror of
https://github.com/status-im/EIPs.git
synced 2025-02-23 12:18:16 +00:00
I have gone through and updated all existing EIPs to match this rule, including EIP-1. In some cases, people were using markdown citations, I suspect because the long-form was a bit verbose to inline. Since the relative path is quite short, I moved these to inline but I wouldn't be opposed to putting them back to citation format if that is desired by the authors. In doing the migration/cleanup, I found some EIP references to EIPs that don't actually exist. In these cases I tried to excise the reference from the EIP as best I could. It is worth noting that the Readme actually already had this rule, it just wasn't expressed properly in EIP-1 and the "Citation Format" section of the readme I think caused people a bit of confusion (when citing externally, you should use the citation format).
133 lines
5.1 KiB
Markdown
133 lines
5.1 KiB
Markdown
---
|
|
eip: 2733
|
|
title: Transaction package
|
|
author: Matt Garnett (@lightclient)
|
|
discussions-to: https://ethereum-magicians.org/t/eip-transaction-package/4365
|
|
status: Draft
|
|
type: Standards Track
|
|
category: Core
|
|
created: 2020-06-16
|
|
requires: 2718
|
|
---
|
|
|
|
## Simple Summary
|
|
Creates a new transaction type which executes a package of one or more
|
|
transactions, while passing status information to subsequent transactions.
|
|
|
|
## Abstract
|
|
After `FORK_BLOCK`, a new [EIP-2718](./eip-2718.md)
|
|
transaction of type `N` is recognized. Transactions of type `N` will define a
|
|
list of transactions, which must be executed serially by clients. Execution
|
|
information (e.g. `success`, `gas_used`, etc.) will be propagated forward to
|
|
the next transaction.
|
|
|
|
## Motivation
|
|
Meta-transaction relay contracts have historically been designed to catch
|
|
reversions in their inner transactions by only passing a portion of the
|
|
available gas to the subcall. This has been considered bad practice for a long
|
|
time, but in the case of untrusted subcalls, like the ones relay contracts
|
|
make, it is the only available solution. Transaction packages are an
|
|
alternative that allow multiple transactions to be bundled into one package and
|
|
executed atomically, similarly to how relay contracts operate. Transactions are
|
|
able to pass their result to subsequent transactions. This allows for
|
|
conditional workflows based on the outcome of previous transactions. Although
|
|
this functionality is already possible as described above, workflows using
|
|
transaction packages are more robust, because they are protected from future
|
|
changes to the gas schedule.
|
|
|
|
## Specification
|
|
|
|
### Definitions
|
|
```
|
|
N = TBD transaction type number
|
|
INTRINSIC_COST = TBD
|
|
TOTAL_COST = INTRINSIC_COST + inner_txs.reduce(|itx, acc| acc += itx.value + tx.gas_price * itx.gas_limit)
|
|
TOTAL_GAS_LIMIT = inner_txs.reduce(|itx, acc| acc += itx.gas_limit)
|
|
TX_HASH = hash of transaction as defined below
|
|
SENDER = ecrecover(hash, v, r, s)
|
|
RESULT = result as defined below for the previous transaction, empty if its the first tx in a package
|
|
```
|
|
|
|
### Serialization
|
|
After `FORK_BLOCK`, a new [EIP-2718](./eip-2718.md)
|
|
transaction type `N` will be interpreted as follows:
|
|
|
|
`rlp([N, [v, r, s, chain_id, nonce, gas_price, [inner_tx_0, ..., inner_tx_n]])`
|
|
|
|
where `inner_tx_n` is defined as:
|
|
|
|
`[to, value, data, gas_limit]`
|
|
|
|
### Hashing
|
|
The hash of transaction type `N` is defined to be the Keccak-256 hash of the
|
|
rlp encoding of the entire transaction with `v`, `r`, and `s` values set to
|
|
zero.
|
|
|
|
### Results
|
|
Subsequent transactions will be able to receive the result of the previous
|
|
transaction via `RETURNDATACOPY (0x3E)` in first frame of exeuction, before
|
|
making any subcalls. Each element, except the last, will be `0`-padded left to
|
|
32 bytes.
|
|
|
|
| Name | Type | Description |
|
|
|---|---|---|
|
|
| `success` | bool | Status of the previous transaction |
|
|
| `gas_used` | uint256 | Total gas used by the previous transaction |
|
|
| `cum_gas_used` | uint256 | Cumulative gas used by previous transactions |
|
|
| `return_size` | uint256 | The size of the return value |
|
|
| `return_value` | bytes | The return value of the previous transaction
|
|
|
|
### Validation
|
|
* (v, r, s) are a valid signature of the hash of the transaction
|
|
* The nonce is one greater than recovered address' current nonce
|
|
* The recovered address has a balance of at least `TOTAL_COST`
|
|
* The `TOTAL_GAS_LIMIT` is less than the current block's `gas_limit`
|
|
|
|
### Execution
|
|
Transaction packages should be executed as follows:
|
|
|
|
1. Deduct `TOTAL_COST` from `SENDER`'s balance
|
|
2. Execute the first inner transaction in the list
|
|
3. Refund any unused `gas`
|
|
4. Record all state changes, logs, and the receipt
|
|
5. If there are no more transaction, stop
|
|
6. Compute `RESULT` for the previously executed transaction
|
|
7. Prepare `RESULT` to be available via return opcodes in the next
|
|
transaction's first frame
|
|
8. Execute the next transaction
|
|
9. Goto `3`
|
|
|
|
## Rationale
|
|
|
|
#### Non-recursive inner transactions
|
|
For simplicity, inner transactions are fully defined within this EIP. However,
|
|
there is value in supporting recursive transaction definitions. For example,
|
|
suppose there is a transaction type which can become invalid after a certain
|
|
block number. It would be beneficial to support those types of transactions
|
|
within a package, but the complexity of this EIP would dramatically increase.
|
|
|
|
#### Appending result data to transaction input data
|
|
An alternative to using return opcodes to propagate `RESULT` would be to append
|
|
the `RESULT` to the subsequent transaction's `data` field. Unfortunately, in
|
|
many cases contracts generated using Solidity [will
|
|
fail](https://solidity.readthedocs.io/en/v0.6.0/contracts.html#overload-resolution-and-argument-matching)
|
|
to resolve the intended function if additional data is present.
|
|
|
|
## Backwards Compatibility
|
|
Contracts which rely on `ORIGIN (0x32) == CALLER (0x33) && RETURNDATASIZE
|
|
(0x3D) == 0x00` will now always fail in transaction packages, unless they are
|
|
the first executed transaction. It's unknown if any contracts conduct this
|
|
check.
|
|
|
|
## Test Cases
|
|
TBD
|
|
|
|
## Implementation
|
|
TBD
|
|
|
|
## Security Considerations
|
|
TBD
|
|
|
|
## Copyright
|
|
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).
|