-
Notifications
You must be signed in to change notification settings - Fork 2
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 commit for Signature Aggregation RIP-7560 transaction subtypes #2
base: master
Are you sure you want to change the base?
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,306 @@ | ||
--- | ||
eip: 0 | ||
title: Aggregation for Native Account Abstraction | ||
description: Aggregation allows Smart Contract Accounts to share a single signature data between multiple AA transactions. | ||
author: Yoav Weiss (@yoavw), Alex Forshtat (@forshtat), Dror Tirosh (@drortirosh), Shahaf Nacson (@shahafn) | ||
discussions-to: https://www.google.com/ | ||
status: Draft | ||
type: Standards Track | ||
category: Core | ||
created: 2023-09-01 | ||
requires: 7560 | ||
--- | ||
|
||
## Abstract | ||
|
||
RIP-7560 defined a native way to achieve Account Abstraction on Ethereum. However, one big limitation remains: | ||
each transaction must carry its own `signature` or other form of validation input in order to be included. | ||
|
||
We propose an extension to the RIP-7560 that introduces a validation frame that is shared by multiple transactions. | ||
|
||
This addition follows the design of [ERC-4337](./eip-4337) signature aggregation and will enable | ||
Ethereum transactions to natively support sharing validation inputs for the first time. | ||
|
||
## Motivation | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On L2s the cost of transaction is proportional to the size it requires to store on L1. |
||
|
||
Using validation schemes that allow signature aggregation enables significant optimisations and savings on | ||
gas for execution and transaction data cost. This is especially relevant in the context of rollups that publish data on | ||
the Ethereum mainnet. | ||
|
||
Another reason to support aggregation for transactions is snark aggregation. | ||
Some signature schemes, such as the ones relying on `secp256r1`, are expensive to verify. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This may no longer be a good example, with the growing adoption of RIP-7212 ( |
||
An aggregated zero-knowledge proof that the signatures of a large number of transactions were verified | ||
may be cheaper to verify on-chain than verifying each of them separately. | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Another motivation, that we may or may not want to mention here, is the ability to perform some validation on a set of transactions. For example, AtomicAggregator doesn't actually aggregate signatures (each account still validates its own) but enforces a relation between the transactions. This could be a powerful tool for intents, CoW swaps, etc. but it makes "aggregation" a bit of a misnomer - it's a hack that uses the aggregation subtype for a different use case. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is a strange beast. it seems completely unrelated to the account. you require a "protocol" (e.g in account signature) for a wallet to sign its "agreement" for the userop placement. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @yoavw , do you still thikn we should mention the AtomicAggregator here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, a strange beast and not related to signature aggregation (or account validation). The account would be validating as usual, just returning an aggregator for a different purpose. But I think it's a valid use case that could enhance intent protocols, for which there seems to be a lot of demand. An intent solver could benefit from being able to atomically bundle a set of transactions. And it doesn't require changing anything in the RIP - just renaming |
||
## Specification | ||
|
||
### Transaction version AA_TX_TYPE_AGGREGATED_SIG with aggregated signature data | ||
|
||
A new special version of RIP-7560 Transaction called `AA_TX_TYPE_AGGREGATED_SIG` is introduced to carry | ||
the aggregated signature data: | ||
|
||
``` | ||
|
||
0x04 || 0x01 || rlp([chainId, transactionCount, aggregator, aggregatedSignature, aggregatedSigValidationGasLimit, accessList]) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't remember where we landed on the discussion regarding having gas fees and a signature for this transaction type. In this form it doesn't, so it will only be created by the builder. This precludes use cases where an aggregated batch comes from a separate entity such as an intent solver that uses There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't see how AtomicAggregator can create it: this tx type is not signed by itself, and doesn't pay for itself: It is thus can only be generated by the same bundler putting in all other UserOps into this block. |
||
|
||
``` | ||
|
||
All on-chain computations that take place during the aggregated signature validation happen within the context | ||
of this transaction. | ||
|
||
### Calculation of Transaction Type AA_TX_TYPE_AGGREGATED_SIG hash | ||
|
||
``` | ||
|
||
keccak256(0x04 || 0x01 || rlp(transaction_payload) | ||
|
||
``` | ||
|
||
### Bundles of aggregated transactions | ||
|
||
As aggregated transactions share their signatures, they form a set of transactions that are only valid together and in | ||
a given order. We refer to this set of transactions as "aggregated bundle". | ||
|
||
Upon inclusion in a block, each bundle consists of the single "Aggregator validation transaction" and an arbitrary | ||
number of individual aggregated AA transactions. | ||
|
||
There may be an arbitrary number of bundles in an Ethereum block, using same or different `aggregator` addresses. | ||
|
||
### Aggregator validation transaction | ||
|
||
The aggregator validation transaction must run before any of the transactions authorized by this `aggregator`. | ||
|
||
If the execution of this transaction results in a revert the block is INVALID. | ||
|
||
We define the following Solidity method and the `aggregator` of the transaction is invoked with a corresponding data: | ||
|
||
```solidity | ||
|
||
function validateSignatures(uint256 version, bytes[] aggregatedTransactions, bytes aggregatedSignature) external view; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is a kind of method that is hard to be replaced with EOF section. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, encoding is needed. See our current discussion re SSZ. We still don't need a method for it. Just another EOF "entrypoint" which will be called with an array of SSZ-encoded transactions and the aggregated sig. |
||
|
||
``` | ||
|
||
The `aggregatedTransactions` parameter is interpreted as an array of `TransactionType4` structs. | ||
|
||
It contains an array of all transactions within a bundle that are verified by the `aggregator`. | ||
The transactions' individual `signature` parameters are replaced with the `signatureReplacement` as described below. | ||
|
||
The entire amount of gas consumed by this transaction is referred to as `gasUsedByAggregator`. | ||
|
||
### Individual transaction validity | ||
|
||
We define the following Solidity method in the `aggregator` contract defined in the transaction: | ||
|
||
```solidity | ||
|
||
function validateTransactionSignature(uint256 version, bytes transaction) external view returns (bytes signatureReplacement); | ||
|
||
``` | ||
|
||
The `transaction` parameter is interpreted as a `TransactionType4` struct. | ||
|
||
This function is only ever executed in a view mode to the `aggregator` and it reverts if the signature validation fails. | ||
The gas limit of this view-only frame can be set to the block gas limit. | ||
|
||
Individual transactions are validated for the purposes of mempool propagation and block building by running the | ||
validation steps in the following order: | ||
|
||
* `sender` deployment frame (once per account) | ||
* `sender` validation frame (required) | ||
* `paymaster` validation frame (optional) | ||
* `aggregator` individual signature validation frame (required) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the above call to validateTransactionSignature (but only if sender validation frame returns this aggregator. |
||
|
||
When block builder is running the 'aggregator individual signature validation frame', it MUST use this frame's | ||
return value as `signatureReplacement` and replace the `signature` transaction parameter with `signatureReplacement` | ||
when the transaction is being included in the block. | ||
|
||
This step allows the `aggregator` to provide any necessary context or metadata to the `sender` validation step without | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. separate "Rationale for xxx" section should be extracted form the "spec" |
||
having to provide the entire signature that has been verified by the `aggregator` already. | ||
|
||
### Generating aggregated signatures | ||
|
||
It is the block builder's job to combine an array of transaction signatures into a single aggregated signature. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this paragraph is misleading, and I'm not sure what it does here. I think we should reverse the rules: |
||
Not all signature schemes have solidity implementations for aggregation, therefore not all block producers will be able | ||
to include all kinds of aggregated transactions. | ||
|
||
The `aggregator` contract MAY include an implementation for the aggregation by accepting the following view call: | ||
|
||
```solidity | ||
|
||
function aggregateSignatures(uint256 version, bytes transactions) external returns (bytes aggregatedSignature); | ||
|
||
``` | ||
|
||
The `transactions` parameter is interpreted as an array of `TransactionType4` structs. | ||
|
||
This call returns a value used as `aggregatedSignature` elsewhere. Aggregator MUST revert this call if it is unable to | ||
calculate this value. | ||
|
||
Note that the mempool MUST only include aggregated AA transactions for `aggregators` that have an implementation | ||
of `aggregateSignatures` function. | ||
|
||
A block builder MAY calculate this value using any alternative way. | ||
If the aggregator does not implement `aggregateSignatures` function it is up to block builder to add | ||
support for this `aggregator` and its signature scheme. | ||
|
||
### Execution layer validity of a block with aggregated transactions included | ||
|
||
The `validateAccountAbstractionTransaction` function's logic is not modified compared to RIP-7560. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Except for |
||
|
||
On the execution layer, the block transactions validity conditions are extended as follows: | ||
|
||
``` | ||
|
||
if type(tx) is AccountAbstractionTransaction { | ||
if (tx.version == AA_AGGREGATED_SIG_TX_VERSION){ | ||
aggregatedTxs := collectTransactions(tx.transactionCount) | ||
aggregatedSignature := aggregateSig(aggregatedTxs) | ||
aggregatorInput := ABI.encodeWithSelector('validateSignatures()', aggregatedTxs, aggregatedSignature) | ||
gasUsedByAggregator := evm.Call( | ||
from: AA_ENTRY_POINT, | ||
to: tx.aggreagor, | ||
input: aggregatorInput, | ||
gas: config.aa_aggregated_sig_validation_gas_limit) | ||
else if (tx.version == AA_AGGREGATED_TX_VERSION){ | ||
// NOTE: we subtract the share of aggregated tx signature valdiation gas used from the validation gas limit | ||
tx.validationGasLimit = tx.validationGasLimit - (gasUsedByAggregator / tx.transactionCount) | ||
validateAccountAbstractionTransaction(tx) | ||
} | ||
} | ||
} | ||
|
||
// note: make sure all transactions are accounted for | ||
assert all_type_x_version_1_transactions_validated() | ||
|
||
// note: 'aggregated signature data' transactions do not pay their own gas | ||
// make sure no such transaction is left 'hanging' in a block without paying 'child' transactions | ||
assert all_type_x_version_1_transactions_gas_paid_for() | ||
|
||
``` | ||
|
||
### Passing cost savings to users via gas cost adjustments | ||
|
||
The RIP-7560 charges the signature validation cost as part of a transaction gas usage. | ||
It also treats transaction `signature` parameter as an arbitrary length byte arrays input. Its cost is calculated in the | ||
same way the transaction `data` cost is calculated for previous transaction types. | ||
|
||
With signature aggregation, however, the individual transactions no longer carry their own signature. They also share | ||
the cost of validating the aggregated signature. | ||
|
||
Therefore, the gas cost of the aggregated validation transaction is evenly divided by the number of transactions it | ||
validates and is added to each aggregated transaction's gas cost. | ||
Comment on lines
+196
to
+197
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This incentivizes the builder to make aggregated batches small (e.g. batches of 1 transaction). It's a zero-sum game - the more the user pays, the more the builder earns. And in the current model the user has no say in this. The alternative is that the builder (or whoever sends the AA_TX_TYPE_AGGREGATED_SIG transaction) pays for aggregation directly, and gets compensated by the user transaction, e.g. via We still need to figure out the incentives model for aggregation in a way that doesn't bring back pre-1559 inefficiencies. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we started the gas incentive for aggregation elsewhere on TG, so not starting the discussion again here. |
||
|
||
This amount of consumed gas counts towards the `validationGasLimit` of the transaction, meaning that each | ||
transaction's validation cost includes `gasUsedByAggregator / transactionCount`. | ||
This value is referred to as `aggregatedValidationGasUsed`. | ||
|
||
### Sender validation frame | ||
|
||
The `AA_TX_TYPE_AGGREGATED_SIG` type transaction includes a parameter `transactionCount`. | ||
This value indicates a number of transactions whose validation has been aggregated. | ||
|
||
For AA transactions marked as "aggregated" by the `AA_TX_TYPE_AGGREGATED_SIG` type transaction, | ||
the validation method `validateTransaction` return value is interpreted as: | ||
|
||
```solidity | ||
|
||
abi.encodePacked(aggregator, MAGIC_VALUE_SENDER, validBefore, validAfter) | ||
|
||
``` | ||
|
||
The block including this transaction is only valid if the `aggregator` address returned by the `validateTransaction` | ||
matches the `aggregator` address specified in the `AA_TX_TYPE_AGGREGATED_SIG` transaction. | ||
|
||
### RPC methods (eth namespace) | ||
|
||
#### `eth_aggregationFeeHistory` | ||
|
||
We propose the RPC method `eth_aggregationFeeHistory` to be created. | ||
This method behaves similarly to `eth_feeHistory` method used to estimate [EIP-1559](./eip-1559.md) gas fees, | ||
but instead provides history of a per-transaction validation costs, | ||
`aggregatedValidationGasUsed` and `builderFee`, for a given aggregator. | ||
The values are calculated as an average across all transactions. | ||
|
||
Value of `null` indicates there was no bundle with the given `aggregator` in the given block. | ||
|
||
Input: `aggregator address`, `block count` | ||
|
||
Returns: | ||
|
||
```json | ||
{ | ||
"oldestBlock": "100000", | ||
"newestBlock": "100003", | ||
"aggregatedValidationGasUsed": [ | ||
"450000", | ||
null, | ||
"400000", | ||
"500000" | ||
], | ||
"builderFee": [ | ||
"0x2386f26fc10000", | ||
null, | ||
"0x2386f26fc10000", | ||
"0x2386f26fc10000" | ||
] | ||
} | ||
``` | ||
|
||
#### `eth_estimateGas` | ||
|
||
In case an `aggregator` address is returned by the `validateTransaction` by the `sender`, relies on a | ||
`eth_aggregationFeeHistory` logic in order to calculate sufficient `validationGasLimit` and `builderFee` values. | ||
|
||
Returns `{validationGasLimit, callGasLimit, builderFee}` object. | ||
|
||
#### `eth_getTransactionReceipt` | ||
|
||
Accepts the Transaction Type `AA_TX_TYPE_AGGREGATED_SIG` hash. | ||
|
||
This is a special kind of transaction with `from` field set to the `coinbase` and `to` field set to `aggregator`. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. any special reason to put "from:coinbase" ? this is something that can't be simulated reliably. maybe its better to set it to ENTRYPOINT ? |
||
|
||
## Rationale | ||
|
||
### Fixed transaction order in bundle | ||
|
||
The `aggregator` contract maintains control over the number and order of transactions inside the "bundle". | ||
This means that some of the strategies block builders apply in order to extract MEV from a block become | ||
harder to do or even impossible. | ||
|
||
However, allowing the block builder to arbitrarily reorder transactions in the block, mixing aggregated and regular | ||
transactions, would make this RIP impractically complex while the MEV extraction was never an intended feature | ||
in the first place. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Block builders are free to reorder by splitting aggregated batches (even if they're for the same aggregator). They need to include multiple AA_TX_TYPE_AGGREGATED_SIG transactions for that aggregator in this case, but can control the order. Therefore the same strategies are still possible (except if something like That's another reason I think the builder should be paying for AA_TX_TYPE_AGGREGATED_SIG transactions rather than splitting their cost among the aggregated transactions. If the builder chooses to make the batches smaller to control the order, the builder should be the one paying for the additional blockspace and work it causes. |
||
|
||
## Backwards Compatibility | ||
|
||
This EIP creates a new distinct version of RIP-7560 transactions and does not break backwards-compatibility with the | ||
original specification. | ||
|
||
Same paymasters and factories contracts can be used with signature aggregation. | ||
Sender contracts need to opt in to signature aggregation explicitly by providing the `aggregator` address | ||
as a returned data from the `validateTransaction` function. | ||
|
||
## Security Considerations | ||
|
||
### Bundle size determination | ||
|
||
The proposed design leaves the freedom to determine the size of the "bundle" of aggregated AA transactions | ||
to the block builder. However, accounts retain some control over the "bundle" size as well by setting the | ||
`validationGasLimit` parameter, which may affect the minimal size of the bundle that works for this transaction. | ||
|
||
This may create opposing forces where bundlers are occasionally incentivized to split one "bundle" into two | ||
which pays more priority fee in total. This is somewhat mitigated by the `eth_estimateGas` relying on historic averages | ||
to calculate the best possible `validationGasLimit` for the transaction. | ||
|
||
### Malicious aggregators | ||
|
||
The `aggregator` contracts are among te most trusted contracts in the entire ecosystem. | ||
They can authorize transactions on behalf of accounts, and they can invalidate large numbers of transactions with | ||
a simple storage change. | ||
|
||
Both account developers and block builders should be extremely careful with the selection of `aggregotor` contracts | ||
forshtat marked this conversation as resolved.
Show resolved
Hide resolved
|
||
that they are willing to support. | ||
|
||
## Copyright | ||
|
||
Copyright and related rights waived via [CC0](../LICENSE.md). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we remove validation/execution separation from 7560 and move it to PR3 than this RIP probably also requires that.