From 288e00cb32f95079de39536166ca7cbfdf558a0f Mon Sep 17 00:00:00 2001 From: Alex Forshtat Date: Wed, 1 Nov 2023 17:35:53 +0200 Subject: [PATCH 1/3] Add both unused gas penalty and a no-op transaction subtype to the Native AA EIP --- EIPS/eip-00.md | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/EIPS/eip-00.md b/EIPS/eip-00.md index ba892e3dffcd7..21a1cf44bc193 100644 --- a/EIPS/eip-00.md +++ b/EIPS/eip-00.md @@ -71,6 +71,7 @@ smart contracts. This, however, is impossible without an addition of Native Acco | MAGIC_VALUE_SENDER | 0xbf45c166 // bytes4(keccak256("validateTransaction(uint256,bytes32,bytes)")) | | MAGIC_VALUE_PAYMASTER | 0xe0e6183a // bytes4(keccak256("validatePaymasterTransaction(uint256,bytes32,bytes)")) | | MAX_CONTEXT_SIZE | 65536 | +| UNUSED_GAS_PENALTY | 10 | ### New Transaction Type @@ -96,6 +97,28 @@ If `paymasterData` is specified, its first 20 bytes contain the address of a `pa If `deployerData` is specified, its first 20 bytes contain the address of a `deployer` contract. +### No-op transaction subtype + +In some cases the block builders may want to split up an array of type `AA_TX_TYPE` transactions into individual +batches of transactions that perform validations and executions separately. + +Without a no-op transaction type this would only be possible by creating an artificial legacy type transaction. +Instead, we propose to introduce an explicit no-op transaction subtype. Their payload should be interpreted as: + +``` +0x04 || 0x01 || rlp([]) +``` + +No-op transactions have a unique hash calculated as follows: + +``` +keccak256(AA_TX_TYPE || 0x00 || rlp(blockNumber, txIndex) +``` + +The no-op transactions are only used to help execution clients determine where one set of `AA_TX_TYPE` transactions +ends and the next one starts. The block is not valid if a no-op transaction is located anywhere except between two +of `AA_TX_TYPE` transactions, they do not affect blockchain state and do not cost any gas. + ### Non-sequential nonce support Before EIP-9999, for accounts with associated code (smart contracts), the account nonce is only used and incremented @@ -203,6 +226,21 @@ to pay an extra `builderFee` as a "tip" to the block builder. This value is denominated in wei and is passed from the `sender` to the `coinbase` as part of the gas pre-charge. +### Unused gas penalty charge + +Transactions of type `AA_TX_TYPE` that reserve a lot of gas for themselves using `validationGasLimit`, +`paymasterGasLimit` and `callGasLimit` fields but do not use the reserved gas present a challenge for +block builders. This is especially demanding in case a gas used by a transaction can be significantly different +based on its position within a block, as such transactions may cause the block builder to iterate its algorithm +many times until a fully utilized block is discovered. + +A penalty of `UNUSED_GAS_PENALTY` percent of the entire unused gas limit is charged from the +transaction `sender` or `paymaster`. + +The total gas limit is calculated as `totalLimit = validationGasLimit + paymasterGasLimit + callGasLimit`.\ +The `totalGasUsed` is calculated as a sum of all gas used during the transaction.\ +The unused gas is calculated as `unusedGas = totalLimit - totalGasUsed`. + ### Multiple execution frames for a single transaction All existing transaction types only have an implicit validation phase where balance, nonce, and signature are checked, From 0d9f054cc17922959c14b5113c4b04aec0bb839a Mon Sep 17 00:00:00 2001 From: Alex Forshtat Date: Thu, 2 Nov 2023 17:48:49 +0200 Subject: [PATCH 2/3] Replace no-op transaction with an optional "header counter" transaction --- EIPS/eip-00.md | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/EIPS/eip-00.md b/EIPS/eip-00.md index 21a1cf44bc193..325be94567c12 100644 --- a/EIPS/eip-00.md +++ b/EIPS/eip-00.md @@ -97,27 +97,34 @@ If `paymasterData` is specified, its first 20 bytes contain the address of a `pa If `deployerData` is specified, its first 20 bytes contain the address of a `deployer` contract. -### No-op transaction subtype +### Optional "transaction counter header" In some cases the block builders may want to split up an array of type `AA_TX_TYPE` transactions into individual batches of transactions that perform validations and executions separately. -Without a no-op transaction type this would only be possible by creating an artificial legacy type transaction. -Instead, we propose to introduce an explicit no-op transaction subtype. Their payload should be interpreted as: +Without a header transaction type this would only be possible by creating an artificial legacy type transaction. +Instead, we propose to introduce an explicit "counter" transaction subtype. + +Their payload should be interpreted as: ``` -0x04 || 0x01 || rlp([]) +0x04 || 0x01 || rlp([chainId, transactionCount]) ``` -No-op transactions have a unique hash calculated as follows: +Header transactions have a unique hash calculated as follows: ``` -keccak256(AA_TX_TYPE || 0x00 || rlp(blockNumber, txIndex) +keccak256(AA_TX_TYPE || 0x00 || rlp(chainId, transactionCount, blockNumber, txIndex)) ``` -The no-op transactions are only used to help execution clients determine where one set of `AA_TX_TYPE` transactions -ends and the next one starts. The block is not valid if a no-op transaction is located anywhere except between two -of `AA_TX_TYPE` transactions, they do not affect blockchain state and do not cost any gas. +The `blockNumber` and `txIndex` parameters are added to the hash to achieve unique header transaction IDs. + +The header transactions are only used to help execution clients determine how many of the `AA_TX_TYPE` transactions +belong to each individual batch. +The block is not valid if a header transaction is located anywhere except before an `AA_TX_TYPE` transactions.\ +If a header transaction is included all `AA_TX_TYPE` transactions in the block must be covered by one. + +Header transactions do not affect blockchain state and do not cost any gas. ### Non-sequential nonce support From d437c71b51515ded0bb9e28f71765cf9e212a2b4 Mon Sep 17 00:00:00 2001 From: Alex Forshtat Date: Thu, 2 Nov 2023 18:14:46 +0200 Subject: [PATCH 3/3] Move the 'calldataCost' from the 'callGasLimit' to 'validationGasLimit' It is reasonable to assume the "inner" call is the first piece of data known to the transaction sender. This includes the gas limit needed for the "inner" call to happen. However, the 'calldataCost' also depends on the validation and paymaster data, creating a chicken-or-egg problem. Moving the costs of caldata to validation defers the calculation of expected calldata cost and allows solving the paradox in most cases. --- EIPS/eip-00.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/EIPS/eip-00.md b/EIPS/eip-00.md index 325be94567c12..f7a00738cfe42 100644 --- a/EIPS/eip-00.md +++ b/EIPS/eip-00.md @@ -219,9 +219,9 @@ charged for the `data` parameter. Transaction Type AA_TX_TYPE introduces the following dynamic length inputs: `callData`, `paymasterData`, `deployerData`, `signature`. Each of these parameters' gas cost is counted towards transaction data cost. -This transaction data gas cost is referred to as `calldataCost` and is subtracted from the `callGasLimit` +This transaction data gas cost is referred to as `calldataCost` and is subtracted from the `validationGasLimit` before execution of the transaction. -The transaction is considered INVALID if `callGasLimit` is smaller than `calldataCost`. +The transaction is considered INVALID if `validationGasLimit` is smaller than `calldataCost`. ### Builder Fee @@ -334,7 +334,7 @@ function validateTransaction(uint256 version, bytes32 txHash, bytes transaction) ``` -The gas limit of this frame is set to `validationGasLimit - senderCreationGasUsed`.\ +The gas limit of this frame is set to `validationGasLimit - senderCreationGasUsed - calldataCost`.\ The `transaction` parameter is interpreted as an ABI encoding of `TransactionType4`.\ The `txHash` parameter represents the hash of the AA_TX_TYPE transaction with empty signature, as defined in section [Calculation of Transaction Type AA_TX_TYPE hash](#calculation-of-transaction-type-aatxtype-hash).\ @@ -396,7 +396,7 @@ The size of the `context` byte array may not exceed `MAX_CONTEXT_SIZE` for a tra The `sender` address is invoked with `callData` input. -The gas limit of this frame is set to `callGasLimit - calldataCost`.\ +The gas limit of this frame is set to `callGasLimit`.\ Calculation of the `calldataCost` value is defined in the [Gas fees charged for transaction input](#gas-fees-charged-for-transaction-input) section.\ The amount of gas used by this frame is referred to as `gasUsedByExecution`. @@ -452,11 +452,12 @@ func validateAccountAbstractionTransaction(tx *Transaction) { if (sender.code.length == 0 && deployerData.length > 0) { assert deployerData.length > 20 deployer := deployerData[0:20] + calldataCost := calculateCalldataCost(tx) retDeployer, error := evm.Call( from: AA_SENDER_CREATOR, to: deployer, input: deployerData[20:], - gas: validationGasLimit) + gas: validationGasLimit - calldataCost) assert error == nil assert sender.code.length > 0 } @@ -644,12 +645,11 @@ for txIndex := 0; txIndex < range block.Transactions.Len(); txIndex++ { break } - calldataCost := calculateCalldataCost(tx) retCall, error := evm.Call( from: AA_ENTRY_POINT, to: sender, input: callData, - gas: callGasLimit - calldataCost) + gas: callGasLimit) txIndex := j // transaction executed - no need to revisit in the outer loop