From d2888cd10808be536c344ba9956c5d5bf52aa790 Mon Sep 17 00:00:00 2001 From: chengzhinei Date: Tue, 30 Apr 2024 15:41:48 +0800 Subject: [PATCH 01/18] init optimisticGasLimit --- state/transaction.go | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/state/transaction.go b/state/transaction.go index a54d7c0f89..cc496bc538 100644 --- a/state/transaction.go +++ b/state/transaction.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "github.com/ethereum/go-ethereum/params" "math/big" "time" @@ -851,6 +852,26 @@ func (s *State) EstimateGas(transaction *types.Transaction, senderAddress common lowEnd = gasUsed } + optimisticGasLimit := (gasUsed + params.CallStipend) * 64 / 63 + if optimisticGasLimit < highEnd { + if forkID < FORKID_ETROG { + failed, _, _, _, err = s.internalTestGasEstimationTransactionV1(ctx, batch, l2Block, latestL2BlockNumber, transaction, forkID, senderAddress, optimisticGasLimit, nonce, false) + } else { + failed, _, _, _, err = s.internalTestGasEstimationTransactionV2(ctx, batch, l2Block, latestL2BlockNumber, transaction, forkID, senderAddress, optimisticGasLimit, nonce, false) + } + if err != nil { + // This should not happen under normal conditions since if we make it this far the + // transaction had run without error at least once before. + log.Error("Execution error in estimate gas", "err", err) + return 0, nil, err + } + if failed { + lowEnd = optimisticGasLimit + } else { + highEnd = optimisticGasLimit + } + } + // Start the binary search for the lowest possible gas price for (lowEnd < highEnd) && (highEnd-lowEnd) > 4096 { txExecutionStart := time.Now() From cde7c9adf323aa189cdcb63c8f60434e87f17d2e Mon Sep 17 00:00:00 2001 From: chengzhinei Date: Tue, 30 Apr 2024 16:55:31 +0800 Subject: [PATCH 02/18] fmt code --- state/transaction.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/state/transaction.go b/state/transaction.go index cc496bc538..eae6ee1785 100644 --- a/state/transaction.go +++ b/state/transaction.go @@ -4,7 +4,6 @@ import ( "context" "errors" "fmt" - "github.com/ethereum/go-ethereum/params" "math/big" "time" @@ -16,6 +15,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/trie" "github.com/google/uuid" "github.com/jackc/pgx/v4" From c3482977e08ccc6ca2acd6f4f462b2f3894f5665 Mon Sep 17 00:00:00 2001 From: chengzhinei Date: Tue, 30 Apr 2024 17:03:30 +0800 Subject: [PATCH 03/18] fix lint --- state/transaction.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/state/transaction.go b/state/transaction.go index eae6ee1785..cc95116199 100644 --- a/state/transaction.go +++ b/state/transaction.go @@ -852,7 +852,7 @@ func (s *State) EstimateGas(transaction *types.Transaction, senderAddress common lowEnd = gasUsed } - optimisticGasLimit := (gasUsed + params.CallStipend) * 64 / 63 + optimisticGasLimit := (gasUsed + params.CallStipend) * 64 / 63 // nolint:gomnd if optimisticGasLimit < highEnd { if forkID < FORKID_ETROG { failed, _, _, _, err = s.internalTestGasEstimationTransactionV1(ctx, batch, l2Block, latestL2BlockNumber, transaction, forkID, senderAddress, optimisticGasLimit, nonce, false) From bd7b7528da5ec96d9aa6523402d393016f911b6d Mon Sep 17 00:00:00 2001 From: chengzhinei Date: Tue, 30 Apr 2024 18:18:10 +0800 Subject: [PATCH 04/18] test --- state/transaction.go | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/state/transaction.go b/state/transaction.go index cc95116199..92d8cab0ea 100644 --- a/state/transaction.go +++ b/state/transaction.go @@ -15,7 +15,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/trie" "github.com/google/uuid" "github.com/jackc/pgx/v4" @@ -852,28 +851,29 @@ func (s *State) EstimateGas(transaction *types.Transaction, senderAddress common lowEnd = gasUsed } - optimisticGasLimit := (gasUsed + params.CallStipend) * 64 / 63 // nolint:gomnd - if optimisticGasLimit < highEnd { - if forkID < FORKID_ETROG { - failed, _, _, _, err = s.internalTestGasEstimationTransactionV1(ctx, batch, l2Block, latestL2BlockNumber, transaction, forkID, senderAddress, optimisticGasLimit, nonce, false) - } else { - failed, _, _, _, err = s.internalTestGasEstimationTransactionV2(ctx, batch, l2Block, latestL2BlockNumber, transaction, forkID, senderAddress, optimisticGasLimit, nonce, false) - } - if err != nil { - // This should not happen under normal conditions since if we make it this far the - // transaction had run without error at least once before. - log.Error("Execution error in estimate gas", "err", err) - return 0, nil, err - } - if failed { - lowEnd = optimisticGasLimit - } else { - highEnd = optimisticGasLimit - } - } + //optimisticGasLimit := (gasUsed + params.CallStipend) * 64 / 63 // nolint:gomnd + //if optimisticGasLimit < highEnd { + // if forkID < FORKID_ETROG { + // failed, _, _, _, err = s.internalTestGasEstimationTransactionV1(ctx, batch, l2Block, latestL2BlockNumber, transaction, forkID, senderAddress, optimisticGasLimit, nonce, false) + // } else { + // failed, _, _, _, err = s.internalTestGasEstimationTransactionV2(ctx, batch, l2Block, latestL2BlockNumber, transaction, forkID, senderAddress, optimisticGasLimit, nonce, false) + // } + // if err != nil { + // // This should not happen under normal conditions since if we make it this far the + // // transaction had run without error at least once before. + // log.Error("Execution error in estimate gas", "err", err) + // return 0, nil, err + // } + // if failed { + // lowEnd = optimisticGasLimit + // } else { + // highEnd = optimisticGasLimit + // } + //} // Start the binary search for the lowest possible gas price - for (lowEnd < highEnd) && (highEnd-lowEnd) > 4096 { + times := 0 + for (lowEnd < highEnd) && (highEnd-lowEnd) > 4096 && times <= 3 { txExecutionStart := time.Now() mid := (lowEnd + highEnd) / 2 // nolint:gomnd if mid > lowEnd*2 { @@ -905,6 +905,7 @@ func (s *State) EstimateGas(transaction *types.Transaction, senderAddress common // If the transaction didn't fail => make this ok value the high end highEnd = mid } + times++ } executions := int64(len(txExecutions)) From 52d5734c600a08066d05744ec557173039e729b2 Mon Sep 17 00:00:00 2001 From: chengzhinei Date: Mon, 6 May 2024 18:04:54 +0800 Subject: [PATCH 05/18] test --- state/transaction.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/state/transaction.go b/state/transaction.go index 92d8cab0ea..a5223f3720 100644 --- a/state/transaction.go +++ b/state/transaction.go @@ -872,8 +872,8 @@ func (s *State) EstimateGas(transaction *types.Transaction, senderAddress common //} // Start the binary search for the lowest possible gas price - times := 0 - for (lowEnd < highEnd) && (highEnd-lowEnd) > 4096 && times <= 3 { + highEnd = gasUsed * 2 + for (lowEnd < highEnd) && (highEnd-lowEnd) > 4096 { txExecutionStart := time.Now() mid := (lowEnd + highEnd) / 2 // nolint:gomnd if mid > lowEnd*2 { @@ -905,7 +905,6 @@ func (s *State) EstimateGas(transaction *types.Transaction, senderAddress common // If the transaction didn't fail => make this ok value the high end highEnd = mid } - times++ } executions := int64(len(txExecutions)) From bba6a821978609b15e4e38bb00c51fe1393eb9e8 Mon Sep 17 00:00:00 2001 From: chengzhinei Date: Tue, 7 May 2024 15:03:53 +0800 Subject: [PATCH 06/18] test --- state/transaction.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/state/transaction.go b/state/transaction.go index a5223f3720..6badb80527 100644 --- a/state/transaction.go +++ b/state/transaction.go @@ -872,7 +872,7 @@ func (s *State) EstimateGas(transaction *types.Transaction, senderAddress common //} // Start the binary search for the lowest possible gas price - highEnd = gasUsed * 2 + //highEnd = gasUsed * 2 for (lowEnd < highEnd) && (highEnd-lowEnd) > 4096 { txExecutionStart := time.Now() mid := (lowEnd + highEnd) / 2 // nolint:gomnd From 61206c8ca480cc25ad1d98e47c88c245cc25d3ef Mon Sep 17 00:00:00 2001 From: chengzhinei Date: Tue, 7 May 2024 16:26:41 +0800 Subject: [PATCH 07/18] test --- state/transaction.go | 42 +- test/e2e/jsonrpc1_test.go | 930 +++++++++++++++++++------------------- 2 files changed, 484 insertions(+), 488 deletions(-) diff --git a/state/transaction.go b/state/transaction.go index 6badb80527..19a8dd3262 100644 --- a/state/transaction.go +++ b/state/transaction.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "github.com/ethereum/go-ethereum/params" "math/big" "time" @@ -705,6 +706,7 @@ func CheckSupersetBatchTransactions(existingTxHashes []common.Hash, processedTxs // EstimateGas for a transaction func (s *State) EstimateGas(transaction *types.Transaction, senderAddress common.Address, l2BlockNumber *uint64, dbTx pgx.Tx) (uint64, []byte, error) { + fmt.Printf("L2 EstimateGas\n") const ethTransferGas = 21000 ctx := context.Background() @@ -751,7 +753,7 @@ func (s *State) EstimateGas(transaction *types.Transaction, senderAddress common t4 := time.Now() getNonceTime := t4.Sub(t3) - highEnd := MaxTxGasLimit + highEnd := transaction.Gas() // if gas price is set, set the highEnd to the max amount // of the account afford @@ -851,25 +853,25 @@ func (s *State) EstimateGas(transaction *types.Transaction, senderAddress common lowEnd = gasUsed } - //optimisticGasLimit := (gasUsed + params.CallStipend) * 64 / 63 // nolint:gomnd - //if optimisticGasLimit < highEnd { - // if forkID < FORKID_ETROG { - // failed, _, _, _, err = s.internalTestGasEstimationTransactionV1(ctx, batch, l2Block, latestL2BlockNumber, transaction, forkID, senderAddress, optimisticGasLimit, nonce, false) - // } else { - // failed, _, _, _, err = s.internalTestGasEstimationTransactionV2(ctx, batch, l2Block, latestL2BlockNumber, transaction, forkID, senderAddress, optimisticGasLimit, nonce, false) - // } - // if err != nil { - // // This should not happen under normal conditions since if we make it this far the - // // transaction had run without error at least once before. - // log.Error("Execution error in estimate gas", "err", err) - // return 0, nil, err - // } - // if failed { - // lowEnd = optimisticGasLimit - // } else { - // highEnd = optimisticGasLimit - // } - //} + optimisticGasLimit := (gasUsed + params.CallStipend) * 64 / 63 // nolint:gomnd + if optimisticGasLimit < highEnd { + if forkID < FORKID_ETROG { + failed, _, _, _, err = s.internalTestGasEstimationTransactionV1(ctx, batch, l2Block, latestL2BlockNumber, transaction, forkID, senderAddress, optimisticGasLimit, nonce, false) + } else { + failed, _, _, _, err = s.internalTestGasEstimationTransactionV2(ctx, batch, l2Block, latestL2BlockNumber, transaction, forkID, senderAddress, optimisticGasLimit, nonce, false) + } + if err != nil { + // This should not happen under normal conditions since if we make it this far the + // transaction had run without error at least once before. + log.Error("Execution error in estimate gas", "err", err) + return 0, nil, err + } + if failed { + lowEnd = optimisticGasLimit + } else { + highEnd = optimisticGasLimit + } + } // Start the binary search for the lowest possible gas price //highEnd = gasUsed * 2 diff --git a/test/e2e/jsonrpc1_test.go b/test/e2e/jsonrpc1_test.go index 5c2cd1cd7f..f082e58e1c 100644 --- a/test/e2e/jsonrpc1_test.go +++ b/test/e2e/jsonrpc1_test.go @@ -2,284 +2,275 @@ package e2e import ( "context" - "encoding/json" - "math/big" - "reflect" - "testing" - - "github.com/0xPolygonHermez/zkevm-node/hex" - "github.com/0xPolygonHermez/zkevm-node/jsonrpc/client" - "github.com/0xPolygonHermez/zkevm-node/jsonrpc/types" "github.com/0xPolygonHermez/zkevm-node/log" - "github.com/0xPolygonHermez/zkevm-node/pool" - "github.com/0xPolygonHermez/zkevm-node/test/contracts/bin/Double" - "github.com/0xPolygonHermez/zkevm-node/test/contracts/bin/EmitLog" "github.com/0xPolygonHermez/zkevm-node/test/contracts/bin/triggerErrors" "github.com/0xPolygonHermez/zkevm-node/test/operations" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - ethTypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethclient" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "math/big" + "testing" ) +/* // TestJSONRPC tests JSON RPC methods on a running environment. -func TestJSONRPC(t *testing.T) { - if testing.Short() { - t.Skip() - } - setup() - defer teardown() - for _, network := range networks { - log.Infof("Network %s", network.Name) - sc, err := deployContracts(network.URL, fromPriKey, network.ChainID) - require.NoError(t, err) - callOpts := &bind.CallOpts{Pending: false} + func TestJSONRPC(t *testing.T) { + if testing.Short() { + t.Skip() + } + setup() + defer teardown() + for _, network := range networks { + log.Infof("Network %s", network.Name) + sc, err := deployContracts(network.URL, fromPriKey, network.ChainID) + require.NoError(t, err) + + callOpts := &bind.CallOpts{Pending: false} - payload := big.NewInt(5) - number, err := sc.Double(callOpts, payload) - require.NoError(t, err) - expected := big.NewInt(0).Mul(payload, big.NewInt(2)) - require.Equal(t, expected, number) + payload := big.NewInt(5) + number, err := sc.Double(callOpts, payload) + require.NoError(t, err) + expected := big.NewInt(0).Mul(payload, big.NewInt(2)) + require.Equal(t, expected, number) + } } -} -func deployContracts(url, privateKey string, chainId uint64) (*Double.Double, error) { - ctx := context.Background() - client := operations.MustGetClient(url) - auth := operations.MustGetAuth(privateKey, chainId) + func deployContracts(url, privateKey string, chainId uint64) (*Double.Double, error) { + ctx := context.Background() + client := operations.MustGetClient(url) + auth := operations.MustGetAuth(privateKey, chainId) - _, scTx, sc, err := Double.DeployDouble(auth, client) - if err != nil { - return nil, err - } - err = operations.WaitTxToBeMined(ctx, client, scTx, operations.DefaultTimeoutTxToBeMined) - if err != nil { - return nil, err + _, scTx, sc, err := Double.DeployDouble(auth, client) + if err != nil { + return nil, err + } + err = operations.WaitTxToBeMined(ctx, client, scTx, operations.DefaultTimeoutTxToBeMined) + if err != nil { + return nil, err + } + + return sc, nil } - return sc, nil -} + func Test_Filters(t *testing.T) { + if testing.Short() { + t.Skip() + } + ctx := context.Background() + setup() + defer teardown() + for _, network := range networks { + // test newBlockFilter creation + log.Infof("Network %s", network.Name) + response, err := client.JSONRPCCall(network.URL, "eth_newBlockFilter") + require.NoError(t, err) + require.Nil(t, response.Error) + require.NotNil(t, response.Result) -func Test_Filters(t *testing.T) { - if testing.Short() { - t.Skip() - } - ctx := context.Background() - setup() - defer teardown() - for _, network := range networks { - // test newBlockFilter creation - log.Infof("Network %s", network.Name) - response, err := client.JSONRPCCall(network.URL, "eth_newBlockFilter") - require.NoError(t, err) - require.Nil(t, response.Error) - require.NotNil(t, response.Result) - - var filterId string - err = json.Unmarshal(response.Result, &filterId) - require.NoError(t, err) - require.NotEmpty(t, filterId) - - // test newFilter creation with block range and block hash - response, err = client.JSONRPCCall(network.URL, "eth_newFilter", map[string]interface{}{ - "BlockHash": common.HexToHash("0x1"), - "FromBlock": "0x1", - "ToBlock": "0x2", - }) - require.NoError(t, err) - require.NotNil(t, response.Error) - require.Equal(t, invalidParamsErrorCode, response.Error.Code) - require.Equal(t, "invalid argument 0: cannot specify both BlockHash and FromBlock/ToBlock, choose one or the other", response.Error.Message) - - // test newFilter creation with block hash - response, err = client.JSONRPCCall(network.URL, "eth_newFilter", map[string]interface{}{ - "BlockHash": common.HexToHash("0x1"), - "Addresses": []common.Address{ - common.HexToAddress("0x2"), - }, - "Topics": [][]common.Hash{ - {common.HexToHash("0x3")}, - }, - }) - require.NoError(t, err) - require.Nil(t, response.Error) - require.NotNil(t, response.Result) - - filterId = "" - err = json.Unmarshal(response.Result, &filterId) - require.NoError(t, err) - require.NotEmpty(t, filterId) - - // test newFilter creation with block range - response, err = client.JSONRPCCall(network.URL, "eth_newFilter", map[string]interface{}{ - "FromBlock": "0x1", - "ToBlock": "0x2", - "Addresses": []common.Address{ - common.HexToAddress("0x2"), - }, - "Topics": [][]common.Hash{ - {common.HexToHash("0x3")}, - }, - }) - require.NoError(t, err) - require.Nil(t, response.Error) - require.NotNil(t, response.Result) - - filterId = "" - err = json.Unmarshal(response.Result, &filterId) - require.NoError(t, err) - require.NotEmpty(t, filterId) - - // test uninstallFilter when filter is installed - response, err = client.JSONRPCCall(network.URL, "eth_uninstallFilter", filterId) - require.NoError(t, err) - require.Nil(t, response.Error) - require.NotNil(t, response.Result) - - var uninstalled bool - err = json.Unmarshal(response.Result, &uninstalled) - require.NoError(t, err) - require.True(t, uninstalled) - - // test uninstallFilter when filter doesn't exist or was already uninstalled - response, err = client.JSONRPCCall(network.URL, "eth_uninstallFilter", filterId) - require.NoError(t, err) - require.Nil(t, response.Error) - require.NotNil(t, response.Result) - - uninstalled = true - err = json.Unmarshal(response.Result, &uninstalled) - require.NoError(t, err) - require.False(t, uninstalled) - - ethereumClient := operations.MustGetClient(network.URL) - zkEVMClient := client.NewClient(network.URL) - auth := operations.MustGetAuth(fromPriKey, network.ChainID) - - // test getFilterChanges for a blockFilter ID - var blockBeforeFilterHash common.Hash - if network.Name == "Local L2" { - blockBeforeFilter, err := zkEVMClient.BlockByNumber(ctx, nil) + var filterId string + err = json.Unmarshal(response.Result, &filterId) require.NoError(t, err) - blockBeforeFilterHash = *blockBeforeFilter.Hash - } else { - blockBeforeFilter, err := ethereumClient.BlockByNumber(ctx, nil) + require.NotEmpty(t, filterId) + + // test newFilter creation with block range and block hash + response, err = client.JSONRPCCall(network.URL, "eth_newFilter", map[string]interface{}{ + "BlockHash": common.HexToHash("0x1"), + "FromBlock": "0x1", + "ToBlock": "0x2", + }) require.NoError(t, err) - blockBeforeFilterHash = blockBeforeFilter.Hash() - } + require.NotNil(t, response.Error) + require.Equal(t, invalidParamsErrorCode, response.Error.Code) + require.Equal(t, "invalid argument 0: cannot specify both BlockHash and FromBlock/ToBlock, choose one or the other", response.Error.Message) + + // test newFilter creation with block hash + response, err = client.JSONRPCCall(network.URL, "eth_newFilter", map[string]interface{}{ + "BlockHash": common.HexToHash("0x1"), + "Addresses": []common.Address{ + common.HexToAddress("0x2"), + }, + "Topics": [][]common.Hash{ + {common.HexToHash("0x3")}, + }, + }) + require.NoError(t, err) + require.Nil(t, response.Error) + require.NotNil(t, response.Result) + + filterId = "" + err = json.Unmarshal(response.Result, &filterId) + require.NoError(t, err) + require.NotEmpty(t, filterId) + + // test newFilter creation with block range + response, err = client.JSONRPCCall(network.URL, "eth_newFilter", map[string]interface{}{ + "FromBlock": "0x1", + "ToBlock": "0x2", + "Addresses": []common.Address{ + common.HexToAddress("0x2"), + }, + "Topics": [][]common.Hash{ + {common.HexToHash("0x3")}, + }, + }) + require.NoError(t, err) + require.Nil(t, response.Error) + require.NotNil(t, response.Result) - response, err = client.JSONRPCCall(network.URL, "eth_newBlockFilter") - require.NoError(t, err) - require.Nil(t, response.Error) - require.NotNil(t, response.Result) + filterId = "" + err = json.Unmarshal(response.Result, &filterId) + require.NoError(t, err) + require.NotEmpty(t, filterId) - var blockFilterId string - err = json.Unmarshal(response.Result, &blockFilterId) - require.NoError(t, err) - require.NotEmpty(t, blockFilterId) + // test uninstallFilter when filter is installed + response, err = client.JSONRPCCall(network.URL, "eth_uninstallFilter", filterId) + require.NoError(t, err) + require.Nil(t, response.Error) + require.NotNil(t, response.Result) - // force a block to be generated sending a eth transfer tx - tx, err := createTX(ethereumClient, auth, toAddress, big.NewInt(1000)) - require.NoError(t, err) - err = operations.WaitTxToBeMined(ctx, ethereumClient, tx, operations.DefaultTimeoutTxToBeMined) - require.NoError(t, err) + var uninstalled bool + err = json.Unmarshal(response.Result, &uninstalled) + require.NoError(t, err) + require.True(t, uninstalled) - var blockAfterFilterHash common.Hash - if network.Name == "Local L2" { - blockAfterFilter, err := zkEVMClient.BlockByNumber(ctx, nil) + // test uninstallFilter when filter doesn't exist or was already uninstalled + response, err = client.JSONRPCCall(network.URL, "eth_uninstallFilter", filterId) require.NoError(t, err) - blockAfterFilterHash = *blockAfterFilter.Hash - } else { - blockAfterFilter, err := ethereumClient.BlockByNumber(ctx, nil) + require.Nil(t, response.Error) + require.NotNil(t, response.Result) + + uninstalled = true + err = json.Unmarshal(response.Result, &uninstalled) require.NoError(t, err) - blockAfterFilterHash = blockAfterFilter.Hash() - } + require.False(t, uninstalled) - response, err = client.JSONRPCCall(network.URL, "eth_getFilterChanges", blockFilterId) - require.NoError(t, err) - require.Nil(t, response.Error) - require.NotNil(t, response.Result) + ethereumClient := operations.MustGetClient(network.URL) + zkEVMClient := client.NewClient(network.URL) + auth := operations.MustGetAuth(fromPriKey, network.ChainID) - var blockFilterChanges []common.Hash - err = json.Unmarshal(response.Result, &blockFilterChanges) - require.NoError(t, err) + // test getFilterChanges for a blockFilter ID + var blockBeforeFilterHash common.Hash + if network.Name == "Local L2" { + blockBeforeFilter, err := zkEVMClient.BlockByNumber(ctx, nil) + require.NoError(t, err) + blockBeforeFilterHash = *blockBeforeFilter.Hash + } else { + blockBeforeFilter, err := ethereumClient.BlockByNumber(ctx, nil) + require.NoError(t, err) + blockBeforeFilterHash = blockBeforeFilter.Hash() + } - assert.NotEqual(t, blockBeforeFilterHash.String(), blockFilterChanges[0].String()) - assert.Equal(t, blockAfterFilterHash.String(), blockFilterChanges[len(blockFilterChanges)-1].String()) + response, err = client.JSONRPCCall(network.URL, "eth_newBlockFilter") + require.NoError(t, err) + require.Nil(t, response.Error) + require.NotNil(t, response.Result) - // test getFilterChanges for a logFilter ID - // create a SC to emit some logs - scAddr, scTx, sc, err := EmitLog.DeployEmitLog(auth, ethereumClient) - require.NoError(t, err) - err = operations.WaitTxToBeMined(ctx, ethereumClient, scTx, operations.DefaultTimeoutTxToBeMined) - require.NoError(t, err) + var blockFilterId string + err = json.Unmarshal(response.Result, &blockFilterId) + require.NoError(t, err) + require.NotEmpty(t, blockFilterId) - response, err = client.JSONRPCCall(network.URL, "eth_newFilter", map[string]interface{}{ - "Addresses": []common.Address{scAddr}, - }) - require.NoError(t, err) - require.Nil(t, response.Error) - require.NotNil(t, response.Result) - - logFilterId := "" - err = json.Unmarshal(response.Result, &logFilterId) - require.NoError(t, err) - require.NotEmpty(t, logFilterId) - - // emit logs - tx, err = sc.EmitLogs(auth) - require.NoError(t, err) - err = operations.WaitTxToBeMined(ctx, ethereumClient, tx, operations.DefaultTimeoutTxToBeMined) - require.NoError(t, err) - - logs, err := ethereumClient.FilterLogs(ctx, ethereum.FilterQuery{Addresses: []common.Address{scAddr}}) - require.NoError(t, err) - - response, err = client.JSONRPCCall(network.URL, "eth_getFilterChanges", logFilterId) - require.NoError(t, err) - require.Nil(t, response.Error) - require.NotNil(t, response.Result) - - var logFilterChanges []ethTypes.Log - err = json.Unmarshal(response.Result, &logFilterChanges) - require.NoError(t, err) - - assert.Equal(t, 10, len(logs)) - assert.Equal(t, 10, len(logFilterChanges)) - assert.True(t, reflect.DeepEqual(logs, logFilterChanges)) - - // emit more logs - tx, err = sc.EmitLogs(auth) - require.NoError(t, err) - err = operations.WaitTxToBeMined(ctx, ethereumClient, tx, operations.DefaultTimeoutTxToBeMined) - require.NoError(t, err) - - tx, err = sc.EmitLogs(auth) - require.NoError(t, err) - err = operations.WaitTxToBeMined(ctx, ethereumClient, tx, operations.DefaultTimeoutTxToBeMined) - require.NoError(t, err) - - logs, err = ethereumClient.FilterLogs(ctx, ethereum.FilterQuery{Addresses: []common.Address{scAddr}}) - require.NoError(t, err) - - response, err = client.JSONRPCCall(network.URL, "eth_getFilterChanges", logFilterId) - require.NoError(t, err) - require.Nil(t, response.Error) - require.NotNil(t, response.Result) - - err = json.Unmarshal(response.Result, &logFilterChanges) - require.NoError(t, err) - - assert.Equal(t, 30, len(logs)) - assert.Equal(t, 20, len(logFilterChanges)) - } -} + // force a block to be generated sending a eth transfer tx + tx, err := createTX(ethereumClient, auth, toAddress, big.NewInt(1000)) + require.NoError(t, err) + err = operations.WaitTxToBeMined(ctx, ethereumClient, tx, operations.DefaultTimeoutTxToBeMined) + require.NoError(t, err) + + var blockAfterFilterHash common.Hash + if network.Name == "Local L2" { + blockAfterFilter, err := zkEVMClient.BlockByNumber(ctx, nil) + require.NoError(t, err) + blockAfterFilterHash = *blockAfterFilter.Hash + } else { + blockAfterFilter, err := ethereumClient.BlockByNumber(ctx, nil) + require.NoError(t, err) + blockAfterFilterHash = blockAfterFilter.Hash() + } + + response, err = client.JSONRPCCall(network.URL, "eth_getFilterChanges", blockFilterId) + require.NoError(t, err) + require.Nil(t, response.Error) + require.NotNil(t, response.Result) + + var blockFilterChanges []common.Hash + err = json.Unmarshal(response.Result, &blockFilterChanges) + require.NoError(t, err) + + assert.NotEqual(t, blockBeforeFilterHash.String(), blockFilterChanges[0].String()) + assert.Equal(t, blockAfterFilterHash.String(), blockFilterChanges[len(blockFilterChanges)-1].String()) + + // test getFilterChanges for a logFilter ID + // create a SC to emit some logs + scAddr, scTx, sc, err := EmitLog.DeployEmitLog(auth, ethereumClient) + require.NoError(t, err) + err = operations.WaitTxToBeMined(ctx, ethereumClient, scTx, operations.DefaultTimeoutTxToBeMined) + require.NoError(t, err) + + response, err = client.JSONRPCCall(network.URL, "eth_newFilter", map[string]interface{}{ + "Addresses": []common.Address{scAddr}, + }) + require.NoError(t, err) + require.Nil(t, response.Error) + require.NotNil(t, response.Result) + + logFilterId := "" + err = json.Unmarshal(response.Result, &logFilterId) + require.NoError(t, err) + require.NotEmpty(t, logFilterId) + + // emit logs + tx, err = sc.EmitLogs(auth) + require.NoError(t, err) + err = operations.WaitTxToBeMined(ctx, ethereumClient, tx, operations.DefaultTimeoutTxToBeMined) + require.NoError(t, err) + + logs, err := ethereumClient.FilterLogs(ctx, ethereum.FilterQuery{Addresses: []common.Address{scAddr}}) + require.NoError(t, err) + + response, err = client.JSONRPCCall(network.URL, "eth_getFilterChanges", logFilterId) + require.NoError(t, err) + require.Nil(t, response.Error) + require.NotNil(t, response.Result) + + var logFilterChanges []ethTypes.Log + err = json.Unmarshal(response.Result, &logFilterChanges) + require.NoError(t, err) + + assert.Equal(t, 10, len(logs)) + assert.Equal(t, 10, len(logFilterChanges)) + assert.True(t, reflect.DeepEqual(logs, logFilterChanges)) + + // emit more logs + tx, err = sc.EmitLogs(auth) + require.NoError(t, err) + err = operations.WaitTxToBeMined(ctx, ethereumClient, tx, operations.DefaultTimeoutTxToBeMined) + require.NoError(t, err) + + tx, err = sc.EmitLogs(auth) + require.NoError(t, err) + err = operations.WaitTxToBeMined(ctx, ethereumClient, tx, operations.DefaultTimeoutTxToBeMined) + require.NoError(t, err) + + logs, err = ethereumClient.FilterLogs(ctx, ethereum.FilterQuery{Addresses: []common.Address{scAddr}}) + require.NoError(t, err) + + response, err = client.JSONRPCCall(network.URL, "eth_getFilterChanges", logFilterId) + require.NoError(t, err) + require.Nil(t, response.Error) + require.NotNil(t, response.Result) + + err = json.Unmarshal(response.Result, &logFilterChanges) + require.NoError(t, err) + assert.Equal(t, 30, len(logs)) + assert.Equal(t, 20, len(logFilterChanges)) + } + } +*/ func Test_Gas(t *testing.T) { if testing.Short() { t.Skip() @@ -324,252 +315,253 @@ func Test_Gas(t *testing.T) { } } -func Test_Block(t *testing.T) { - if testing.Short() { - t.Skip() - } - ctx := context.Background() - setup() - defer teardown() - type rpcTx struct { - BlockHash string `json:"blockHash"` - BlockNumber string `json:"blockNumber"` - ChainID string `json:"chainId"` - From string `json:"from"` - Gas string `json:"gas"` - GasPrice string `json:"gasPrice"` - Hash string `json:"hash"` - Input string `json:"input"` - Nonce string `json:"nonce"` - PublicKey string `json:"publicKey"` - R string `json:"r"` - Raw string `json:"raw"` - S string `json:"s"` - To string `json:"to"` - TransactionIndex string `json:"transactionIndex"` - V string `json:"v"` - Value string `json:"value"` - } +/* + func Test_Block(t *testing.T) { + if testing.Short() { + t.Skip() + } + ctx := context.Background() + setup() + defer teardown() + type rpcTx struct { + BlockHash string `json:"blockHash"` + BlockNumber string `json:"blockNumber"` + ChainID string `json:"chainId"` + From string `json:"from"` + Gas string `json:"gas"` + GasPrice string `json:"gasPrice"` + Hash string `json:"hash"` + Input string `json:"input"` + Nonce string `json:"nonce"` + PublicKey string `json:"publicKey"` + R string `json:"r"` + Raw string `json:"raw"` + S string `json:"s"` + To string `json:"to"` + TransactionIndex string `json:"transactionIndex"` + V string `json:"v"` + Value string `json:"value"` + } - for _, network := range networks { - log.Infof("Network %s", network.Name) - ethereumClient, err := ethclient.Dial(network.URL) - zkEVMClient := client.NewClient(network.URL) - require.NoError(t, err) - auth, err := operations.GetAuth(fromPriKey, network.ChainID) - require.NoError(t, err) - - tx, err := createTX(ethereumClient, auth, toAddress, big.NewInt(1000)) - require.NoError(t, err) - // no block number yet... will wait - err = operations.WaitTxToBeMined(ctx, ethereumClient, tx, operations.DefaultTimeoutTxToBeMined) - require.NoError(t, err) - - receipt, err := ethereumClient.TransactionReceipt(ctx, tx.Hash()) - require.NoError(t, err) - require.Equal(t, receipt.TxHash, tx.Hash()) - require.Equal(t, receipt.Type, tx.Type()) - require.Equal(t, uint(0), receipt.TransactionIndex) + for _, network := range networks { + log.Infof("Network %s", network.Name) + ethereumClient, err := ethclient.Dial(network.URL) + zkEVMClient := client.NewClient(network.URL) + require.NoError(t, err) + auth, err := operations.GetAuth(fromPriKey, network.ChainID) + require.NoError(t, err) - if network.Name == "Local L2" { - block, err := zkEVMClient.BlockByNumber(ctx, receipt.BlockNumber) + tx, err := createTX(ethereumClient, auth, toAddress, big.NewInt(1000)) + require.NoError(t, err) + // no block number yet... will wait + err = operations.WaitTxToBeMined(ctx, ethereumClient, tx, operations.DefaultTimeoutTxToBeMined) + require.NoError(t, err) + + receipt, err := ethereumClient.TransactionReceipt(ctx, tx.Hash()) + require.NoError(t, err) + require.Equal(t, receipt.TxHash, tx.Hash()) + require.Equal(t, receipt.Type, tx.Type()) + require.Equal(t, uint(0), receipt.TransactionIndex) + + if network.Name == "Local L2" { + block, err := zkEVMClient.BlockByNumber(ctx, receipt.BlockNumber) + require.NoError(t, err) + require.NotNil(t, block) + require.Equal(t, receipt.BlockNumber.Uint64(), uint64(block.Number)) + require.Equal(t, receipt.BlockHash.String(), block.Hash.String()) + + block, err = zkEVMClient.BlockByHash(ctx, receipt.BlockHash) + require.NoError(t, err) + require.NotNil(t, block) + require.Equal(t, receipt.BlockNumber.Uint64(), uint64(block.Number)) + require.Equal(t, receipt.BlockHash.String(), block.Hash.String()) + } else { + block, err := ethereumClient.BlockByNumber(ctx, receipt.BlockNumber) + require.NoError(t, err) + require.NotNil(t, block) + require.Equal(t, receipt.BlockNumber.Uint64(), block.NumberU64()) + require.Equal(t, receipt.BlockHash.String(), block.Hash().String()) + + block, err = ethereumClient.BlockByHash(ctx, receipt.BlockHash) + require.NoError(t, err) + require.NotNil(t, block) + require.Equal(t, receipt.BlockNumber.Uint64(), block.NumberU64()) + require.Equal(t, receipt.BlockHash.String(), block.Hash().String()) + } + + blockNumber, err := ethereumClient.BlockNumber(ctx) + require.NoError(t, err) + log.Infof("\nBlock num %d", blockNumber) + require.GreaterOrEqual(t, blockNumber, receipt.BlockNumber.Uint64()) + + nonExistentBlockNumber := big.NewInt(0).SetUint64(blockNumber + uint64(1000)) + _, err = ethereumClient.BlockByNumber(ctx, nonExistentBlockNumber) + require.Error(t, err) + + nonExistentBlockHash := common.HexToHash("0xFFFFFF") + _, err = ethereumClient.BlockByHash(ctx, nonExistentBlockHash) + require.Error(t, err) + + // its pending + response, err := client.JSONRPCCall(network.URL, "eth_getBlockTransactionCountByNumber", hexutil.EncodeBig(receipt.BlockNumber)) + require.NoError(t, err) + require.Nil(t, response.Error) + require.NotNil(t, response.Result) + + txCount := "" + err = json.Unmarshal(response.Result, &txCount) + require.NoError(t, err) + require.Equal(t, "0x1", txCount) + + // check if block number is correct + count, err := ethereumClient.TransactionCount(ctx, receipt.BlockHash) + require.NoError(t, err) + require.Equal(t, uint(1), count) + + tx = nil + tx, err = ethereumClient.TransactionInBlock(ctx, receipt.BlockHash, receipt.TransactionIndex) + require.NoError(t, err) + require.Equal(t, receipt.TxHash, tx.Hash()) + + raw, err := client.JSONRPCCall(network.URL, "eth_getTransactionByBlockNumberAndIndex", hexutil.EncodeBig(receipt.BlockNumber), "0x0") require.NoError(t, err) - require.NotNil(t, block) - require.Equal(t, receipt.BlockNumber.Uint64(), uint64(block.Number)) - require.Equal(t, receipt.BlockHash.String(), block.Hash.String()) + require.Nil(t, raw.Error) + require.NotNil(t, raw.Result) - block, err = zkEVMClient.BlockByHash(ctx, receipt.BlockHash) + var newTx rpcTx + err = json.Unmarshal(raw.Result, &newTx) require.NoError(t, err) - require.NotNil(t, block) - require.Equal(t, receipt.BlockNumber.Uint64(), uint64(block.Number)) - require.Equal(t, receipt.BlockHash.String(), block.Hash.String()) - } else { - block, err := ethereumClient.BlockByNumber(ctx, receipt.BlockNumber) + + raw, err = client.JSONRPCCall(network.URL, "eth_getTransactionByBlockNumberAndIndex", "0x123", "0x8659") require.NoError(t, err) - require.NotNil(t, block) - require.Equal(t, receipt.BlockNumber.Uint64(), block.NumberU64()) - require.Equal(t, receipt.BlockHash.String(), block.Hash().String()) + require.Nil(t, raw.Error) + require.NotNil(t, raw.Result) - block, err = ethereumClient.BlockByHash(ctx, receipt.BlockHash) + var empty rpcTx + err = json.Unmarshal(raw.Result, &empty) require.NoError(t, err) - require.NotNil(t, block) - require.Equal(t, receipt.BlockNumber.Uint64(), block.NumberU64()) - require.Equal(t, receipt.BlockHash.String(), block.Hash().String()) + + // Checks for empty, when the lookup fail we get an empty struct and no errors... + v := reflect.ValueOf(empty) + + for i := 0; i < v.NumField(); i++ { + require.Empty(t, v.Field(i).Interface()) + } + + // checks for successful query + require.Equal(t, hexutil.EncodeBig(receipt.BlockNumber), newTx.BlockNumber) + require.Equal(t, receipt.BlockHash.String(), newTx.BlockHash) + require.Equal(t, hexutil.EncodeUint64(tx.Nonce()), newTx.Nonce) + require.Equal(t, hexutil.EncodeBig(tx.ChainId()), newTx.ChainID) } + } - blockNumber, err := ethereumClient.BlockNumber(ctx) - require.NoError(t, err) - log.Infof("\nBlock num %d", blockNumber) - require.GreaterOrEqual(t, blockNumber, receipt.BlockNumber.Uint64()) - - nonExistentBlockNumber := big.NewInt(0).SetUint64(blockNumber + uint64(1000)) - _, err = ethereumClient.BlockByNumber(ctx, nonExistentBlockNumber) - require.Error(t, err) - - nonExistentBlockHash := common.HexToHash("0xFFFFFF") - _, err = ethereumClient.BlockByHash(ctx, nonExistentBlockHash) - require.Error(t, err) - - // its pending - response, err := client.JSONRPCCall(network.URL, "eth_getBlockTransactionCountByNumber", hexutil.EncodeBig(receipt.BlockNumber)) - require.NoError(t, err) - require.Nil(t, response.Error) - require.NotNil(t, response.Result) - - txCount := "" - err = json.Unmarshal(response.Result, &txCount) - require.NoError(t, err) - require.Equal(t, "0x1", txCount) - - // check if block number is correct - count, err := ethereumClient.TransactionCount(ctx, receipt.BlockHash) - require.NoError(t, err) - require.Equal(t, uint(1), count) - - tx = nil - tx, err = ethereumClient.TransactionInBlock(ctx, receipt.BlockHash, receipt.TransactionIndex) - require.NoError(t, err) - require.Equal(t, receipt.TxHash, tx.Hash()) - - raw, err := client.JSONRPCCall(network.URL, "eth_getTransactionByBlockNumberAndIndex", hexutil.EncodeBig(receipt.BlockNumber), "0x0") - require.NoError(t, err) - require.Nil(t, raw.Error) - require.NotNil(t, raw.Result) - - var newTx rpcTx - err = json.Unmarshal(raw.Result, &newTx) - require.NoError(t, err) - - raw, err = client.JSONRPCCall(network.URL, "eth_getTransactionByBlockNumberAndIndex", "0x123", "0x8659") - require.NoError(t, err) - require.Nil(t, raw.Error) - require.NotNil(t, raw.Result) - - var empty rpcTx - err = json.Unmarshal(raw.Result, &empty) - require.NoError(t, err) - - // Checks for empty, when the lookup fail we get an empty struct and no errors... - v := reflect.ValueOf(empty) - - for i := 0; i < v.NumField(); i++ { - require.Empty(t, v.Field(i).Interface()) + func Test_Transactions(t *testing.T) { + if testing.Short() { + t.Skip() } + ctx := context.Background() + setup() + defer teardown() + for _, network := range networks { + log.Infof("Network %s", network.Name) + ethClient, err := ethclient.Dial(network.URL) + require.NoError(t, err) + auth, err := operations.GetAuth(fromPriKey, network.ChainID) + require.NoError(t, err) - // checks for successful query - require.Equal(t, hexutil.EncodeBig(receipt.BlockNumber), newTx.BlockNumber) - require.Equal(t, receipt.BlockHash.String(), newTx.BlockHash) - require.Equal(t, hexutil.EncodeUint64(tx.Nonce()), newTx.Nonce) - require.Equal(t, hexutil.EncodeBig(tx.ChainId()), newTx.ChainID) - } -} + // Test Case: Successful transfer + tx, err := createTX(ethClient, auth, toAddress, big.NewInt(100000)) + require.NoError(t, err) + err = operations.WaitTxToBeMined(ctx, ethClient, tx, operations.DefaultTimeoutTxToBeMined) + require.NoError(t, err) -func Test_Transactions(t *testing.T) { - if testing.Short() { - t.Skip() - } - ctx := context.Background() - setup() - defer teardown() - for _, network := range networks { - log.Infof("Network %s", network.Name) - ethClient, err := ethclient.Dial(network.URL) - require.NoError(t, err) - auth, err := operations.GetAuth(fromPriKey, network.ChainID) - require.NoError(t, err) - - // Test Case: Successful transfer - tx, err := createTX(ethClient, auth, toAddress, big.NewInt(100000)) - require.NoError(t, err) - err = operations.WaitTxToBeMined(ctx, ethClient, tx, operations.DefaultTimeoutTxToBeMined) - require.NoError(t, err) - - // Test Case: get transaction by block number and index - receipt, err := ethClient.TransactionReceipt(ctx, tx.Hash()) - require.NoError(t, err) - require.NotNil(t, receipt) - res, err := client.JSONRPCCall(network.URL, "eth_getTransactionByBlockNumberAndIndex", hex.EncodeBig(receipt.BlockNumber), hex.EncodeUint64(uint64(receipt.TransactionIndex))) - require.NoError(t, err) - require.Nil(t, res.Error) - require.NotNil(t, res.Result) - var txByBlockNumberAndIndex *types.Transaction - err = json.Unmarshal(res.Result, &txByBlockNumberAndIndex) - require.NoError(t, err) - - require.Equal(t, tx.Hash().String(), txByBlockNumberAndIndex.Hash.String()) - - // Test Case: get transaction by block hash and index - receipt, err = ethClient.TransactionReceipt(ctx, tx.Hash()) - require.NoError(t, err) - require.NotNil(t, receipt) - txByBlockHashAndIndex, err := ethClient.TransactionInBlock(ctx, receipt.BlockHash, receipt.TransactionIndex) - require.NoError(t, err) - require.Equal(t, tx.Hash().String(), txByBlockHashAndIndex.Hash().String()) - - // Setup for test cases - nonce, err := ethClient.NonceAt(context.Background(), auth.From, nil) - require.NoError(t, err) - - gasLimit, err := ethClient.EstimateGas(context.Background(), ethereum.CallMsg{From: auth.From, To: &toAddress, Value: big.NewInt(10000)}) - require.NoError(t, err) - - gasPrice, err := ethClient.SuggestGasPrice(context.Background()) - require.NoError(t, err) - - // Test Case: TX with invalid nonce - tx = ethTypes.NewTransaction(nonce-1, // Nonce will be lower than the current getNonceAt() - toAddress, big.NewInt(100), gasLimit, gasPrice, nil) - signedTx, err := auth.Signer(auth.From, tx) - require.NoError(t, err) - - log.Infof("Sending Tx %v Nonce (invalid) %v", signedTx.Hash(), signedTx.Nonce()) - err = ethClient.SendTransaction(context.Background(), signedTx) - require.ErrorContains(t, err, "nonce too low") - // End Test Case - - // Test Case: TX with no signature (which would fail the EIP-155) - invalidTx := ethTypes.NewTx(ðTypes.LegacyTx{ - Nonce: nonce, - Value: big.NewInt(10000), - Gas: gasLimit, - GasPrice: gasPrice, - Data: nil, - }) - err = ethClient.SendTransaction(context.Background(), invalidTx) - require.Error(t, err) - // End Test Case + // Test Case: get transaction by block number and index + receipt, err := ethClient.TransactionReceipt(ctx, tx.Hash()) + require.NoError(t, err) + require.NotNil(t, receipt) + res, err := client.JSONRPCCall(network.URL, "eth_getTransactionByBlockNumberAndIndex", hex.EncodeBig(receipt.BlockNumber), hex.EncodeUint64(uint64(receipt.TransactionIndex))) + require.NoError(t, err) + require.Nil(t, res.Error) + require.NotNil(t, res.Result) + var txByBlockNumberAndIndex *types.Transaction + err = json.Unmarshal(res.Result, &txByBlockNumberAndIndex) + require.NoError(t, err) - // Test Case: TX with amount being higher than balance - balance, err := ethClient.BalanceAt(context.Background(), auth.From, nil) - require.NoError(t, err) + require.Equal(t, tx.Hash().String(), txByBlockNumberAndIndex.Hash.String()) - nonce, err = ethClient.NonceAt(context.Background(), auth.From, nil) - require.NoError(t, err) + // Test Case: get transaction by block hash and index + receipt, err = ethClient.TransactionReceipt(ctx, tx.Hash()) + require.NoError(t, err) + require.NotNil(t, receipt) + txByBlockHashAndIndex, err := ethClient.TransactionInBlock(ctx, receipt.BlockHash, receipt.TransactionIndex) + require.NoError(t, err) + require.Equal(t, tx.Hash().String(), txByBlockHashAndIndex.Hash().String()) - log.Infof("Balance: %d", balance) + // Setup for test cases + nonce, err := ethClient.NonceAt(context.Background(), auth.From, nil) + require.NoError(t, err) - tx = ethTypes.NewTransaction(nonce, toAddress, big.NewInt(0).Add(balance, big.NewInt(10)), gasLimit, gasPrice, nil) - signedTx, err = auth.Signer(auth.From, tx) - require.NoError(t, err) + gasLimit, err := ethClient.EstimateGas(context.Background(), ethereum.CallMsg{From: auth.From, To: &toAddress, Value: big.NewInt(10000)}) + require.NoError(t, err) - log.Infof("Sending Tx %v Nonce %v", signedTx.Hash(), signedTx.Nonce()) - err = ethClient.SendTransaction(context.Background(), signedTx) - require.ErrorContains(t, err, pool.ErrInsufficientFunds.Error()) + gasPrice, err := ethClient.SuggestGasPrice(context.Background()) + require.NoError(t, err) - // no contract code at given address test - // deploy contract with not enough gas for storage, just execution - address := common.HexToAddress("0xDEADBEEF596a836C9063a7EE35dA94DDA3b57B62") - instance, err := Double.NewDouble(address, ethClient) - require.NoError(t, err) + // Test Case: TX with invalid nonce + tx = ethTypes.NewTransaction(nonce-1, // Nonce will be lower than the current getNonceAt() + toAddress, big.NewInt(100), gasLimit, gasPrice, nil) + signedTx, err := auth.Signer(auth.From, tx) + require.NoError(t, err) - callOpts := &bind.CallOpts{Pending: false} + log.Infof("Sending Tx %v Nonce (invalid) %v", signedTx.Hash(), signedTx.Nonce()) + err = ethClient.SendTransaction(context.Background(), signedTx) + require.ErrorContains(t, err, "nonce too low") + // End Test Case + + // Test Case: TX with no signature (which would fail the EIP-155) + invalidTx := ethTypes.NewTx(ðTypes.LegacyTx{ + Nonce: nonce, + Value: big.NewInt(10000), + Gas: gasLimit, + GasPrice: gasPrice, + Data: nil, + }) + err = ethClient.SendTransaction(context.Background(), invalidTx) + require.Error(t, err) + // End Test Case + + // Test Case: TX with amount being higher than balance + balance, err := ethClient.BalanceAt(context.Background(), auth.From, nil) + require.NoError(t, err) - payload := big.NewInt(5) - _, err = instance.Double(callOpts, payload) - require.ErrorContains(t, err, "no contract code at given address") - } -} + nonce, err = ethClient.NonceAt(context.Background(), auth.From, nil) + require.NoError(t, err) + + log.Infof("Balance: %d", balance) + + tx = ethTypes.NewTransaction(nonce, toAddress, big.NewInt(0).Add(balance, big.NewInt(10)), gasLimit, gasPrice, nil) + signedTx, err = auth.Signer(auth.From, tx) + require.NoError(t, err) + + log.Infof("Sending Tx %v Nonce %v", signedTx.Hash(), signedTx.Nonce()) + err = ethClient.SendTransaction(context.Background(), signedTx) + require.ErrorContains(t, err, pool.ErrInsufficientFunds.Error()) + // no contract code at given address test + // deploy contract with not enough gas for storage, just execution + address := common.HexToAddress("0xDEADBEEF596a836C9063a7EE35dA94DDA3b57B62") + instance, err := Double.NewDouble(address, ethClient) + require.NoError(t, err) + + callOpts := &bind.CallOpts{Pending: false} + + payload := big.NewInt(5) + _, err = instance.Double(callOpts, payload) + require.ErrorContains(t, err, "no contract code at given address") + } + } +*/ func Test_OOCErrors(t *testing.T) { if testing.Short() { t.Skip() @@ -676,6 +668,7 @@ func Test_OOCErrors(t *testing.T) { } } +/* func Test_EstimateCounters(t *testing.T) { if testing.Short() { t.Skip() @@ -796,3 +789,4 @@ func Test_EstimateCounters(t *testing.T) { }) } } +*/ From 38f469ed2fb05cf090312bfe65d58d6271b6932d Mon Sep 17 00:00:00 2001 From: chengzhinei Date: Tue, 7 May 2024 16:35:34 +0800 Subject: [PATCH 08/18] test --- state/transaction.go | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/state/transaction.go b/state/transaction.go index 19a8dd3262..b39bc75d04 100644 --- a/state/transaction.go +++ b/state/transaction.go @@ -753,7 +753,7 @@ func (s *State) EstimateGas(transaction *types.Transaction, senderAddress common t4 := time.Now() getNonceTime := t4.Sub(t3) - highEnd := transaction.Gas() + highEnd := MaxTxGasLimit // if gas price is set, set the highEnd to the max amount // of the account afford @@ -853,24 +853,28 @@ func (s *State) EstimateGas(transaction *types.Transaction, senderAddress common lowEnd = gasUsed } - optimisticGasLimit := (gasUsed + params.CallStipend) * 64 / 63 // nolint:gomnd - if optimisticGasLimit < highEnd { - if forkID < FORKID_ETROG { - failed, _, _, _, err = s.internalTestGasEstimationTransactionV1(ctx, batch, l2Block, latestL2BlockNumber, transaction, forkID, senderAddress, optimisticGasLimit, nonce, false) - } else { - failed, _, _, _, err = s.internalTestGasEstimationTransactionV2(ctx, batch, l2Block, latestL2BlockNumber, transaction, forkID, senderAddress, optimisticGasLimit, nonce, false) - } - if err != nil { - // This should not happen under normal conditions since if we make it this far the - // transaction had run without error at least once before. - log.Error("Execution error in estimate gas", "err", err) - return 0, nil, err - } - if failed { - lowEnd = optimisticGasLimit - } else { - highEnd = optimisticGasLimit + if transaction.Gas() != 0 { + optimisticGasLimit := (gasUsed + params.CallStipend) * 64 / 63 // nolint:gomnd + if optimisticGasLimit < highEnd { + if forkID < FORKID_ETROG { + failed, _, _, _, err = s.internalTestGasEstimationTransactionV1(ctx, batch, l2Block, latestL2BlockNumber, transaction, forkID, senderAddress, optimisticGasLimit, nonce, false) + } else { + failed, _, _, _, err = s.internalTestGasEstimationTransactionV2(ctx, batch, l2Block, latestL2BlockNumber, transaction, forkID, senderAddress, optimisticGasLimit, nonce, false) + } + if err != nil { + // This should not happen under normal conditions since if we make it this far the + // transaction had run without error at least once before. + log.Error("Execution error in estimate gas", "err", err) + return 0, nil, err + } + if failed { + lowEnd = optimisticGasLimit + } else { + highEnd = optimisticGasLimit + } } + } else { + highEnd = transaction.Gas() } // Start the binary search for the lowest possible gas price From b39d8a2c1bedc2c7d222efe4a041c28b52fa273b Mon Sep 17 00:00:00 2001 From: chengzhinei Date: Tue, 7 May 2024 16:42:46 +0800 Subject: [PATCH 09/18] fix ut --- state/transaction.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/state/transaction.go b/state/transaction.go index b39bc75d04..e582d0c50c 100644 --- a/state/transaction.go +++ b/state/transaction.go @@ -853,7 +853,7 @@ func (s *State) EstimateGas(transaction *types.Transaction, senderAddress common lowEnd = gasUsed } - if transaction.Gas() != 0 { + if transaction.Gas() == 0 { optimisticGasLimit := (gasUsed + params.CallStipend) * 64 / 63 // nolint:gomnd if optimisticGasLimit < highEnd { if forkID < FORKID_ETROG { From cc5c962b017478da979bc04219415a04ce242c60 Mon Sep 17 00:00:00 2001 From: chengzhinei Date: Tue, 7 May 2024 16:55:42 +0800 Subject: [PATCH 10/18] fix lint --- state/transaction.go | 1 - test/e2e/jsonrpc1_test.go | 930 +++++++++++++++++++------------------- 2 files changed, 468 insertions(+), 463 deletions(-) diff --git a/state/transaction.go b/state/transaction.go index e582d0c50c..844b67f8db 100644 --- a/state/transaction.go +++ b/state/transaction.go @@ -878,7 +878,6 @@ func (s *State) EstimateGas(transaction *types.Transaction, senderAddress common } // Start the binary search for the lowest possible gas price - //highEnd = gasUsed * 2 for (lowEnd < highEnd) && (highEnd-lowEnd) > 4096 { txExecutionStart := time.Now() mid := (lowEnd + highEnd) / 2 // nolint:gomnd diff --git a/test/e2e/jsonrpc1_test.go b/test/e2e/jsonrpc1_test.go index f082e58e1c..5c2cd1cd7f 100644 --- a/test/e2e/jsonrpc1_test.go +++ b/test/e2e/jsonrpc1_test.go @@ -2,275 +2,284 @@ package e2e import ( "context" + "encoding/json" + "math/big" + "reflect" + "testing" + + "github.com/0xPolygonHermez/zkevm-node/hex" + "github.com/0xPolygonHermez/zkevm-node/jsonrpc/client" + "github.com/0xPolygonHermez/zkevm-node/jsonrpc/types" "github.com/0xPolygonHermez/zkevm-node/log" + "github.com/0xPolygonHermez/zkevm-node/pool" + "github.com/0xPolygonHermez/zkevm-node/test/contracts/bin/Double" + "github.com/0xPolygonHermez/zkevm-node/test/contracts/bin/EmitLog" "github.com/0xPolygonHermez/zkevm-node/test/contracts/bin/triggerErrors" "github.com/0xPolygonHermez/zkevm-node/test/operations" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + ethTypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethclient" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "math/big" - "testing" ) -/* // TestJSONRPC tests JSON RPC methods on a running environment. - - func TestJSONRPC(t *testing.T) { - if testing.Short() { - t.Skip() - } - setup() - defer teardown() - for _, network := range networks { - log.Infof("Network %s", network.Name) - sc, err := deployContracts(network.URL, fromPriKey, network.ChainID) - require.NoError(t, err) - - callOpts := &bind.CallOpts{Pending: false} - - payload := big.NewInt(5) - number, err := sc.Double(callOpts, payload) - require.NoError(t, err) - expected := big.NewInt(0).Mul(payload, big.NewInt(2)) - require.Equal(t, expected, number) - } +func TestJSONRPC(t *testing.T) { + if testing.Short() { + t.Skip() } + setup() + defer teardown() + for _, network := range networks { + log.Infof("Network %s", network.Name) + sc, err := deployContracts(network.URL, fromPriKey, network.ChainID) + require.NoError(t, err) - func deployContracts(url, privateKey string, chainId uint64) (*Double.Double, error) { - ctx := context.Background() - client := operations.MustGetClient(url) - auth := operations.MustGetAuth(privateKey, chainId) - - _, scTx, sc, err := Double.DeployDouble(auth, client) - if err != nil { - return nil, err - } - err = operations.WaitTxToBeMined(ctx, client, scTx, operations.DefaultTimeoutTxToBeMined) - if err != nil { - return nil, err - } + callOpts := &bind.CallOpts{Pending: false} - return sc, nil + payload := big.NewInt(5) + number, err := sc.Double(callOpts, payload) + require.NoError(t, err) + expected := big.NewInt(0).Mul(payload, big.NewInt(2)) + require.Equal(t, expected, number) } +} - func Test_Filters(t *testing.T) { - if testing.Short() { - t.Skip() - } - ctx := context.Background() - setup() - defer teardown() - for _, network := range networks { - // test newBlockFilter creation - log.Infof("Network %s", network.Name) - response, err := client.JSONRPCCall(network.URL, "eth_newBlockFilter") - require.NoError(t, err) - require.Nil(t, response.Error) - require.NotNil(t, response.Result) - - var filterId string - err = json.Unmarshal(response.Result, &filterId) - require.NoError(t, err) - require.NotEmpty(t, filterId) - - // test newFilter creation with block range and block hash - response, err = client.JSONRPCCall(network.URL, "eth_newFilter", map[string]interface{}{ - "BlockHash": common.HexToHash("0x1"), - "FromBlock": "0x1", - "ToBlock": "0x2", - }) - require.NoError(t, err) - require.NotNil(t, response.Error) - require.Equal(t, invalidParamsErrorCode, response.Error.Code) - require.Equal(t, "invalid argument 0: cannot specify both BlockHash and FromBlock/ToBlock, choose one or the other", response.Error.Message) - - // test newFilter creation with block hash - response, err = client.JSONRPCCall(network.URL, "eth_newFilter", map[string]interface{}{ - "BlockHash": common.HexToHash("0x1"), - "Addresses": []common.Address{ - common.HexToAddress("0x2"), - }, - "Topics": [][]common.Hash{ - {common.HexToHash("0x3")}, - }, - }) - require.NoError(t, err) - require.Nil(t, response.Error) - require.NotNil(t, response.Result) - - filterId = "" - err = json.Unmarshal(response.Result, &filterId) - require.NoError(t, err) - require.NotEmpty(t, filterId) - - // test newFilter creation with block range - response, err = client.JSONRPCCall(network.URL, "eth_newFilter", map[string]interface{}{ - "FromBlock": "0x1", - "ToBlock": "0x2", - "Addresses": []common.Address{ - common.HexToAddress("0x2"), - }, - "Topics": [][]common.Hash{ - {common.HexToHash("0x3")}, - }, - }) - require.NoError(t, err) - require.Nil(t, response.Error) - require.NotNil(t, response.Result) - - filterId = "" - err = json.Unmarshal(response.Result, &filterId) - require.NoError(t, err) - require.NotEmpty(t, filterId) - - // test uninstallFilter when filter is installed - response, err = client.JSONRPCCall(network.URL, "eth_uninstallFilter", filterId) - require.NoError(t, err) - require.Nil(t, response.Error) - require.NotNil(t, response.Result) - - var uninstalled bool - err = json.Unmarshal(response.Result, &uninstalled) - require.NoError(t, err) - require.True(t, uninstalled) - - // test uninstallFilter when filter doesn't exist or was already uninstalled - response, err = client.JSONRPCCall(network.URL, "eth_uninstallFilter", filterId) - require.NoError(t, err) - require.Nil(t, response.Error) - require.NotNil(t, response.Result) - - uninstalled = true - err = json.Unmarshal(response.Result, &uninstalled) - require.NoError(t, err) - require.False(t, uninstalled) - - ethereumClient := operations.MustGetClient(network.URL) - zkEVMClient := client.NewClient(network.URL) - auth := operations.MustGetAuth(fromPriKey, network.ChainID) - - // test getFilterChanges for a blockFilter ID - var blockBeforeFilterHash common.Hash - if network.Name == "Local L2" { - blockBeforeFilter, err := zkEVMClient.BlockByNumber(ctx, nil) - require.NoError(t, err) - blockBeforeFilterHash = *blockBeforeFilter.Hash - } else { - blockBeforeFilter, err := ethereumClient.BlockByNumber(ctx, nil) - require.NoError(t, err) - blockBeforeFilterHash = blockBeforeFilter.Hash() - } - - response, err = client.JSONRPCCall(network.URL, "eth_newBlockFilter") - require.NoError(t, err) - require.Nil(t, response.Error) - require.NotNil(t, response.Result) - - var blockFilterId string - err = json.Unmarshal(response.Result, &blockFilterId) - require.NoError(t, err) - require.NotEmpty(t, blockFilterId) - - // force a block to be generated sending a eth transfer tx - tx, err := createTX(ethereumClient, auth, toAddress, big.NewInt(1000)) - require.NoError(t, err) - err = operations.WaitTxToBeMined(ctx, ethereumClient, tx, operations.DefaultTimeoutTxToBeMined) - require.NoError(t, err) - - var blockAfterFilterHash common.Hash - if network.Name == "Local L2" { - blockAfterFilter, err := zkEVMClient.BlockByNumber(ctx, nil) - require.NoError(t, err) - blockAfterFilterHash = *blockAfterFilter.Hash - } else { - blockAfterFilter, err := ethereumClient.BlockByNumber(ctx, nil) - require.NoError(t, err) - blockAfterFilterHash = blockAfterFilter.Hash() - } - - response, err = client.JSONRPCCall(network.URL, "eth_getFilterChanges", blockFilterId) - require.NoError(t, err) - require.Nil(t, response.Error) - require.NotNil(t, response.Result) - - var blockFilterChanges []common.Hash - err = json.Unmarshal(response.Result, &blockFilterChanges) - require.NoError(t, err) - - assert.NotEqual(t, blockBeforeFilterHash.String(), blockFilterChanges[0].String()) - assert.Equal(t, blockAfterFilterHash.String(), blockFilterChanges[len(blockFilterChanges)-1].String()) - - // test getFilterChanges for a logFilter ID - // create a SC to emit some logs - scAddr, scTx, sc, err := EmitLog.DeployEmitLog(auth, ethereumClient) - require.NoError(t, err) - err = operations.WaitTxToBeMined(ctx, ethereumClient, scTx, operations.DefaultTimeoutTxToBeMined) - require.NoError(t, err) +func deployContracts(url, privateKey string, chainId uint64) (*Double.Double, error) { + ctx := context.Background() + client := operations.MustGetClient(url) + auth := operations.MustGetAuth(privateKey, chainId) - response, err = client.JSONRPCCall(network.URL, "eth_newFilter", map[string]interface{}{ - "Addresses": []common.Address{scAddr}, - }) - require.NoError(t, err) - require.Nil(t, response.Error) - require.NotNil(t, response.Result) + _, scTx, sc, err := Double.DeployDouble(auth, client) + if err != nil { + return nil, err + } + err = operations.WaitTxToBeMined(ctx, client, scTx, operations.DefaultTimeoutTxToBeMined) + if err != nil { + return nil, err + } - logFilterId := "" - err = json.Unmarshal(response.Result, &logFilterId) - require.NoError(t, err) - require.NotEmpty(t, logFilterId) + return sc, nil +} - // emit logs - tx, err = sc.EmitLogs(auth) - require.NoError(t, err) - err = operations.WaitTxToBeMined(ctx, ethereumClient, tx, operations.DefaultTimeoutTxToBeMined) +func Test_Filters(t *testing.T) { + if testing.Short() { + t.Skip() + } + ctx := context.Background() + setup() + defer teardown() + for _, network := range networks { + // test newBlockFilter creation + log.Infof("Network %s", network.Name) + response, err := client.JSONRPCCall(network.URL, "eth_newBlockFilter") + require.NoError(t, err) + require.Nil(t, response.Error) + require.NotNil(t, response.Result) + + var filterId string + err = json.Unmarshal(response.Result, &filterId) + require.NoError(t, err) + require.NotEmpty(t, filterId) + + // test newFilter creation with block range and block hash + response, err = client.JSONRPCCall(network.URL, "eth_newFilter", map[string]interface{}{ + "BlockHash": common.HexToHash("0x1"), + "FromBlock": "0x1", + "ToBlock": "0x2", + }) + require.NoError(t, err) + require.NotNil(t, response.Error) + require.Equal(t, invalidParamsErrorCode, response.Error.Code) + require.Equal(t, "invalid argument 0: cannot specify both BlockHash and FromBlock/ToBlock, choose one or the other", response.Error.Message) + + // test newFilter creation with block hash + response, err = client.JSONRPCCall(network.URL, "eth_newFilter", map[string]interface{}{ + "BlockHash": common.HexToHash("0x1"), + "Addresses": []common.Address{ + common.HexToAddress("0x2"), + }, + "Topics": [][]common.Hash{ + {common.HexToHash("0x3")}, + }, + }) + require.NoError(t, err) + require.Nil(t, response.Error) + require.NotNil(t, response.Result) + + filterId = "" + err = json.Unmarshal(response.Result, &filterId) + require.NoError(t, err) + require.NotEmpty(t, filterId) + + // test newFilter creation with block range + response, err = client.JSONRPCCall(network.URL, "eth_newFilter", map[string]interface{}{ + "FromBlock": "0x1", + "ToBlock": "0x2", + "Addresses": []common.Address{ + common.HexToAddress("0x2"), + }, + "Topics": [][]common.Hash{ + {common.HexToHash("0x3")}, + }, + }) + require.NoError(t, err) + require.Nil(t, response.Error) + require.NotNil(t, response.Result) + + filterId = "" + err = json.Unmarshal(response.Result, &filterId) + require.NoError(t, err) + require.NotEmpty(t, filterId) + + // test uninstallFilter when filter is installed + response, err = client.JSONRPCCall(network.URL, "eth_uninstallFilter", filterId) + require.NoError(t, err) + require.Nil(t, response.Error) + require.NotNil(t, response.Result) + + var uninstalled bool + err = json.Unmarshal(response.Result, &uninstalled) + require.NoError(t, err) + require.True(t, uninstalled) + + // test uninstallFilter when filter doesn't exist or was already uninstalled + response, err = client.JSONRPCCall(network.URL, "eth_uninstallFilter", filterId) + require.NoError(t, err) + require.Nil(t, response.Error) + require.NotNil(t, response.Result) + + uninstalled = true + err = json.Unmarshal(response.Result, &uninstalled) + require.NoError(t, err) + require.False(t, uninstalled) + + ethereumClient := operations.MustGetClient(network.URL) + zkEVMClient := client.NewClient(network.URL) + auth := operations.MustGetAuth(fromPriKey, network.ChainID) + + // test getFilterChanges for a blockFilter ID + var blockBeforeFilterHash common.Hash + if network.Name == "Local L2" { + blockBeforeFilter, err := zkEVMClient.BlockByNumber(ctx, nil) require.NoError(t, err) - - logs, err := ethereumClient.FilterLogs(ctx, ethereum.FilterQuery{Addresses: []common.Address{scAddr}}) + blockBeforeFilterHash = *blockBeforeFilter.Hash + } else { + blockBeforeFilter, err := ethereumClient.BlockByNumber(ctx, nil) require.NoError(t, err) + blockBeforeFilterHash = blockBeforeFilter.Hash() + } - response, err = client.JSONRPCCall(network.URL, "eth_getFilterChanges", logFilterId) - require.NoError(t, err) - require.Nil(t, response.Error) - require.NotNil(t, response.Result) + response, err = client.JSONRPCCall(network.URL, "eth_newBlockFilter") + require.NoError(t, err) + require.Nil(t, response.Error) + require.NotNil(t, response.Result) - var logFilterChanges []ethTypes.Log - err = json.Unmarshal(response.Result, &logFilterChanges) - require.NoError(t, err) + var blockFilterId string + err = json.Unmarshal(response.Result, &blockFilterId) + require.NoError(t, err) + require.NotEmpty(t, blockFilterId) - assert.Equal(t, 10, len(logs)) - assert.Equal(t, 10, len(logFilterChanges)) - assert.True(t, reflect.DeepEqual(logs, logFilterChanges)) + // force a block to be generated sending a eth transfer tx + tx, err := createTX(ethereumClient, auth, toAddress, big.NewInt(1000)) + require.NoError(t, err) + err = operations.WaitTxToBeMined(ctx, ethereumClient, tx, operations.DefaultTimeoutTxToBeMined) + require.NoError(t, err) - // emit more logs - tx, err = sc.EmitLogs(auth) + var blockAfterFilterHash common.Hash + if network.Name == "Local L2" { + blockAfterFilter, err := zkEVMClient.BlockByNumber(ctx, nil) require.NoError(t, err) - err = operations.WaitTxToBeMined(ctx, ethereumClient, tx, operations.DefaultTimeoutTxToBeMined) + blockAfterFilterHash = *blockAfterFilter.Hash + } else { + blockAfterFilter, err := ethereumClient.BlockByNumber(ctx, nil) require.NoError(t, err) + blockAfterFilterHash = blockAfterFilter.Hash() + } - tx, err = sc.EmitLogs(auth) - require.NoError(t, err) - err = operations.WaitTxToBeMined(ctx, ethereumClient, tx, operations.DefaultTimeoutTxToBeMined) - require.NoError(t, err) + response, err = client.JSONRPCCall(network.URL, "eth_getFilterChanges", blockFilterId) + require.NoError(t, err) + require.Nil(t, response.Error) + require.NotNil(t, response.Result) - logs, err = ethereumClient.FilterLogs(ctx, ethereum.FilterQuery{Addresses: []common.Address{scAddr}}) - require.NoError(t, err) + var blockFilterChanges []common.Hash + err = json.Unmarshal(response.Result, &blockFilterChanges) + require.NoError(t, err) - response, err = client.JSONRPCCall(network.URL, "eth_getFilterChanges", logFilterId) - require.NoError(t, err) - require.Nil(t, response.Error) - require.NotNil(t, response.Result) + assert.NotEqual(t, blockBeforeFilterHash.String(), blockFilterChanges[0].String()) + assert.Equal(t, blockAfterFilterHash.String(), blockFilterChanges[len(blockFilterChanges)-1].String()) - err = json.Unmarshal(response.Result, &logFilterChanges) - require.NoError(t, err) + // test getFilterChanges for a logFilter ID + // create a SC to emit some logs + scAddr, scTx, sc, err := EmitLog.DeployEmitLog(auth, ethereumClient) + require.NoError(t, err) + err = operations.WaitTxToBeMined(ctx, ethereumClient, scTx, operations.DefaultTimeoutTxToBeMined) + require.NoError(t, err) - assert.Equal(t, 30, len(logs)) - assert.Equal(t, 20, len(logFilterChanges)) - } + response, err = client.JSONRPCCall(network.URL, "eth_newFilter", map[string]interface{}{ + "Addresses": []common.Address{scAddr}, + }) + require.NoError(t, err) + require.Nil(t, response.Error) + require.NotNil(t, response.Result) + + logFilterId := "" + err = json.Unmarshal(response.Result, &logFilterId) + require.NoError(t, err) + require.NotEmpty(t, logFilterId) + + // emit logs + tx, err = sc.EmitLogs(auth) + require.NoError(t, err) + err = operations.WaitTxToBeMined(ctx, ethereumClient, tx, operations.DefaultTimeoutTxToBeMined) + require.NoError(t, err) + + logs, err := ethereumClient.FilterLogs(ctx, ethereum.FilterQuery{Addresses: []common.Address{scAddr}}) + require.NoError(t, err) + + response, err = client.JSONRPCCall(network.URL, "eth_getFilterChanges", logFilterId) + require.NoError(t, err) + require.Nil(t, response.Error) + require.NotNil(t, response.Result) + + var logFilterChanges []ethTypes.Log + err = json.Unmarshal(response.Result, &logFilterChanges) + require.NoError(t, err) + + assert.Equal(t, 10, len(logs)) + assert.Equal(t, 10, len(logFilterChanges)) + assert.True(t, reflect.DeepEqual(logs, logFilterChanges)) + + // emit more logs + tx, err = sc.EmitLogs(auth) + require.NoError(t, err) + err = operations.WaitTxToBeMined(ctx, ethereumClient, tx, operations.DefaultTimeoutTxToBeMined) + require.NoError(t, err) + + tx, err = sc.EmitLogs(auth) + require.NoError(t, err) + err = operations.WaitTxToBeMined(ctx, ethereumClient, tx, operations.DefaultTimeoutTxToBeMined) + require.NoError(t, err) + + logs, err = ethereumClient.FilterLogs(ctx, ethereum.FilterQuery{Addresses: []common.Address{scAddr}}) + require.NoError(t, err) + + response, err = client.JSONRPCCall(network.URL, "eth_getFilterChanges", logFilterId) + require.NoError(t, err) + require.Nil(t, response.Error) + require.NotNil(t, response.Result) + + err = json.Unmarshal(response.Result, &logFilterChanges) + require.NoError(t, err) + + assert.Equal(t, 30, len(logs)) + assert.Equal(t, 20, len(logFilterChanges)) } -*/ +} + func Test_Gas(t *testing.T) { if testing.Short() { t.Skip() @@ -315,253 +324,252 @@ func Test_Gas(t *testing.T) { } } -/* - func Test_Block(t *testing.T) { - if testing.Short() { - t.Skip() - } - ctx := context.Background() - setup() - defer teardown() - type rpcTx struct { - BlockHash string `json:"blockHash"` - BlockNumber string `json:"blockNumber"` - ChainID string `json:"chainId"` - From string `json:"from"` - Gas string `json:"gas"` - GasPrice string `json:"gasPrice"` - Hash string `json:"hash"` - Input string `json:"input"` - Nonce string `json:"nonce"` - PublicKey string `json:"publicKey"` - R string `json:"r"` - Raw string `json:"raw"` - S string `json:"s"` - To string `json:"to"` - TransactionIndex string `json:"transactionIndex"` - V string `json:"v"` - Value string `json:"value"` - } - - for _, network := range networks { - log.Infof("Network %s", network.Name) - ethereumClient, err := ethclient.Dial(network.URL) - zkEVMClient := client.NewClient(network.URL) - require.NoError(t, err) - auth, err := operations.GetAuth(fromPriKey, network.ChainID) - require.NoError(t, err) - - tx, err := createTX(ethereumClient, auth, toAddress, big.NewInt(1000)) - require.NoError(t, err) - // no block number yet... will wait - err = operations.WaitTxToBeMined(ctx, ethereumClient, tx, operations.DefaultTimeoutTxToBeMined) - require.NoError(t, err) - - receipt, err := ethereumClient.TransactionReceipt(ctx, tx.Hash()) - require.NoError(t, err) - require.Equal(t, receipt.TxHash, tx.Hash()) - require.Equal(t, receipt.Type, tx.Type()) - require.Equal(t, uint(0), receipt.TransactionIndex) - - if network.Name == "Local L2" { - block, err := zkEVMClient.BlockByNumber(ctx, receipt.BlockNumber) - require.NoError(t, err) - require.NotNil(t, block) - require.Equal(t, receipt.BlockNumber.Uint64(), uint64(block.Number)) - require.Equal(t, receipt.BlockHash.String(), block.Hash.String()) - - block, err = zkEVMClient.BlockByHash(ctx, receipt.BlockHash) - require.NoError(t, err) - require.NotNil(t, block) - require.Equal(t, receipt.BlockNumber.Uint64(), uint64(block.Number)) - require.Equal(t, receipt.BlockHash.String(), block.Hash.String()) - } else { - block, err := ethereumClient.BlockByNumber(ctx, receipt.BlockNumber) - require.NoError(t, err) - require.NotNil(t, block) - require.Equal(t, receipt.BlockNumber.Uint64(), block.NumberU64()) - require.Equal(t, receipt.BlockHash.String(), block.Hash().String()) - - block, err = ethereumClient.BlockByHash(ctx, receipt.BlockHash) - require.NoError(t, err) - require.NotNil(t, block) - require.Equal(t, receipt.BlockNumber.Uint64(), block.NumberU64()) - require.Equal(t, receipt.BlockHash.String(), block.Hash().String()) - } - - blockNumber, err := ethereumClient.BlockNumber(ctx) - require.NoError(t, err) - log.Infof("\nBlock num %d", blockNumber) - require.GreaterOrEqual(t, blockNumber, receipt.BlockNumber.Uint64()) - - nonExistentBlockNumber := big.NewInt(0).SetUint64(blockNumber + uint64(1000)) - _, err = ethereumClient.BlockByNumber(ctx, nonExistentBlockNumber) - require.Error(t, err) - - nonExistentBlockHash := common.HexToHash("0xFFFFFF") - _, err = ethereumClient.BlockByHash(ctx, nonExistentBlockHash) - require.Error(t, err) - - // its pending - response, err := client.JSONRPCCall(network.URL, "eth_getBlockTransactionCountByNumber", hexutil.EncodeBig(receipt.BlockNumber)) - require.NoError(t, err) - require.Nil(t, response.Error) - require.NotNil(t, response.Result) - - txCount := "" - err = json.Unmarshal(response.Result, &txCount) - require.NoError(t, err) - require.Equal(t, "0x1", txCount) - - // check if block number is correct - count, err := ethereumClient.TransactionCount(ctx, receipt.BlockHash) - require.NoError(t, err) - require.Equal(t, uint(1), count) +func Test_Block(t *testing.T) { + if testing.Short() { + t.Skip() + } + ctx := context.Background() + setup() + defer teardown() + type rpcTx struct { + BlockHash string `json:"blockHash"` + BlockNumber string `json:"blockNumber"` + ChainID string `json:"chainId"` + From string `json:"from"` + Gas string `json:"gas"` + GasPrice string `json:"gasPrice"` + Hash string `json:"hash"` + Input string `json:"input"` + Nonce string `json:"nonce"` + PublicKey string `json:"publicKey"` + R string `json:"r"` + Raw string `json:"raw"` + S string `json:"s"` + To string `json:"to"` + TransactionIndex string `json:"transactionIndex"` + V string `json:"v"` + Value string `json:"value"` + } - tx = nil - tx, err = ethereumClient.TransactionInBlock(ctx, receipt.BlockHash, receipt.TransactionIndex) - require.NoError(t, err) - require.Equal(t, receipt.TxHash, tx.Hash()) + for _, network := range networks { + log.Infof("Network %s", network.Name) + ethereumClient, err := ethclient.Dial(network.URL) + zkEVMClient := client.NewClient(network.URL) + require.NoError(t, err) + auth, err := operations.GetAuth(fromPriKey, network.ChainID) + require.NoError(t, err) + + tx, err := createTX(ethereumClient, auth, toAddress, big.NewInt(1000)) + require.NoError(t, err) + // no block number yet... will wait + err = operations.WaitTxToBeMined(ctx, ethereumClient, tx, operations.DefaultTimeoutTxToBeMined) + require.NoError(t, err) + + receipt, err := ethereumClient.TransactionReceipt(ctx, tx.Hash()) + require.NoError(t, err) + require.Equal(t, receipt.TxHash, tx.Hash()) + require.Equal(t, receipt.Type, tx.Type()) + require.Equal(t, uint(0), receipt.TransactionIndex) - raw, err := client.JSONRPCCall(network.URL, "eth_getTransactionByBlockNumberAndIndex", hexutil.EncodeBig(receipt.BlockNumber), "0x0") + if network.Name == "Local L2" { + block, err := zkEVMClient.BlockByNumber(ctx, receipt.BlockNumber) require.NoError(t, err) - require.Nil(t, raw.Error) - require.NotNil(t, raw.Result) + require.NotNil(t, block) + require.Equal(t, receipt.BlockNumber.Uint64(), uint64(block.Number)) + require.Equal(t, receipt.BlockHash.String(), block.Hash.String()) - var newTx rpcTx - err = json.Unmarshal(raw.Result, &newTx) + block, err = zkEVMClient.BlockByHash(ctx, receipt.BlockHash) require.NoError(t, err) - - raw, err = client.JSONRPCCall(network.URL, "eth_getTransactionByBlockNumberAndIndex", "0x123", "0x8659") + require.NotNil(t, block) + require.Equal(t, receipt.BlockNumber.Uint64(), uint64(block.Number)) + require.Equal(t, receipt.BlockHash.String(), block.Hash.String()) + } else { + block, err := ethereumClient.BlockByNumber(ctx, receipt.BlockNumber) require.NoError(t, err) - require.Nil(t, raw.Error) - require.NotNil(t, raw.Result) + require.NotNil(t, block) + require.Equal(t, receipt.BlockNumber.Uint64(), block.NumberU64()) + require.Equal(t, receipt.BlockHash.String(), block.Hash().String()) - var empty rpcTx - err = json.Unmarshal(raw.Result, &empty) + block, err = ethereumClient.BlockByHash(ctx, receipt.BlockHash) require.NoError(t, err) - - // Checks for empty, when the lookup fail we get an empty struct and no errors... - v := reflect.ValueOf(empty) - - for i := 0; i < v.NumField(); i++ { - require.Empty(t, v.Field(i).Interface()) - } - - // checks for successful query - require.Equal(t, hexutil.EncodeBig(receipt.BlockNumber), newTx.BlockNumber) - require.Equal(t, receipt.BlockHash.String(), newTx.BlockHash) - require.Equal(t, hexutil.EncodeUint64(tx.Nonce()), newTx.Nonce) - require.Equal(t, hexutil.EncodeBig(tx.ChainId()), newTx.ChainID) + require.NotNil(t, block) + require.Equal(t, receipt.BlockNumber.Uint64(), block.NumberU64()) + require.Equal(t, receipt.BlockHash.String(), block.Hash().String()) } - } - func Test_Transactions(t *testing.T) { - if testing.Short() { - t.Skip() + blockNumber, err := ethereumClient.BlockNumber(ctx) + require.NoError(t, err) + log.Infof("\nBlock num %d", blockNumber) + require.GreaterOrEqual(t, blockNumber, receipt.BlockNumber.Uint64()) + + nonExistentBlockNumber := big.NewInt(0).SetUint64(blockNumber + uint64(1000)) + _, err = ethereumClient.BlockByNumber(ctx, nonExistentBlockNumber) + require.Error(t, err) + + nonExistentBlockHash := common.HexToHash("0xFFFFFF") + _, err = ethereumClient.BlockByHash(ctx, nonExistentBlockHash) + require.Error(t, err) + + // its pending + response, err := client.JSONRPCCall(network.URL, "eth_getBlockTransactionCountByNumber", hexutil.EncodeBig(receipt.BlockNumber)) + require.NoError(t, err) + require.Nil(t, response.Error) + require.NotNil(t, response.Result) + + txCount := "" + err = json.Unmarshal(response.Result, &txCount) + require.NoError(t, err) + require.Equal(t, "0x1", txCount) + + // check if block number is correct + count, err := ethereumClient.TransactionCount(ctx, receipt.BlockHash) + require.NoError(t, err) + require.Equal(t, uint(1), count) + + tx = nil + tx, err = ethereumClient.TransactionInBlock(ctx, receipt.BlockHash, receipt.TransactionIndex) + require.NoError(t, err) + require.Equal(t, receipt.TxHash, tx.Hash()) + + raw, err := client.JSONRPCCall(network.URL, "eth_getTransactionByBlockNumberAndIndex", hexutil.EncodeBig(receipt.BlockNumber), "0x0") + require.NoError(t, err) + require.Nil(t, raw.Error) + require.NotNil(t, raw.Result) + + var newTx rpcTx + err = json.Unmarshal(raw.Result, &newTx) + require.NoError(t, err) + + raw, err = client.JSONRPCCall(network.URL, "eth_getTransactionByBlockNumberAndIndex", "0x123", "0x8659") + require.NoError(t, err) + require.Nil(t, raw.Error) + require.NotNil(t, raw.Result) + + var empty rpcTx + err = json.Unmarshal(raw.Result, &empty) + require.NoError(t, err) + + // Checks for empty, when the lookup fail we get an empty struct and no errors... + v := reflect.ValueOf(empty) + + for i := 0; i < v.NumField(); i++ { + require.Empty(t, v.Field(i).Interface()) } - ctx := context.Background() - setup() - defer teardown() - for _, network := range networks { - log.Infof("Network %s", network.Name) - ethClient, err := ethclient.Dial(network.URL) - require.NoError(t, err) - auth, err := operations.GetAuth(fromPriKey, network.ChainID) - require.NoError(t, err) - - // Test Case: Successful transfer - tx, err := createTX(ethClient, auth, toAddress, big.NewInt(100000)) - require.NoError(t, err) - err = operations.WaitTxToBeMined(ctx, ethClient, tx, operations.DefaultTimeoutTxToBeMined) - require.NoError(t, err) - - // Test Case: get transaction by block number and index - receipt, err := ethClient.TransactionReceipt(ctx, tx.Hash()) - require.NoError(t, err) - require.NotNil(t, receipt) - res, err := client.JSONRPCCall(network.URL, "eth_getTransactionByBlockNumberAndIndex", hex.EncodeBig(receipt.BlockNumber), hex.EncodeUint64(uint64(receipt.TransactionIndex))) - require.NoError(t, err) - require.Nil(t, res.Error) - require.NotNil(t, res.Result) - var txByBlockNumberAndIndex *types.Transaction - err = json.Unmarshal(res.Result, &txByBlockNumberAndIndex) - require.NoError(t, err) - - require.Equal(t, tx.Hash().String(), txByBlockNumberAndIndex.Hash.String()) - - // Test Case: get transaction by block hash and index - receipt, err = ethClient.TransactionReceipt(ctx, tx.Hash()) - require.NoError(t, err) - require.NotNil(t, receipt) - txByBlockHashAndIndex, err := ethClient.TransactionInBlock(ctx, receipt.BlockHash, receipt.TransactionIndex) - require.NoError(t, err) - require.Equal(t, tx.Hash().String(), txByBlockHashAndIndex.Hash().String()) - - // Setup for test cases - nonce, err := ethClient.NonceAt(context.Background(), auth.From, nil) - require.NoError(t, err) - gasLimit, err := ethClient.EstimateGas(context.Background(), ethereum.CallMsg{From: auth.From, To: &toAddress, Value: big.NewInt(10000)}) - require.NoError(t, err) - - gasPrice, err := ethClient.SuggestGasPrice(context.Background()) - require.NoError(t, err) + // checks for successful query + require.Equal(t, hexutil.EncodeBig(receipt.BlockNumber), newTx.BlockNumber) + require.Equal(t, receipt.BlockHash.String(), newTx.BlockHash) + require.Equal(t, hexutil.EncodeUint64(tx.Nonce()), newTx.Nonce) + require.Equal(t, hexutil.EncodeBig(tx.ChainId()), newTx.ChainID) + } +} - // Test Case: TX with invalid nonce - tx = ethTypes.NewTransaction(nonce-1, // Nonce will be lower than the current getNonceAt() - toAddress, big.NewInt(100), gasLimit, gasPrice, nil) - signedTx, err := auth.Signer(auth.From, tx) - require.NoError(t, err) +func Test_Transactions(t *testing.T) { + if testing.Short() { + t.Skip() + } + ctx := context.Background() + setup() + defer teardown() + for _, network := range networks { + log.Infof("Network %s", network.Name) + ethClient, err := ethclient.Dial(network.URL) + require.NoError(t, err) + auth, err := operations.GetAuth(fromPriKey, network.ChainID) + require.NoError(t, err) + + // Test Case: Successful transfer + tx, err := createTX(ethClient, auth, toAddress, big.NewInt(100000)) + require.NoError(t, err) + err = operations.WaitTxToBeMined(ctx, ethClient, tx, operations.DefaultTimeoutTxToBeMined) + require.NoError(t, err) + + // Test Case: get transaction by block number and index + receipt, err := ethClient.TransactionReceipt(ctx, tx.Hash()) + require.NoError(t, err) + require.NotNil(t, receipt) + res, err := client.JSONRPCCall(network.URL, "eth_getTransactionByBlockNumberAndIndex", hex.EncodeBig(receipt.BlockNumber), hex.EncodeUint64(uint64(receipt.TransactionIndex))) + require.NoError(t, err) + require.Nil(t, res.Error) + require.NotNil(t, res.Result) + var txByBlockNumberAndIndex *types.Transaction + err = json.Unmarshal(res.Result, &txByBlockNumberAndIndex) + require.NoError(t, err) + + require.Equal(t, tx.Hash().String(), txByBlockNumberAndIndex.Hash.String()) + + // Test Case: get transaction by block hash and index + receipt, err = ethClient.TransactionReceipt(ctx, tx.Hash()) + require.NoError(t, err) + require.NotNil(t, receipt) + txByBlockHashAndIndex, err := ethClient.TransactionInBlock(ctx, receipt.BlockHash, receipt.TransactionIndex) + require.NoError(t, err) + require.Equal(t, tx.Hash().String(), txByBlockHashAndIndex.Hash().String()) + + // Setup for test cases + nonce, err := ethClient.NonceAt(context.Background(), auth.From, nil) + require.NoError(t, err) + + gasLimit, err := ethClient.EstimateGas(context.Background(), ethereum.CallMsg{From: auth.From, To: &toAddress, Value: big.NewInt(10000)}) + require.NoError(t, err) + + gasPrice, err := ethClient.SuggestGasPrice(context.Background()) + require.NoError(t, err) + + // Test Case: TX with invalid nonce + tx = ethTypes.NewTransaction(nonce-1, // Nonce will be lower than the current getNonceAt() + toAddress, big.NewInt(100), gasLimit, gasPrice, nil) + signedTx, err := auth.Signer(auth.From, tx) + require.NoError(t, err) + + log.Infof("Sending Tx %v Nonce (invalid) %v", signedTx.Hash(), signedTx.Nonce()) + err = ethClient.SendTransaction(context.Background(), signedTx) + require.ErrorContains(t, err, "nonce too low") + // End Test Case + + // Test Case: TX with no signature (which would fail the EIP-155) + invalidTx := ethTypes.NewTx(ðTypes.LegacyTx{ + Nonce: nonce, + Value: big.NewInt(10000), + Gas: gasLimit, + GasPrice: gasPrice, + Data: nil, + }) + err = ethClient.SendTransaction(context.Background(), invalidTx) + require.Error(t, err) + // End Test Case - log.Infof("Sending Tx %v Nonce (invalid) %v", signedTx.Hash(), signedTx.Nonce()) - err = ethClient.SendTransaction(context.Background(), signedTx) - require.ErrorContains(t, err, "nonce too low") - // End Test Case - - // Test Case: TX with no signature (which would fail the EIP-155) - invalidTx := ethTypes.NewTx(ðTypes.LegacyTx{ - Nonce: nonce, - Value: big.NewInt(10000), - Gas: gasLimit, - GasPrice: gasPrice, - Data: nil, - }) - err = ethClient.SendTransaction(context.Background(), invalidTx) - require.Error(t, err) - // End Test Case - - // Test Case: TX with amount being higher than balance - balance, err := ethClient.BalanceAt(context.Background(), auth.From, nil) - require.NoError(t, err) + // Test Case: TX with amount being higher than balance + balance, err := ethClient.BalanceAt(context.Background(), auth.From, nil) + require.NoError(t, err) - nonce, err = ethClient.NonceAt(context.Background(), auth.From, nil) - require.NoError(t, err) + nonce, err = ethClient.NonceAt(context.Background(), auth.From, nil) + require.NoError(t, err) - log.Infof("Balance: %d", balance) + log.Infof("Balance: %d", balance) - tx = ethTypes.NewTransaction(nonce, toAddress, big.NewInt(0).Add(balance, big.NewInt(10)), gasLimit, gasPrice, nil) - signedTx, err = auth.Signer(auth.From, tx) - require.NoError(t, err) + tx = ethTypes.NewTransaction(nonce, toAddress, big.NewInt(0).Add(balance, big.NewInt(10)), gasLimit, gasPrice, nil) + signedTx, err = auth.Signer(auth.From, tx) + require.NoError(t, err) - log.Infof("Sending Tx %v Nonce %v", signedTx.Hash(), signedTx.Nonce()) - err = ethClient.SendTransaction(context.Background(), signedTx) - require.ErrorContains(t, err, pool.ErrInsufficientFunds.Error()) + log.Infof("Sending Tx %v Nonce %v", signedTx.Hash(), signedTx.Nonce()) + err = ethClient.SendTransaction(context.Background(), signedTx) + require.ErrorContains(t, err, pool.ErrInsufficientFunds.Error()) - // no contract code at given address test - // deploy contract with not enough gas for storage, just execution - address := common.HexToAddress("0xDEADBEEF596a836C9063a7EE35dA94DDA3b57B62") - instance, err := Double.NewDouble(address, ethClient) - require.NoError(t, err) + // no contract code at given address test + // deploy contract with not enough gas for storage, just execution + address := common.HexToAddress("0xDEADBEEF596a836C9063a7EE35dA94DDA3b57B62") + instance, err := Double.NewDouble(address, ethClient) + require.NoError(t, err) - callOpts := &bind.CallOpts{Pending: false} + callOpts := &bind.CallOpts{Pending: false} - payload := big.NewInt(5) - _, err = instance.Double(callOpts, payload) - require.ErrorContains(t, err, "no contract code at given address") - } + payload := big.NewInt(5) + _, err = instance.Double(callOpts, payload) + require.ErrorContains(t, err, "no contract code at given address") } -*/ +} + func Test_OOCErrors(t *testing.T) { if testing.Short() { t.Skip() @@ -668,7 +676,6 @@ func Test_OOCErrors(t *testing.T) { } } -/* func Test_EstimateCounters(t *testing.T) { if testing.Short() { t.Skip() @@ -789,4 +796,3 @@ func Test_EstimateCounters(t *testing.T) { }) } } -*/ From a6ac57ace49cbc4f9f9ff83bd8c5753a4770e48f Mon Sep 17 00:00:00 2001 From: chengzhinei Date: Tue, 7 May 2024 16:56:09 +0800 Subject: [PATCH 11/18] fmt code --- state/transaction.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/state/transaction.go b/state/transaction.go index 844b67f8db..301ce6602a 100644 --- a/state/transaction.go +++ b/state/transaction.go @@ -4,7 +4,6 @@ import ( "context" "errors" "fmt" - "github.com/ethereum/go-ethereum/params" "math/big" "time" @@ -16,6 +15,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/trie" "github.com/google/uuid" "github.com/jackc/pgx/v4" From 6a46ec5715ad7f8750dd932eea80a13d210522e1 Mon Sep 17 00:00:00 2001 From: chengzhinei Date: Tue, 7 May 2024 16:57:00 +0800 Subject: [PATCH 12/18] fmt code --- state/transaction.go | 1 - 1 file changed, 1 deletion(-) diff --git a/state/transaction.go b/state/transaction.go index 301ce6602a..59e237d3a9 100644 --- a/state/transaction.go +++ b/state/transaction.go @@ -706,7 +706,6 @@ func CheckSupersetBatchTransactions(existingTxHashes []common.Hash, processedTxs // EstimateGas for a transaction func (s *State) EstimateGas(transaction *types.Transaction, senderAddress common.Address, l2BlockNumber *uint64, dbTx pgx.Tx) (uint64, []byte, error) { - fmt.Printf("L2 EstimateGas\n") const ethTransferGas = 21000 ctx := context.Background() From 5cf08d58d3acb24c6397117b730d7e888ec9909c Mon Sep 17 00:00:00 2001 From: chengzhinei Date: Sat, 11 May 2024 10:29:41 +0800 Subject: [PATCH 13/18] add gas refund --- state/transaction.go | 85 +++++++++++++++++++++----------------------- 1 file changed, 41 insertions(+), 44 deletions(-) diff --git a/state/transaction.go b/state/transaction.go index 59e237d3a9..2c4df41f94 100644 --- a/state/transaction.go +++ b/state/transaction.go @@ -824,12 +824,12 @@ func (s *State) EstimateGas(transaction *types.Transaction, senderAddress common // can return immediately. log.Debugf("Estimate gas. Trying to execute TX with %v gas", highEnd) var failed, reverted bool - var gasUsed uint64 + var gasUsed, gasRefund uint64 var returnValue []byte if forkID < FORKID_ETROG { - failed, reverted, gasUsed, returnValue, err = s.internalTestGasEstimationTransactionV1(ctx, batch, l2Block, latestL2BlockNumber, transaction, forkID, senderAddress, highEnd, nonce, false) + failed, reverted, gasUsed, gasRefund, returnValue, err = s.internalTestGasEstimationTransactionV1(ctx, batch, l2Block, latestL2BlockNumber, transaction, forkID, senderAddress, highEnd, nonce, false) } else { - failed, reverted, gasUsed, returnValue, err = s.internalTestGasEstimationTransactionV2(ctx, batch, l2Block, latestL2BlockNumber, transaction, forkID, senderAddress, highEnd, nonce, false) + failed, reverted, gasUsed, gasRefund, returnValue, err = s.internalTestGasEstimationTransactionV2(ctx, batch, l2Block, latestL2BlockNumber, transaction, forkID, senderAddress, highEnd, nonce, false) } if failed { @@ -852,28 +852,24 @@ func (s *State) EstimateGas(transaction *types.Transaction, senderAddress common lowEnd = gasUsed } - if transaction.Gas() == 0 { - optimisticGasLimit := (gasUsed + params.CallStipend) * 64 / 63 // nolint:gomnd - if optimisticGasLimit < highEnd { - if forkID < FORKID_ETROG { - failed, _, _, _, err = s.internalTestGasEstimationTransactionV1(ctx, batch, l2Block, latestL2BlockNumber, transaction, forkID, senderAddress, optimisticGasLimit, nonce, false) - } else { - failed, _, _, _, err = s.internalTestGasEstimationTransactionV2(ctx, batch, l2Block, latestL2BlockNumber, transaction, forkID, senderAddress, optimisticGasLimit, nonce, false) - } - if err != nil { - // This should not happen under normal conditions since if we make it this far the - // transaction had run without error at least once before. - log.Error("Execution error in estimate gas", "err", err) - return 0, nil, err - } - if failed { - lowEnd = optimisticGasLimit - } else { - highEnd = optimisticGasLimit - } + optimisticGasLimit := (gasUsed + gasRefund + params.CallStipend) * 64 / 63 // nolint:gomnd + if optimisticGasLimit < highEnd { + if forkID < FORKID_ETROG { + failed, _, _, _, _, err = s.internalTestGasEstimationTransactionV1(ctx, batch, l2Block, latestL2BlockNumber, transaction, forkID, senderAddress, optimisticGasLimit, nonce, false) + } else { + failed, _, _, _, _, err = s.internalTestGasEstimationTransactionV2(ctx, batch, l2Block, latestL2BlockNumber, transaction, forkID, senderAddress, optimisticGasLimit, nonce, false) + } + if err != nil { + // This should not happen under normal conditions since if we make it this far the + // transaction had run without error at least once before. + log.Error("Execution error in estimate gas", "err", err) + return 0, nil, err + } + if failed { + lowEnd = optimisticGasLimit + } else { + highEnd = optimisticGasLimit } - } else { - highEnd = transaction.Gas() } // Start the binary search for the lowest possible gas price @@ -889,9 +885,9 @@ func (s *State) EstimateGas(transaction *types.Transaction, senderAddress common log.Debugf("Estimate gas. Trying to execute TX with %v gas", mid) if forkID < FORKID_ETROG { - failed, reverted, _, _, err = s.internalTestGasEstimationTransactionV1(ctx, batch, l2Block, latestL2BlockNumber, transaction, forkID, senderAddress, mid, nonce, true) + failed, reverted, _, _, _, err = s.internalTestGasEstimationTransactionV1(ctx, batch, l2Block, latestL2BlockNumber, transaction, forkID, senderAddress, mid, nonce, true) } else { - failed, reverted, _, _, err = s.internalTestGasEstimationTransactionV2(ctx, batch, l2Block, latestL2BlockNumber, transaction, forkID, senderAddress, mid, nonce, true) + failed, reverted, _, _, _, err = s.internalTestGasEstimationTransactionV2(ctx, batch, l2Block, latestL2BlockNumber, transaction, forkID, senderAddress, mid, nonce, true) } executionTime := time.Since(txExecutionStart) totalExecutionTime += executionTime @@ -928,7 +924,7 @@ func (s *State) EstimateGas(transaction *types.Transaction, senderAddress common // before ETROG func (s *State) internalTestGasEstimationTransactionV1(ctx context.Context, batch *Batch, l2Block *L2Block, latestL2BlockNumber uint64, transaction *types.Transaction, forkID uint64, senderAddress common.Address, - gas uint64, nonce uint64, shouldOmitErr bool) (failed, reverted bool, gasUsed uint64, returnValue []byte, err error) { + gas uint64, nonce uint64, shouldOmitErr bool) (failed, reverted bool, gasUsed, gasRefund uint64, returnValue []byte, err error) { timestamp := l2Block.Time() if l2Block.NumberU64() == latestL2BlockNumber { timestamp = uint64(time.Now().Unix()) @@ -946,7 +942,7 @@ func (s *State) internalTestGasEstimationTransactionV1(ctx context.Context, batc batchL2Data, err := EncodeUnsignedTransaction(*tx, s.cfg.ChainID, &nonce, forkID) if err != nil { log.Errorf("error encoding unsigned transaction ", err) - return false, false, gasUsed, nil, err + return false, false, gasUsed, gasRefund, nil, err } // Create a batch to be sent to the executor @@ -985,14 +981,15 @@ func (s *State) internalTestGasEstimationTransactionV1(ctx context.Context, batc log.Debugf("executor time: %vms", time.Since(txExecutionOnExecutorTime).Milliseconds()) if err != nil { log.Errorf("error estimating gas: %v", err) - return false, false, gasUsed, nil, err + return false, false, gasUsed, gasRefund, nil, err } if processBatchResponse.Error != executor.ExecutorError_EXECUTOR_ERROR_NO_ERROR { err = executor.ExecutorErr(processBatchResponse.Error) s.eventLog.LogExecutorError(ctx, processBatchResponse.Error, processBatchRequestV1) - return false, false, gasUsed, nil, err + return false, false, gasUsed, gasRefund, nil, err } gasUsed = processBatchResponse.Responses[0].GasUsed + gasRefund = processBatchResponse.Responses[0].GasRefunded txResponse := processBatchResponse.Responses[0] // Check if an out of gas error happened during EVM execution @@ -1003,20 +1000,20 @@ func (s *State) internalTestGasEstimationTransactionV1(ctx context.Context, batc // Specifying the transaction failed, but not providing an error // is an indication that a valid error occurred due to low gas, // which will increase the lower bound for the search - return true, false, gasUsed, nil, nil + return true, false, gasUsed, gasRefund, nil, nil } if isEVMRevertError(err) { // The EVM reverted during execution, attempt to extract the // error message and return it returnValue := txResponse.ReturnValue - return true, true, gasUsed, returnValue, ConstructErrorFromRevert(err, returnValue) + return true, true, gasUsed, gasRefund, returnValue, ConstructErrorFromRevert(err, returnValue) } - return true, false, gasUsed, nil, err + return true, false, gasUsed, gasRefund, nil, err } - return false, false, gasUsed, nil, nil + return false, false, gasUsed, gasRefund, nil, nil } // internalTestGasEstimationTransactionV2 is used by the EstimateGas to test the tx execution @@ -1024,7 +1021,7 @@ func (s *State) internalTestGasEstimationTransactionV1(ctx context.Context, batc // after ETROG func (s *State) internalTestGasEstimationTransactionV2(ctx context.Context, batch *Batch, l2Block *L2Block, latestL2BlockNumber uint64, transaction *types.Transaction, forkID uint64, senderAddress common.Address, - gas uint64, nonce uint64, shouldOmitErr bool) (failed, reverted bool, gasUsed uint64, returnValue []byte, err error) { + gas uint64, nonce uint64, shouldOmitErr bool) (failed, reverted bool, gasUsed, gasRefund uint64, returnValue []byte, err error) { deltaTimestamp := uint32(uint64(time.Now().Unix()) - l2Block.Time()) transactions := s.BuildChangeL2Block(deltaTimestamp, uint32(0)) @@ -1040,7 +1037,7 @@ func (s *State) internalTestGasEstimationTransactionV2(ctx context.Context, batc batchL2Data, err := EncodeUnsignedTransaction(*tx, s.cfg.ChainID, &nonce, forkID) if err != nil { log.Errorf("error encoding unsigned transaction ", err) - return false, false, gasUsed, nil, err + return false, false, gasUsed, gasRefund, nil, err } transactions = append(transactions, batchL2Data...) @@ -1085,21 +1082,21 @@ func (s *State) internalTestGasEstimationTransactionV2(ctx context.Context, batc log.Infof("executor time: %vms", time.Since(txExecutionOnExecutorTime).Milliseconds()) if err != nil { log.Errorf("error estimating gas: %v", err) - return false, false, gasUsed, nil, err + return false, false, gasUsed, gasRefund, nil, err } if processBatchResponseV2.Error != executor.ExecutorError_EXECUTOR_ERROR_NO_ERROR { err = executor.ExecutorErr(processBatchResponseV2.Error) s.eventLog.LogExecutorErrorV2(ctx, processBatchResponseV2.Error, processBatchRequestV2) - return false, false, gasUsed, nil, err + return false, false, gasUsed, gasRefund, nil, err } if processBatchResponseV2.ErrorRom != executor.RomError_ROM_ERROR_NO_ERROR { err = executor.RomErr(processBatchResponseV2.ErrorRom) - return false, false, gasUsed, nil, err + return false, false, gasUsed, gasRefund, nil, err } gasUsed = processBatchResponseV2.BlockResponses[0].GasUsed - txResponse := processBatchResponseV2.BlockResponses[0].Responses[0] + gasRefund = txResponse.GasRefunded // Check if an out of gas error happened during EVM execution if txResponse.Error != executor.RomError_ROM_ERROR_NO_ERROR { err := executor.RomErr(txResponse.Error) @@ -1108,20 +1105,20 @@ func (s *State) internalTestGasEstimationTransactionV2(ctx context.Context, batc // Specifying the transaction failed, but not providing an error // is an indication that a valid error occurred due to low gas, // which will increase the lower bound for the search - return true, false, gasUsed, nil, nil + return true, false, gasUsed, gasRefund, nil, nil } if isEVMRevertError(err) { // The EVM reverted during execution, attempt to extract the // error message and return it returnValue := txResponse.ReturnValue - return true, true, gasUsed, returnValue, ConstructErrorFromRevert(err, returnValue) + return true, true, gasUsed, gasRefund, returnValue, ConstructErrorFromRevert(err, returnValue) } - return true, false, gasUsed, nil, err + return true, false, gasUsed, gasRefund, nil, err } - return false, false, gasUsed, nil, nil + return false, false, gasUsed, gasRefund, nil, nil } // Checks if executor level valid gas errors occurred From 8ce1cec4acaa482282a9f8f13c810a56b9b9c0fb Mon Sep 17 00:00:00 2001 From: chengzhinei Date: Mon, 13 May 2024 10:13:22 +0800 Subject: [PATCH 14/18] test fix ut --- test/e2e/jsonrpc1_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/jsonrpc1_test.go b/test/e2e/jsonrpc1_test.go index 5c2cd1cd7f..7464449db7 100644 --- a/test/e2e/jsonrpc1_test.go +++ b/test/e2e/jsonrpc1_test.go @@ -636,7 +636,7 @@ func Test_OOCErrors(t *testing.T) { }) return err.Error() }, - expectedError: "not enough poseidon counters to continue the execution", + expectedError: "gas limit intrinsic error", }, { name: "estimate gas OOG", From 0fc9b93d04d58ddcfcba087a908c8632731b65fb Mon Sep 17 00:00:00 2001 From: chengzhinei Date: Mon, 13 May 2024 10:37:40 +0800 Subject: [PATCH 15/18] add benchmark --- test/e2e/jsonrpc1_test.go | 61 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/test/e2e/jsonrpc1_test.go b/test/e2e/jsonrpc1_test.go index 7464449db7..53a458712f 100644 --- a/test/e2e/jsonrpc1_test.go +++ b/test/e2e/jsonrpc1_test.go @@ -6,6 +6,7 @@ import ( "math/big" "reflect" "testing" + "time" "github.com/0xPolygonHermez/zkevm-node/hex" "github.com/0xPolygonHermez/zkevm-node/jsonrpc/client" @@ -796,3 +797,63 @@ func Test_EstimateCounters(t *testing.T) { }) } } + +func Test_Gas_Bench2(t *testing.T) { + if testing.Short() { + t.Skip() + } + ctx := context.Background() + setup() + defer teardown() + ethClient, err := ethclient.Dial(operations.DefaultL2NetworkURL) + require.NoError(t, err) + auth, err := operations.GetAuth(operations.DefaultSequencerPrivateKey, operations.DefaultL2ChainID) + require.NoError(t, err) + + type testCase struct { + name string + execute func(*testing.T, context.Context, *triggerErrors.TriggerErrors, *ethclient.Client, bind.TransactOpts) string + expectedError string + } + + testCases := []testCase{ + { + name: "estimate gas with given gas limit", + execute: func(t *testing.T, ctx context.Context, sc *triggerErrors.TriggerErrors, c *ethclient.Client, a bind.TransactOpts) string { + a.GasLimit = 30000000 + a.NoSend = true + tx, err := sc.OutOfCountersPoseidon(&a) + require.NoError(t, err) + + t0 := time.Now() + _, err = c.EstimateGas(ctx, ethereum.CallMsg{ + From: a.From, + To: tx.To(), + Gas: tx.Gas(), + GasPrice: tx.GasPrice(), + Value: tx.Value(), + Data: tx.Data(), + }) + log.Infof("EstimateGas time: %v", time.Since(t0)) + if err != nil { + return err.Error() + } + return "" + }, + expectedError: "", + }, + } + + // deploy triggerErrors SC + _, tx, sc, err := triggerErrors.DeployTriggerErrors(auth, ethClient) + require.NoError(t, err) + + err = operations.WaitTxToBeMined(ctx, ethClient, tx, operations.DefaultTimeoutTxToBeMined) + require.NoError(t, err) + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + testCase.execute(t, context.Background(), sc, ethClient, *auth) + }) + } +} From de55e5ea45229d3a5bfda2ef16b80c3417ff9d9f Mon Sep 17 00:00:00 2001 From: chengzhinei Date: Tue, 21 May 2024 16:38:34 +0800 Subject: [PATCH 16/18] fix ut --- test/e2e/jsonrpc1_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/jsonrpc1_test.go b/test/e2e/jsonrpc1_test.go index 53a458712f..182af71701 100644 --- a/test/e2e/jsonrpc1_test.go +++ b/test/e2e/jsonrpc1_test.go @@ -807,7 +807,7 @@ func Test_Gas_Bench2(t *testing.T) { defer teardown() ethClient, err := ethclient.Dial(operations.DefaultL2NetworkURL) require.NoError(t, err) - auth, err := operations.GetAuth(operations.DefaultSequencerPrivateKey, operations.DefaultL2ChainID) + auth, err := operations.GetAuth(fromPriKey, operations.DefaultL2ChainID) require.NoError(t, err) type testCase struct { From 0e31c5688c96d8208c35f29b7541aa857a2b486d Mon Sep 17 00:00:00 2001 From: chengzhinei Date: Tue, 28 May 2024 11:41:28 +0800 Subject: [PATCH 17/18] merge from zkevm --- state/test/forkid_common/common.go | 2 +- state/transaction.go | 129 +++++++++++++++++------------ test/e2e/jsonrpc1_test.go | 2 +- 3 files changed, 80 insertions(+), 53 deletions(-) diff --git a/state/test/forkid_common/common.go b/state/test/forkid_common/common.go index 478b7e0222..2275276cd0 100644 --- a/state/test/forkid_common/common.go +++ b/state/test/forkid_common/common.go @@ -53,7 +53,7 @@ func InitTestState(stateCfg state.Config) *state.State { panic(err) } - zkProverURI := testutils.GetEnv("ZKPROVER_URI", "zkevm-prover") + zkProverURI := testutils.GetEnv("ZKPROVER_URI", "localhost") executorServerConfig := executor.Config{URI: fmt.Sprintf("%s:50071", zkProverURI), MaxGRPCMessageSize: 100000000} ExecutorClient, executorClientConn, executorCancel = executor.NewExecutorClient(ctx, executorServerConfig) diff --git a/state/transaction.go b/state/transaction.go index 2c4df41f94..c689e42636 100644 --- a/state/transaction.go +++ b/state/transaction.go @@ -23,6 +23,13 @@ import ( "google.golang.org/grpc/status" ) +type testGasEstimationResult struct { + failed, reverted, ooc bool + gasUsed, gasRefund uint64 + returnValue []byte + executionError error +} + // GetSender gets the sender from the transaction's signature func GetSender(tx types.Transaction) (common.Address, error) { signer := types.NewEIP155Signer(tx.ChainId()) @@ -823,18 +830,22 @@ func (s *State) EstimateGas(transaction *types.Transaction, senderAddress common // Check if the highEnd is a good value to make the transaction pass, if it fails we // can return immediately. log.Debugf("Estimate gas. Trying to execute TX with %v gas", highEnd) - var failed, reverted bool - var gasUsed, gasRefund uint64 - var returnValue []byte + var estimationResult *testGasEstimationResult if forkID < FORKID_ETROG { - failed, reverted, gasUsed, gasRefund, returnValue, err = s.internalTestGasEstimationTransactionV1(ctx, batch, l2Block, latestL2BlockNumber, transaction, forkID, senderAddress, highEnd, nonce, false) + estimationResult, err = s.internalTestGasEstimationTransactionV1(ctx, batch, l2Block, latestL2BlockNumber, transaction, forkID, senderAddress, highEnd, nonce, false) } else { - failed, reverted, gasUsed, gasRefund, returnValue, err = s.internalTestGasEstimationTransactionV2(ctx, batch, l2Block, latestL2BlockNumber, transaction, forkID, senderAddress, highEnd, nonce, false) + estimationResult, err = s.internalTestGasEstimationTransactionV2(ctx, batch, l2Block, latestL2BlockNumber, transaction, forkID, senderAddress, highEnd, nonce, false) + } + if err != nil { + return 0, nil, err } + if estimationResult.failed { + if estimationResult.reverted { + return 0, estimationResult.returnValue, estimationResult.executionError + } - if failed { - if reverted { - return 0, returnValue, err + if estimationResult.ooc { + return 0, nil, estimationResult.executionError } // The transaction shouldn't fail, for whatever reason, at highEnd @@ -848,16 +859,16 @@ func (s *State) EstimateGas(transaction *types.Transaction, senderAddress common internalGasTime := t6.Sub(t5) // sets - if lowEnd < gasUsed { - lowEnd = gasUsed + if lowEnd < estimationResult.gasUsed { + lowEnd = estimationResult.gasUsed } - optimisticGasLimit := (gasUsed + gasRefund + params.CallStipend) * 64 / 63 // nolint:gomnd + optimisticGasLimit := (estimationResult.gasUsed + estimationResult.gasRefund + params.CallStipend) * 64 / 63 // nolint:gomnd if optimisticGasLimit < highEnd { if forkID < FORKID_ETROG { - failed, _, _, _, _, err = s.internalTestGasEstimationTransactionV1(ctx, batch, l2Block, latestL2BlockNumber, transaction, forkID, senderAddress, optimisticGasLimit, nonce, false) + estimationResult, err = s.internalTestGasEstimationTransactionV1(ctx, batch, l2Block, latestL2BlockNumber, transaction, forkID, senderAddress, optimisticGasLimit, nonce, false) } else { - failed, _, _, _, _, err = s.internalTestGasEstimationTransactionV2(ctx, batch, l2Block, latestL2BlockNumber, transaction, forkID, senderAddress, optimisticGasLimit, nonce, false) + estimationResult, err = s.internalTestGasEstimationTransactionV2(ctx, batch, l2Block, latestL2BlockNumber, transaction, forkID, senderAddress, optimisticGasLimit, nonce, false) } if err != nil { // This should not happen under normal conditions since if we make it this far the @@ -865,7 +876,7 @@ func (s *State) EstimateGas(transaction *types.Transaction, senderAddress common log.Error("Execution error in estimate gas", "err", err) return 0, nil, err } - if failed { + if estimationResult.failed { lowEnd = optimisticGasLimit } else { highEnd = optimisticGasLimit @@ -885,20 +896,20 @@ func (s *State) EstimateGas(transaction *types.Transaction, senderAddress common log.Debugf("Estimate gas. Trying to execute TX with %v gas", mid) if forkID < FORKID_ETROG { - failed, reverted, _, _, _, err = s.internalTestGasEstimationTransactionV1(ctx, batch, l2Block, latestL2BlockNumber, transaction, forkID, senderAddress, mid, nonce, true) + estimationResult, err = s.internalTestGasEstimationTransactionV1(ctx, batch, l2Block, latestL2BlockNumber, transaction, forkID, senderAddress, mid, nonce, true) } else { - failed, reverted, _, _, _, err = s.internalTestGasEstimationTransactionV2(ctx, batch, l2Block, latestL2BlockNumber, transaction, forkID, senderAddress, mid, nonce, true) + estimationResult, err = s.internalTestGasEstimationTransactionV2(ctx, batch, l2Block, latestL2BlockNumber, transaction, forkID, senderAddress, mid, nonce, true) } executionTime := time.Since(txExecutionStart) totalExecutionTime += executionTime txExecutions = append(txExecutions, executionTime) - if err != nil && !reverted { + if err != nil && !estimationResult.reverted { // Reverts are ignored in the binary search, but are checked later on // during the execution for the optimal gas limit found return 0, nil, err } - if failed { + if estimationResult.failed { // If the transaction failed => increase the gas lowEnd = mid + 1 } else { @@ -924,7 +935,7 @@ func (s *State) EstimateGas(transaction *types.Transaction, senderAddress common // before ETROG func (s *State) internalTestGasEstimationTransactionV1(ctx context.Context, batch *Batch, l2Block *L2Block, latestL2BlockNumber uint64, transaction *types.Transaction, forkID uint64, senderAddress common.Address, - gas uint64, nonce uint64, shouldOmitErr bool) (failed, reverted bool, gasUsed, gasRefund uint64, returnValue []byte, err error) { + gas uint64, nonce uint64, shouldOmitErr bool) (*testGasEstimationResult, err error) { timestamp := l2Block.Time() if l2Block.NumberU64() == latestL2BlockNumber { timestamp = uint64(time.Now().Unix()) @@ -942,7 +953,7 @@ func (s *State) internalTestGasEstimationTransactionV1(ctx context.Context, batc batchL2Data, err := EncodeUnsignedTransaction(*tx, s.cfg.ChainID, &nonce, forkID) if err != nil { log.Errorf("error encoding unsigned transaction ", err) - return false, false, gasUsed, gasRefund, nil, err + return nil, err } // Create a batch to be sent to the executor @@ -981,39 +992,44 @@ func (s *State) internalTestGasEstimationTransactionV1(ctx context.Context, batc log.Debugf("executor time: %vms", time.Since(txExecutionOnExecutorTime).Milliseconds()) if err != nil { log.Errorf("error estimating gas: %v", err) - return false, false, gasUsed, gasRefund, nil, err + return nil, err } if processBatchResponse.Error != executor.ExecutorError_EXECUTOR_ERROR_NO_ERROR { err = executor.ExecutorErr(processBatchResponse.Error) s.eventLog.LogExecutorError(ctx, processBatchResponse.Error, processBatchRequestV1) - return false, false, gasUsed, gasRefund, nil, err + return nil, err } - gasUsed = processBatchResponse.Responses[0].GasUsed - gasRefund = processBatchResponse.Responses[0].GasRefunded txResponse := processBatchResponse.Responses[0] + result := &testGasEstimationResult{} + result.gasUsed = txResponse.GasUsed + result.gasRefund = txResponse.GasRefunded // Check if an out of gas error happened during EVM execution if txResponse.Error != executor.RomError_ROM_ERROR_NO_ERROR { - err := executor.RomErr(txResponse.Error) + result.failed = true + result.executionError = executor.RomErr(txResponse.Error) - if (isGasEVMError(err) || isGasApplyError(err)) && shouldOmitErr { + if (isGasEVMError(result.executionError) || isGasApplyError(result.executionError)) && shouldOmitErr { // Specifying the transaction failed, but not providing an error // is an indication that a valid error occurred due to low gas, // which will increase the lower bound for the search - return true, false, gasUsed, gasRefund, nil, nil - } - - if isEVMRevertError(err) { + return result, nil + } else if isEVMRevertError(result.executionError) { // The EVM reverted during execution, attempt to extract the // error message and return it - returnValue := txResponse.ReturnValue - return true, true, gasUsed, gasRefund, returnValue, ConstructErrorFromRevert(err, returnValue) + result.reverted = true + result.returnValue = txResponse.ReturnValue + result.executionError = ConstructErrorFromRevert(err, txResponse.ReturnValue) + } else if isOOCError(result.executionError) { + // The EVM got into an OOC error + result.ooc = true + return result, nil } - return true, false, gasUsed, gasRefund, nil, err + return result, nil } - return false, false, gasUsed, gasRefund, nil, nil + return result, nil } // internalTestGasEstimationTransactionV2 is used by the EstimateGas to test the tx execution @@ -1021,7 +1037,7 @@ func (s *State) internalTestGasEstimationTransactionV1(ctx context.Context, batc // after ETROG func (s *State) internalTestGasEstimationTransactionV2(ctx context.Context, batch *Batch, l2Block *L2Block, latestL2BlockNumber uint64, transaction *types.Transaction, forkID uint64, senderAddress common.Address, - gas uint64, nonce uint64, shouldOmitErr bool) (failed, reverted bool, gasUsed, gasRefund uint64, returnValue []byte, err error) { + gas uint64, nonce uint64, shouldOmitErr bool) (*testGasEstimationResult, error) { deltaTimestamp := uint32(uint64(time.Now().Unix()) - l2Block.Time()) transactions := s.BuildChangeL2Block(deltaTimestamp, uint32(0)) @@ -1037,7 +1053,7 @@ func (s *State) internalTestGasEstimationTransactionV2(ctx context.Context, batc batchL2Data, err := EncodeUnsignedTransaction(*tx, s.cfg.ChainID, &nonce, forkID) if err != nil { log.Errorf("error encoding unsigned transaction ", err) - return false, false, gasUsed, gasRefund, nil, err + return nil, err } transactions = append(transactions, batchL2Data...) @@ -1082,43 +1098,54 @@ func (s *State) internalTestGasEstimationTransactionV2(ctx context.Context, batc log.Infof("executor time: %vms", time.Since(txExecutionOnExecutorTime).Milliseconds()) if err != nil { log.Errorf("error estimating gas: %v", err) - return false, false, gasUsed, gasRefund, nil, err + return nil, err } if processBatchResponseV2.Error != executor.ExecutorError_EXECUTOR_ERROR_NO_ERROR { err = executor.ExecutorErr(processBatchResponseV2.Error) s.eventLog.LogExecutorErrorV2(ctx, processBatchResponseV2.Error, processBatchRequestV2) - return false, false, gasUsed, gasRefund, nil, err + return nil, err } if processBatchResponseV2.ErrorRom != executor.RomError_ROM_ERROR_NO_ERROR { err = executor.RomErr(processBatchResponseV2.ErrorRom) - return false, false, gasUsed, gasRefund, nil, err + return nil, err } - gasUsed = processBatchResponseV2.BlockResponses[0].GasUsed txResponse := processBatchResponseV2.BlockResponses[0].Responses[0] - gasRefund = txResponse.GasRefunded + result := &testGasEstimationResult{} + result.gasUsed = txResponse.GasUsed + result.gasRefund = txResponse.GasRefunded // Check if an out of gas error happened during EVM execution if txResponse.Error != executor.RomError_ROM_ERROR_NO_ERROR { - err := executor.RomErr(txResponse.Error) + result.failed = true + result.executionError = executor.RomErr(txResponse.Error) - if (isGasEVMError(err) || isGasApplyError(err)) && shouldOmitErr { + if (isGasEVMError(result.executionError) || isGasApplyError(result.executionError)) && shouldOmitErr { // Specifying the transaction failed, but not providing an error // is an indication that a valid error occurred due to low gas, // which will increase the lower bound for the search - return true, false, gasUsed, gasRefund, nil, nil - } - - if isEVMRevertError(err) { + return result, nil + } else if isEVMRevertError(result.executionError) { // The EVM reverted during execution, attempt to extract the // error message and return it - returnValue := txResponse.ReturnValue - return true, true, gasUsed, gasRefund, returnValue, ConstructErrorFromRevert(err, returnValue) + result.reverted = true + result.returnValue = txResponse.ReturnValue + result.executionError = ConstructErrorFromRevert(result.executionError, txResponse.ReturnValue) + } else if isOOCError(result.executionError) { + // The EVM got into an OOC error + result.ooc = true + return result, nil } - return true, false, gasUsed, gasRefund, nil, err + return result, nil } - return false, false, gasUsed, gasRefund, nil, nil + return result, nil +} + +// Checks if the EVM stopped tx execution due to OOC error +func isOOCError(err error) bool { + romErr := executor.RomErrorCode(err) + return executor.IsROMOutOfCountersError(romErr) } // Checks if executor level valid gas errors occurred diff --git a/test/e2e/jsonrpc1_test.go b/test/e2e/jsonrpc1_test.go index 182af71701..4906c13bfa 100644 --- a/test/e2e/jsonrpc1_test.go +++ b/test/e2e/jsonrpc1_test.go @@ -637,7 +637,7 @@ func Test_OOCErrors(t *testing.T) { }) return err.Error() }, - expectedError: "gas limit intrinsic error", + expectedError: "not enough poseidon counters to continue the execution", }, { name: "estimate gas OOG", From b9b994ac4ffc33b28e0a7db283875277af6cfe70 Mon Sep 17 00:00:00 2001 From: chengzhinei Date: Tue, 28 May 2024 11:45:16 +0800 Subject: [PATCH 18/18] fix code --- state/transaction.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/state/transaction.go b/state/transaction.go index c689e42636..9bc22a584c 100644 --- a/state/transaction.go +++ b/state/transaction.go @@ -935,7 +935,7 @@ func (s *State) EstimateGas(transaction *types.Transaction, senderAddress common // before ETROG func (s *State) internalTestGasEstimationTransactionV1(ctx context.Context, batch *Batch, l2Block *L2Block, latestL2BlockNumber uint64, transaction *types.Transaction, forkID uint64, senderAddress common.Address, - gas uint64, nonce uint64, shouldOmitErr bool) (*testGasEstimationResult, err error) { + gas uint64, nonce uint64, shouldOmitErr bool) (*testGasEstimationResult, error) { timestamp := l2Block.Time() if l2Block.NumberU64() == latestL2BlockNumber { timestamp = uint64(time.Now().Unix())