-
Notifications
You must be signed in to change notification settings - Fork 710
Support various eth_call invocations post 1559 #3317
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
Changes from 21 commits
f5bed91
4dcc4f4
9065595
5574d5a
ab32915
8883dd4
6fff2c1
7611928
0a412ff
78a20f7
03e0b0e
d2fc7ba
0385a18
a4829c2
9d8ac63
c7e8bb2
646834d
394c190
7f46a98
78c8f41
8652d2c
4c62c77
c91715e
7fff105
ac8f321
800b083
9c19612
e1993b2
11f7cf4
b3b8739
1e323ed
cd29e01
f831fe1
b257240
0eac807
77bdd4d
5175f3c
367ab1b
5126e27
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 |
|---|---|---|
|
|
@@ -60,7 +60,17 @@ private enum ExecutionOptions | |
| /// <summary> | ||
| /// Commit and later restore state, use for CallAndRestore | ||
| /// </summary> | ||
| CommitAndRestore = Commit | Restore | ||
| CommitAndRestore = Commit | Restore, | ||
|
|
||
| /// <summary> | ||
| /// Zero Gas price | ||
| /// </summary> | ||
| SkipGasPricingValidation = 4, | ||
|
|
||
| /// <summary> | ||
| /// Commit and restore with zero gas price | ||
| /// </summary> | ||
| CommitAndRestoreWithSkippingGasPricingValidation = CommitAndRestore | SkipGasPricingValidation | ||
| } | ||
|
|
||
| public TransactionProcessor( | ||
|
|
@@ -80,7 +90,17 @@ public TransactionProcessor( | |
|
|
||
| public void CallAndRestore(Transaction transaction, BlockHeader block, ITxTracer txTracer) | ||
| { | ||
| Execute(transaction, block, txTracer, ExecutionOptions.CommitAndRestore); | ||
| IReleaseSpec spec = _specProvider.GetSpec(block.Number); | ||
| spec = new SystemTransactionReleaseSpec(spec); | ||
|
|
||
| bool skipGasPricing = spec.IsEip1559Enabled | ||
| ? (transaction.IsEip1559 | ||
| ? (transaction.MaxFeePerGas.IsZero && transaction.MaxPriorityFeePerGas.IsZero) | ||
| : transaction.GasPrice.IsZero) | ||
| : transaction.GasPrice.IsZero; | ||
|
|
||
| Execute(transaction, block, txTracer, | ||
| skipGasPricing ? ExecutionOptions.CommitAndRestoreWithSkippingGasPricingValidation : ExecutionOptions.CommitAndRestore); | ||
| } | ||
|
|
||
| public void BuildUp(Transaction transaction, BlockHeader block, ITxTracer txTracer) | ||
|
|
@@ -96,7 +116,7 @@ public void Execute(Transaction transaction, BlockHeader block, ITxTracer txTrac | |
| Execute(transaction, block, txTracer, ExecutionOptions.Commit); | ||
| } | ||
|
|
||
| private void QuickFail(Transaction tx, BlockHeader block, ITxTracer txTracer, bool eip658NotEnabled, string? reason) | ||
| private void QuickFail(Transaction tx, BlockHeader block, ITxTracer txTracer, bool eip658NotEnabled, string? reason, bool deleteCallerAccount = false) | ||
| { | ||
| block.GasUsed += tx.GasLimit; | ||
|
|
||
|
|
@@ -115,6 +135,11 @@ private void QuickFail(Transaction tx, BlockHeader block, ITxTracer txTracer, bo | |
|
|
||
| txTracer.MarkAsFailed(recipient, tx.GasLimit, Array.Empty<byte>(), reason ?? "invalid", stateRoot); | ||
| } | ||
|
|
||
| if (deleteCallerAccount) | ||
| { | ||
| _stateProvider.DeleteAccount(tx.SenderAddress ?? throw new InvalidOperationException()); | ||
| } | ||
|
Member
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. Maybe this should be put in a finally clause?
Author
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. Do something like this?
Member
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
Author
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. ok |
||
| } | ||
|
|
||
| private void Execute(Transaction transaction, BlockHeader block, ITxTracer txTracer, ExecutionOptions executionOptions) | ||
|
|
@@ -123,10 +148,14 @@ private void Execute(Transaction transaction, BlockHeader block, ITxTracer txTra | |
|
|
||
| // restore is CallAndRestore - previous call, we will restore state after the execution | ||
| bool restore = (executionOptions & ExecutionOptions.Restore) != ExecutionOptions.None; | ||
|
|
||
| // commit - is for standard execute, we will commit thee state after execution | ||
| bool commit = (executionOptions & ExecutionOptions.Commit) != ExecutionOptions.None || eip658NotEnabled; | ||
| //!commit - is for build up during block production, we won't commit state after each transaction to support rollbacks | ||
| //we commit only after all block is constructed | ||
| //we commit only after all block is constructed | ||
|
|
||
| bool skipGasPricing = (executionOptions & ExecutionOptions.SkipGasPricingValidation) != ExecutionOptions.None; | ||
|
|
||
| bool notSystemTransaction = !transaction.IsSystem(); | ||
| bool deleteCallerAccount = false; | ||
|
|
||
|
|
@@ -137,9 +166,17 @@ private void Execute(Transaction transaction, BlockHeader block, ITxTracer txTra | |
| } | ||
|
|
||
| UInt256 value = transaction.Value; | ||
|
|
||
| if (!skipGasPricing && restore && transaction.MaxPriorityFeePerGas > transaction.MaxFeePerGas) | ||
| { | ||
| TraceLogInvalidTx(transaction, "MAX PRIORITY FEE PER GAS HIGHER THAN MAX FEE PER GAS"); | ||
| QuickFail(transaction, block, txTracer, eip658NotEnabled, "max priority fee per gas higher than max fee per gas"); | ||
| return; | ||
| } | ||
|
|
||
| if (!transaction.TryCalculatePremiumPerGas(block.BaseFeePerGas, out UInt256 premiumPerGas) && !restore) | ||
| if (!transaction.TryCalculatePremiumPerGas(block.BaseFeePerGas, out UInt256 premiumPerGas) && !skipGasPricing) | ||
| { | ||
| // max fee per gas (feeCap) less than block base fee | ||
| TraceLogInvalidTx(transaction, "MINER_PREMIUM_IS_NEGATIVE"); | ||
| QuickFail(transaction, block, txTracer, eip658NotEnabled, "miner premium is negative"); | ||
| return; | ||
|
|
@@ -212,29 +249,29 @@ private void Execute(Transaction transaction, BlockHeader block, ITxTracer txTra | |
| } | ||
| } | ||
|
|
||
| UInt256 senderReservedGasPayment = restore ? UInt256.Zero : (ulong) gasLimit * effectiveGasPrice; | ||
| UInt256 senderReservedGasPayment = skipGasPricing ? UInt256.Zero : (ulong) gasLimit * effectiveGasPrice; | ||
|
|
||
| if (notSystemTransaction) | ||
| { | ||
| UInt256 senderBalance = _stateProvider.GetBalance(caller); | ||
| if (!restore && ((ulong) intrinsicGas * effectiveGasPrice + value > senderBalance || senderReservedGasPayment + value > senderBalance)) | ||
| if (!skipGasPricing && ((ulong) intrinsicGas * effectiveGasPrice + value > senderBalance || senderReservedGasPayment + value > senderBalance)) | ||
| { | ||
| TraceLogInvalidTx(transaction, $"INSUFFICIENT_SENDER_BALANCE: ({caller})_BALANCE = {senderBalance}"); | ||
| QuickFail(transaction, block, txTracer, eip658NotEnabled, "insufficient sender balance"); | ||
| QuickFail(transaction, block, txTracer, eip658NotEnabled, "insufficient sender balance", deleteCallerAccount && restore); | ||
| return; | ||
| } | ||
|
|
||
| if (!restore && spec.IsEip1559Enabled && !transaction.IsServiceTransaction && senderBalance < (UInt256)transaction.GasLimit * transaction.MaxFeePerGas + value) | ||
| if (!skipGasPricing && spec.IsEip1559Enabled && !transaction.IsServiceTransaction && senderBalance < (UInt256)transaction.GasLimit * transaction.MaxFeePerGas + value) | ||
| { | ||
| TraceLogInvalidTx(transaction, $"INSUFFICIENT_MAX_FEE_PER_GAS_FOR_SENDER_BALANCE: ({caller})_BALANCE = {senderBalance}, MAX_FEE_PER_GAS: {transaction.MaxFeePerGas}"); | ||
| QuickFail(transaction, block, txTracer, eip658NotEnabled, "insufficient MaxFeePerGas for sender balance"); | ||
| QuickFail(transaction, block, txTracer, eip658NotEnabled, "insufficient MaxFeePerGas for sender balance", deleteCallerAccount && restore); | ||
| return; | ||
| } | ||
|
|
||
| if (transaction.Nonce != _stateProvider.GetNonce(caller)) | ||
| { | ||
| TraceLogInvalidTx(transaction, $"WRONG_TRANSACTION_NONCE: {transaction.Nonce} (expected {_stateProvider.GetNonce(caller)})"); | ||
| QuickFail(transaction, block, txTracer, eip658NotEnabled, "wrong transaction nonce"); | ||
| QuickFail(transaction, block, txTracer, eip658NotEnabled, "wrong transaction nonce", deleteCallerAccount && restore); | ||
| return; | ||
| } | ||
|
|
||
|
|
@@ -327,7 +364,7 @@ private void Execute(Transaction transaction, BlockHeader block, ITxTracer txTra | |
| } | ||
| else | ||
| { | ||
| // tks: there is similar code fo contract creation from init and from CREATE | ||
| // tks: there is similar code for contract creation from init and from CREATE | ||
| // this may lead to inconsistencies (however it is tested extensively in blockchain tests) | ||
| if (transaction.IsContractCreation) | ||
| { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -43,7 +43,7 @@ public async Task Eth_estimateGas_web3_should_return_insufficient_balance_error( | |
| string serialized = | ||
| ctx._test.TestEthRpc("eth_estimateGas", ctx._test.JsonSerializer.Serialize(transaction)); | ||
| Assert.AreEqual( | ||
| "{\"jsonrpc\":\"2.0\",\"error\":{\"code\":-32000,\"message\":\"insufficient funds for transfer: address 0x0001020304050607080910111213141516171819\"},\"id\":67}", | ||
| "{\"jsonrpc\":\"2.0\",\"error\":{\"code\":-32603,\"message\":\"insufficient sender balance\"},\"id\":67}", | ||
|
Contributor
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. Could you explain why we need to change this error message? |
||
| serialized); | ||
| ctx._test.ReadOnlyState.AccountExists(someAccount).Should().BeFalse(); | ||
| } | ||
|
|
@@ -58,7 +58,7 @@ public async Task Eth_estimateGas_web3_sample_not_enough_gas_system_account() | |
| "{\"gasPrice\":\"0x100000\", \"data\": \"0x70a082310000000000000000000000006c1f09f6271fbe133db38db9c9280307f5d22160\", \"to\": \"0x0d8775f648430679a709e98d2b0cb6250d2887ef\"}"); | ||
|
Contributor
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. It will be nice to add the same tests like it was before but with skipped gas pricing. One more question: did geth change behavior only for blocks after 1559 or for all blocks? |
||
| string serialized = | ||
| ctx._test.TestEthRpc("eth_estimateGas", ctx._test.JsonSerializer.Serialize(transaction)); | ||
| Assert.AreEqual("{\"jsonrpc\":\"2.0\",\"result\":\"0x53b8\",\"id\":67}", serialized); | ||
| Assert.AreEqual("{\"jsonrpc\":\"2.0\",\"error\":{\"code\":-32000,\"message\":\"insufficient funds for transfer: address 0xfffffffffffffffffffffffffffffffffffffffe\"},\"id\":67}", serialized); | ||
| ctx._test.ReadOnlyState.AccountExists(Address.SystemUser).Should().BeFalse(); | ||
| } | ||
|
|
||
|
|
@@ -72,7 +72,7 @@ public async Task Eth_estimateGas_web3_sample_not_enough_gas_other_account() | |
| "{\"from\":\"0x0001020304050607080910111213141516171819\",\"gasPrice\":\"0x100000\", \"data\": \"0x70a082310000000000000000000000006c1f09f6271fbe133db38db9c9280307f5d22160\", \"to\": \"0x0d8775f648430679a709e98d2b0cb6250d2887ef\"}"); | ||
| string serialized = | ||
| ctx._test.TestEthRpc("eth_estimateGas", ctx._test.JsonSerializer.Serialize(transaction)); | ||
| Assert.AreEqual("{\"jsonrpc\":\"2.0\",\"result\":\"0x53b8\",\"id\":67}", serialized); | ||
| Assert.AreEqual("{\"jsonrpc\":\"2.0\",\"error\":{\"code\":-32603,\"message\":\"insufficient sender balance\"},\"id\":67}", serialized); | ||
| ctx._test.ReadOnlyState.AccountExists(someAccount).Should().BeFalse(); | ||
| } | ||
|
|
||
|
|
@@ -86,7 +86,7 @@ public async Task Eth_estimateGas_web3_above_block_gas_limit() | |
| "{\"from\":\"0x0001020304050607080910111213141516171819\",\"gas\":\"0x100000000\",\"gasPrice\":\"0x100000\", \"data\": \"0x70a082310000000000000000000000006c1f09f6271fbe133db38db9c9280307f5d22160\", \"to\": \"0x0d8775f648430679a709e98d2b0cb6250d2887ef\"}"); | ||
| string serialized = | ||
| ctx._test.TestEthRpc("eth_estimateGas", ctx._test.JsonSerializer.Serialize(transaction)); | ||
| Assert.AreEqual("{\"jsonrpc\":\"2.0\",\"result\":\"0x53b8\",\"id\":67}", serialized); | ||
| Assert.AreEqual("{\"jsonrpc\":\"2.0\",\"error\":{\"code\":-32603,\"message\":\"insufficient sender balance\"},\"id\":67}", serialized); | ||
| ctx._test.ReadOnlyState.AccountExists(someAccount).Should().BeFalse(); | ||
| } | ||
|
|
||
|
|
@@ -186,15 +186,15 @@ public async Task Estimate_gas_with_gas_pricing() | |
| TransactionForRpc transaction = ctx._test.JsonSerializer.Deserialize<TransactionForRpc>( | ||
| "{\"from\": \"0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24\", \"to\": \"0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24\", \"gasPrice\": \"0x10\"}"); | ||
| string serialized = ctx._test.TestEthRpc("eth_estimateGas", ctx._test.JsonSerializer.Serialize(transaction)); | ||
| Assert.AreEqual("{\"jsonrpc\":\"2.0\",\"result\":\"0x5208\",\"id\":67}", serialized); | ||
| Assert.AreEqual("{\"jsonrpc\":\"2.0\",\"error\":{\"code\":-32603,\"message\":\"insufficient sender balance\"},\"id\":67}", serialized); | ||
| } | ||
|
|
||
| [Test] | ||
| public async Task Estimate_gas_without_gas_pricing_after_1559_legacy() | ||
| { | ||
| using Context ctx = await Context.CreateWithLondonEnabled(); | ||
| TransactionForRpc transaction = ctx._test.JsonSerializer.Deserialize<TransactionForRpc>( | ||
| "{\"from\": \"0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24\", \"to\": \"0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24\", \"gasPrice\": \"0x10\"}"); | ||
| "{\"from\": \"0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24\", \"to\": \"0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24\"}"); | ||
| string serialized = ctx._test.TestEthRpc("eth_estimateGas", ctx._test.JsonSerializer.Serialize(transaction)); | ||
| Assert.AreEqual("{\"jsonrpc\":\"2.0\",\"result\":\"0x5208\",\"id\":67}", serialized); | ||
| } | ||
|
|
||
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.
Take into account that you will change the behavior of three RPC calls here (eth_call, eth_estimateGas, and eth_createAccessList). Did you verify this behavior with other clients for each of the methods?