From e87057f9ef68964a6551890a42cb54c7d52c2991 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristjan=20T=C3=B5iste?= Date: Wed, 27 Sep 2023 13:06:29 +0300 Subject: [PATCH 1/3] Adding generic tx system fixes to evm --- internal/txsystem/evm/tx_system.go | 25 ++++-- .../evm/tx_system_integration_test.go | 83 ++++++++++++++++++- scripts/evm/pubkey2address.go | 1 + 3 files changed, 98 insertions(+), 11 deletions(-) create mode 100644 scripts/evm/pubkey2address.go diff --git a/internal/txsystem/evm/tx_system.go b/internal/txsystem/evm/tx_system.go index bfd3bde34..beaf61592 100644 --- a/internal/txsystem/evm/tx_system.go +++ b/internal/txsystem/evm/tx_system.go @@ -21,6 +21,7 @@ type TxSystem struct { genericTxValidators []txsystem.GenericTransactionValidator beginBlockFunctions []func(blockNumber uint64) error endBlockFunctions []func(blockNumber uint64) error + roundCommitted bool } func NewEVMTxSystem(systemIdentifier []byte, opts ...Option) (*TxSystem, error) { @@ -92,6 +93,7 @@ func (m *TxSystem) getState() (txsystem.State, error) { func (m *TxSystem) BeginBlock(blockNr uint64) error { m.currentBlockNumber = blockNr + m.roundCommitted = false for _, function := range m.beginBlockFunctions { if err := function(blockNr); err != nil { return fmt.Errorf("begin block function call failed: %w", err) @@ -100,6 +102,13 @@ func (m *TxSystem) BeginBlock(blockNr uint64) error { return nil } +func (m *TxSystem) pruneLogs(blockNr uint64) error { + if err := m.logPruner.Prune(blockNr - 1); err != nil { + return fmt.Errorf("unable to prune state: %w", err) + } + return nil +} + func (m *TxSystem) Execute(tx *types.TransactionOrder) (sm *types.ServerMetadata, err error) { u, _ := m.state.GetUnit(tx.UnitID(), false) ctx := &txsystem.TxValidationContext{ @@ -149,13 +158,6 @@ func (m *TxSystem) Execute(tx *types.TransactionOrder) (sm *types.ServerMetadata return sm, err } -func (m *TxSystem) pruneLogs(blockNr uint64) error { - if err := m.logPruner.Prune(blockNr - 1); err != nil { - return fmt.Errorf("unable to prune state: %w", err) - } - return nil -} - func (m *TxSystem) EndBlock() (txsystem.State, error) { for _, function := range m.endBlockFunctions { if err := function(m.currentBlockNumber); err != nil { @@ -166,11 +168,18 @@ func (m *TxSystem) EndBlock() (txsystem.State, error) { } func (m *TxSystem) Revert() { + if m.roundCommitted { + return + } m.logPruner.Remove(m.currentBlockNumber) m.state.Revert() } func (m *TxSystem) Commit() error { m.logPruner.Remove(m.currentBlockNumber - 1) - return m.state.Commit() + err := m.state.Commit() + if err == nil { + m.roundCommitted = true + } + return err } diff --git a/internal/txsystem/evm/tx_system_integration_test.go b/internal/txsystem/evm/tx_system_integration_test.go index bad7c9c98..aa03bd5c0 100644 --- a/internal/txsystem/evm/tx_system_integration_test.go +++ b/internal/txsystem/evm/tx_system_integration_test.go @@ -83,7 +83,7 @@ func TestEVMPartition_DeployAndCallContract(t *testing.T) { require.NoError(t, err) // call contract - increment - callContractTx := createCallContractTx(from, contractAddr, cABI.Methods["increment"].ID, t) + callContractTx := createCallContractTx(from, contractAddr, cABI.Methods["increment"].ID, 2, t) require.NoError(t, evmPartition.SubmitTx(callContractTx)) require.Eventually(t, testpartition.BlockchainContainsTx(evmPartition, callContractTx), test.WaitDuration, test.WaitTick) _, _, txRecord, err = evmPartition.GetTxProof(callContractTx) @@ -106,6 +106,83 @@ func TestEVMPartition_DeployAndCallContract(t *testing.T) { require.Nil(t, entry.Data) } +func TestEVMPartition_Revert_test(t *testing.T) { + from := test.RandomBytes(20) + cABI, err := abi.JSON(bytes.NewBuffer([]byte(counterABI))) + require.NoError(t, err) + system, err := NewEVMTxSystem(systemIdentifier, WithInitialAddressAndBalance(from, big.NewInt(oneEth)), WithBlockDB(memorydb.New())) // 1 ETH + require.NoError(t, err) + + // Simulate round 1 + require.NoError(t, system.BeginBlock(1)) + // transfer + to := test.RandomBytes(20) + transferTx := createTransferTx(t, from, to) + meta, err := system.Execute(transferTx) + require.NoError(t, err) + require.NotNil(t, meta) + // deploy contract + deployContractTx := createDeployContractTx(t, from) + meta, err = system.Execute(deployContractTx) + require.NoError(t, err) + require.NotNil(t, meta) + require.Equal(t, types.TxStatusSuccessful, meta.SuccessIndicator) + var details ProcessingDetails + require.NoError(t, cbor.Unmarshal(meta.ProcessingDetails, &details)) + require.Equal(t, details.ErrorDetails, "") + contractAddr := evmcrypto.CreateAddress(common.BytesToAddress(from), 1) + require.Equal(t, details.ContractAddr, contractAddr) + require.NotEmpty(t, details.ReturnData) // increment does not return anything + // call contract - increment + callContractTx := createCallContractTx(from, contractAddr, cABI.Methods["increment"].ID, 2, t) + meta, err = system.Execute(callContractTx) + require.NoError(t, err) + require.NotNil(t, meta) + require.Equal(t, types.TxStatusSuccessful, meta.SuccessIndicator) + require.NoError(t, cbor.Unmarshal(meta.ProcessingDetails, &details)) + require.Equal(t, details.ErrorDetails, "") + require.Equal(t, details.ContractAddr, common.Address{}) + // expect count uint256 = 1 + count := uint256.NewInt(1) + require.EqualValues(t, count.PaddedBytes(32), details.ReturnData) + require.Len(t, details.Logs, 1) + entry := details.Logs[0] + require.Len(t, entry.Topics, 2) + require.Equal(t, common.BytesToHash(evmcrypto.Keccak256([]byte(cABI.Events["Increment"].Sig))), entry.Topics[0]) + require.Equal(t, common.BytesToHash(count.PaddedBytes(32)), entry.Topics[1]) + require.Equal(t, contractAddr, entry.Address) + require.Nil(t, entry.Data) + round1EndState, err := system.EndBlock() + require.NoError(t, err) + require.NotNil(t, round1EndState) + require.NoError(t, system.Commit()) + // Round 2, but this gets reverted + require.NoError(t, system.BeginBlock(2)) + callContractTx = createCallContractTx(from, contractAddr, cABI.Methods["increment"].ID, 3, t) + meta, err = system.Execute(callContractTx) + require.NoError(t, err) + require.NotNil(t, meta) + require.Equal(t, types.TxStatusSuccessful, meta.SuccessIndicator) + require.NoError(t, cbor.Unmarshal(meta.ProcessingDetails, &details)) + require.Equal(t, details.ErrorDetails, "") + require.Equal(t, details.ContractAddr, common.Address{}) + count = uint256.NewInt(2) + require.EqualValues(t, count.PaddedBytes(32), details.ReturnData) + round2EndState, err := system.EndBlock() + require.NoError(t, err) + require.NotNil(t, round2EndState) + require.NotEqualValues(t, round1EndState.Root(), round2EndState.Root()) + // revert round 2 and do it over again + system.Revert() + revertedState, err := system.StateSummary() + require.NoError(t, err) + require.Equal(t, round1EndState.Root(), revertedState.Root()) + // Round 2 again, but this time with empty block, state should not change from round 1 + require.NoError(t, system.BeginBlock(2)) + round2EndState, err = system.EndBlock() + require.NotEqualValues(t, round2EndState.Root(), round1EndState.Root()) +} + func createTransferTx(t *testing.T, from []byte, to []byte) *types.TransactionOrder { evmAttr := &TxAttributes{ From: from, @@ -128,14 +205,14 @@ func createTransferTx(t *testing.T, from []byte, to []byte) *types.TransactionOr } } -func createCallContractTx(from []byte, addr common.Address, methodID []byte, t *testing.T) *types.TransactionOrder { +func createCallContractTx(from []byte, addr common.Address, methodID []byte, nonce uint64, t *testing.T) *types.TransactionOrder { evmAttr := &TxAttributes{ From: from, To: addr.Bytes(), Data: methodID, Value: big.NewInt(0), Gas: 100000, - Nonce: 2, + Nonce: nonce, } attrBytes, err := cbor.Marshal(evmAttr) require.NoError(t, err) diff --git a/scripts/evm/pubkey2address.go b/scripts/evm/pubkey2address.go new file mode 100644 index 000000000..e998e5586 --- /dev/null +++ b/scripts/evm/pubkey2address.go @@ -0,0 +1 @@ +package evm From 2a6f9605ec42d11da63b4ef457b18e97a193daee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristjan=20T=C3=B5iste?= Date: Wed, 27 Sep 2023 13:15:28 +0300 Subject: [PATCH 2/3] Corrected AlpabillLink object copy --- internal/txsystem/evm/statedb/units.go | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/internal/txsystem/evm/statedb/units.go b/internal/txsystem/evm/statedb/units.go index f449b814f..11753fe83 100644 --- a/internal/txsystem/evm/statedb/units.go +++ b/internal/txsystem/evm/statedb/units.go @@ -15,7 +15,6 @@ import ( var ( _ abstate.UnitData = (*StateObject)(nil) - _ abstate.UnitData = (*AlphaBillLink)(nil) emptyCodeHash = crypto.Keccak256(nil) ) @@ -74,15 +73,11 @@ func (s *StateObject) Copy() abstate.UnitData { return nil } - var link *AlphaBillLink - if s.AlphaBill != nil { - link = s.AlphaBill.Copy().(*AlphaBillLink) - } return &StateObject{ Address: common.BytesToAddress(bytes.Clone(s.Address.Bytes())), Account: s.Account.Copy(), Storage: s.Storage.Copy(), - AlphaBill: link, + AlphaBill: s.AlphaBill.Copy(), suicided: s.suicided, } } @@ -96,7 +91,7 @@ func (f *AlphaBillLink) SummaryValueInput() uint64 { return 0 } -func (f *AlphaBillLink) Copy() abstate.UnitData { +func (f *AlphaBillLink) Copy() *AlphaBillLink { if f == nil { return nil } From c78d4581f1d8c58b4f2996e51d730cee09645e7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristjan=20T=C3=B5iste?= Date: Wed, 27 Sep 2023 13:19:33 +0300 Subject: [PATCH 3/3] Removed unintended file from commit --- scripts/evm/pubkey2address.go | 1 - 1 file changed, 1 deletion(-) delete mode 100644 scripts/evm/pubkey2address.go diff --git a/scripts/evm/pubkey2address.go b/scripts/evm/pubkey2address.go deleted file mode 100644 index e998e5586..000000000 --- a/scripts/evm/pubkey2address.go +++ /dev/null @@ -1 +0,0 @@ -package evm