Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial draft of transaction package EIP #2733

Merged
merged 5 commits into from
Jun 22, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 132 additions & 0 deletions EIPS/eip-2733.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
---
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.

## Abstract
After `FORK_BLOCK`, a new [EIP-2718](https://eips.ethereum.org/EIPS/eip-2718)
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 untrust subcalls -- it is the only available solution.
Transaction packages are an alternative solution which allow multiple
transactions to be bundled into one package and executed atomically.

## Specification

### Definitions

```
N = TBD transaction type number
INTRINSIC_COST = TBD
TOTAL_COST = INTRINSIC_COST + inner_txs.reduce(|itx, acc| acc += itx.value + itx.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](https://eips.ethereum.org/EIPS/eip-2718)
transaction type `N` will be interpreted as follows:

`rlp([N, rlp([nonce, v, r, s, [inner_tx_0, ..., inner_tx_n]])`

where `inner_tx_n` is defined as:

`[chain_id, to, value, data, gas_limit, gas_price]`

### 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 omitted.

### 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. If there are no more transaction, stop
5. Compute `RESULT` for the previously executed transaction
6. Prepare `RESULT` to be available via return opcodes in the next
transaction's first frame
7. Execute the 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. Another
alternative is introducing new opcodes to expose the result data were not
proposed.


## 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/).