From 36321ce9eb3f1a9d873bb6900643f183d20c7586 Mon Sep 17 00:00:00 2001 From: ramtinms Date: Sat, 7 Sep 2024 15:56:57 -0700 Subject: [PATCH 1/8] adding delta commitment --- fvm/evm/emulator/emulator.go | 29 ++++-- fvm/evm/emulator/state/deltaCommitter.go | 124 +++++++++++++++++++++++ fvm/evm/emulator/state/stateDB.go | 61 +++++++---- fvm/evm/types/result.go | 2 + fvm/evm/types/state.go | 8 +- 5 files changed, 192 insertions(+), 32 deletions(-) create mode 100644 fvm/evm/emulator/state/deltaCommitter.go diff --git a/fvm/evm/emulator/emulator.go b/fvm/evm/emulator/emulator.go index 132bf32600a..b8a8d3d7b2f 100644 --- a/fvm/evm/emulator/emulator.go +++ b/fvm/evm/emulator/emulator.go @@ -6,6 +6,7 @@ import ( "github.com/holiman/uint256" "github.com/onflow/atree" + "github.com/onflow/crypto/hash" gethCommon "github.com/onflow/go-ethereum/common" gethCore "github.com/onflow/go-ethereum/core" gethTracing "github.com/onflow/go-ethereum/core/tracing" @@ -178,7 +179,8 @@ func (bl *BlockView) RunTransaction( } // all commit errors (StateDB errors) has to be returned - if err := proc.commit(true); err != nil { + res.DeltaCommitment, err = proc.commit(true) + if err != nil { return nil, err } @@ -224,7 +226,8 @@ func (bl *BlockView) BatchRunTransactions(txs []*gethTypes.Transaction) ([]*type } // all commit errors (StateDB errors) has to be returned - if err := proc.commit(false); err != nil { + res.DeltaCommitment, err = proc.commit(false) + if err != nil { return nil, err } @@ -332,18 +335,18 @@ type procedure struct { } // commit commits the changes to the state (with optional finalization) -func (proc *procedure) commit(finalize bool) error { - err := proc.state.Commit(finalize) +func (proc *procedure) commit(finalize bool) (hash.Hash, error) { + deltaCommitment, err := proc.state.Commit(finalize) if err != nil { // if known types (state errors) don't do anything and return if types.IsAFatalError(err) || types.IsAStateError(err) || types.IsABackendError(err) { - return err + return deltaCommitment, err } // else is a new fatal error - return types.NewFatalError(err) + return deltaCommitment, types.NewFatalError(err) } - return nil + return deltaCommitment, nil } func (proc *procedure) mintTo( @@ -386,7 +389,8 @@ func (proc *procedure) mintTo( } // commit and finalize the state and return any stateDB error - return res, proc.commit(true) + res.DeltaCommitment, err = proc.commit(true) + return res, err } func (proc *procedure) withdrawFrom( @@ -432,7 +436,8 @@ func (proc *procedure) withdrawFrom( proc.state.SubBalance(bridge, value, gethTracing.BalanceIncreaseWithdrawal) // commit and finalize the state and return any stateDB error - return res, proc.commit(true) + res.DeltaCommitment, err = proc.commit(true) + return res, err } // deployAt deploys a contract at the given target address @@ -574,7 +579,8 @@ func (proc *procedure) deployAt( res.CumulativeGasUsed = proc.config.BlockTotalGasUsedSoFar + res.GasConsumed proc.state.SetCode(addr, ret) - return res, proc.commit(true) + res.DeltaCommitment, err = proc.commit(true) + return res, err } func (proc *procedure) runDirect( @@ -590,7 +596,8 @@ func (proc *procedure) runDirect( return nil, err } // commit and finalize the state and return any stateDB error - return res, proc.commit(true) + res.DeltaCommitment, err = proc.commit(true) + return res, err } // run runs a geth core.message and returns the diff --git a/fvm/evm/emulator/state/deltaCommitter.go b/fvm/evm/emulator/state/deltaCommitter.go new file mode 100644 index 00000000000..bc9a047d13a --- /dev/null +++ b/fvm/evm/emulator/state/deltaCommitter.go @@ -0,0 +1,124 @@ +package state + +import ( + "encoding/binary" + + "github.com/holiman/uint256" + "github.com/onflow/crypto/hash" + gethCommon "github.com/onflow/go-ethereum/common" +) + +type OpCode byte + +const ( + UnknownOpCode OpCode = 0 + + AccountCreationOpCode OpCode = 1 + AccountUpdateOpCode OpCode = 2 + AccountDeletionOpCode OpCode = 3 + SlotUpdateOpCode OpCode = 4 +) + +const ( + opcodeByteSize = 1 + addressByteSize = gethCommon.AddressLength + nonceByteSize = 8 + balanceByteSize = 32 + hashByteSize = gethCommon.HashLength + accountDeletionBufferSize = opcodeByteSize + addressByteSize + accountCreationBufferSize = opcodeByteSize + + addressByteSize + + nonceByteSize + + balanceByteSize + + hashByteSize + accountUpdateBufferSize = accountCreationBufferSize + slotUpdateBufferSize = addressByteSize + hashByteSize + hashByteSize +) + +// DeltaCommitter captures a +// commitment over deltas +type DeltaCommitter struct { + hasher hash.Hasher +} + +// NewDeltaCommitter constructs a new delta committer +func NewDeltaCommitter() *DeltaCommitter { + return &DeltaCommitter{ + hasher: hash.NewSHA3_256(), + } +} + +func (dc *DeltaCommitter) CreateAccount( + addr gethCommon.Address, + balance *uint256.Int, + nonce uint64, + codeHash gethCommon.Hash, +) error { + buffer := make([]byte, accountCreationBufferSize) + var index int + buffer[0] = byte(AccountCreationOpCode) + index += opcodeByteSize + copy(buffer[index:index+addressByteSize], addr.Bytes()) + index += addressByteSize + copy(buffer[index:index+balanceByteSize], balance.Bytes()) + index += balanceByteSize + binary.BigEndian.PutUint64(buffer[index:index+nonceByteSize], nonce) + index += nonceByteSize + copy(buffer[index:index+hashByteSize], codeHash.Bytes()) + _, err := dc.hasher.Write(buffer) + return err +} + +func (dc *DeltaCommitter) UpdateAccount( + addr gethCommon.Address, + balance *uint256.Int, + nonce uint64, + codeHash gethCommon.Hash, +) error { + buffer := make([]byte, accountUpdateBufferSize) + var index int + buffer[0] = byte(AccountUpdateOpCode) + index += opcodeByteSize + copy(buffer[index:index+addressByteSize], addr.Bytes()) + index += addressByteSize + copy(buffer[index:index+balanceByteSize], balance.Bytes()) + index += balanceByteSize + binary.BigEndian.PutUint64(buffer[index:index+nonceByteSize], nonce) + index += nonceByteSize + copy(buffer[index:index+hashByteSize], codeHash.Bytes()) + _, err := dc.hasher.Write(buffer) + return err +} + +func (dc *DeltaCommitter) DeleteAccount(addr gethCommon.Address) error { + buffer := make([]byte, accountDeletionBufferSize) + var index int + buffer[0] = byte(AccountDeletionOpCode) + index += opcodeByteSize + copy(buffer[index:index+addressByteSize], addr.Bytes()) + _, err := dc.hasher.Write(buffer) + return err +} + +func (dc *DeltaCommitter) UpdateSlot( + addr gethCommon.Address, + key gethCommon.Hash, + value gethCommon.Hash, +) error { + buffer := make([]byte, slotUpdateBufferSize) + var index int + buffer[0] = byte(SlotUpdateOpCode) + index += opcodeByteSize + copy(buffer[index:index+addressByteSize], addr.Bytes()) + index += addressByteSize + copy(buffer[index:index+hashByteSize], key.Bytes()) + index += hashByteSize + copy(buffer[index:index+hashByteSize], value.Bytes()) + index += hashByteSize + _, err := dc.hasher.Write(buffer) + return err +} + +func (dc *DeltaCommitter) Commitment() hash.Hash { + return dc.hasher.SumHash() +} diff --git a/fvm/evm/emulator/state/stateDB.go b/fvm/evm/emulator/state/stateDB.go index 7dad40cc0d6..6eaacafc3cb 100644 --- a/fvm/evm/emulator/state/stateDB.go +++ b/fvm/evm/emulator/state/stateDB.go @@ -8,6 +8,7 @@ import ( "github.com/holiman/uint256" "github.com/onflow/atree" + "github.com/onflow/crypto/hash" gethCommon "github.com/onflow/go-ethereum/common" gethStateless "github.com/onflow/go-ethereum/core/stateless" gethTracing "github.com/onflow/go-ethereum/core/tracing" @@ -347,10 +348,10 @@ func (db *StateDB) Preimages() map[gethCommon.Hash][]byte { } // Commit commits state changes back to the underlying -func (db *StateDB) Commit(finalize bool) error { - // return error if any has been acumulated +func (db *StateDB) Commit(finalize bool) (hash.Hash, error) { + // return error if any has been accumulated if db.cachedError != nil { - return wrapError(db.cachedError) + return nil, wrapError(db.cachedError) } var err error @@ -378,6 +379,7 @@ func (db *StateDB) Commit(finalize bool) error { return bytes.Compare(sortedAddresses[i][:], sortedAddresses[j][:]) < 0 }) + deltaCommitter := NewDeltaCommitter() // update accounts for _, addr := range sortedAddresses { deleted := false @@ -385,36 +387,53 @@ func (db *StateDB) Commit(finalize bool) error { if db.HasSelfDestructed(addr) { err = db.baseView.DeleteAccount(addr) if err != nil { - return wrapError(err) + return nil, wrapError(err) + } + err = deltaCommitter.DeleteAccount(addr) + if err != nil { + return nil, wrapError(err) } deleted = true } if deleted { continue } + + bal := db.GetBalance(addr) + nonce := db.GetNonce(addr) + code := db.GetCode(addr) + codeHash := db.GetCodeHash(addr) // create new accounts if db.IsCreated(addr) { err = db.baseView.CreateAccount( addr, - db.GetBalance(addr), - db.GetNonce(addr), - db.GetCode(addr), - db.GetCodeHash(addr), + bal, + nonce, + code, + codeHash, ) if err != nil { - return wrapError(err) + return nil, wrapError(err) + } + err = deltaCommitter.CreateAccount(addr, bal, nonce, codeHash) + if err != nil { + return nil, wrapError(err) } continue } err = db.baseView.UpdateAccount( addr, - db.GetBalance(addr), - db.GetNonce(addr), - db.GetCode(addr), - db.GetCodeHash(addr), + bal, + nonce, + code, + codeHash, ) if err != nil { - return wrapError(err) + return nil, wrapError(err) + } + err = deltaCommitter.UpdateAccount(addr, bal, nonce, codeHash) + if err != nil { + return nil, wrapError(err) } } @@ -437,20 +456,26 @@ func (db *StateDB) Commit(finalize bool) error { if db.HasSelfDestructed(sk.Address) { continue } + val := db.GetState(sk.Address, sk.Key) err = db.baseView.UpdateSlot( sk, - db.GetState(sk.Address, sk.Key), + val, ) if err != nil { - return wrapError(err) + return nil, wrapError(err) + } + err = deltaCommitter.UpdateSlot(sk.Address, sk.Key, val) + if err != nil { + return nil, wrapError(err) } } // don't purge views yet, people might call the logs etc + commit := deltaCommitter.Commitment() if finalize { - return db.Finalize() + return commit, db.Finalize() } - return nil + return commit, nil } // Finalize flushes all the changes diff --git a/fvm/evm/types/result.go b/fvm/evm/types/result.go index 8a4ba270dc6..dadca51a2b6 100644 --- a/fvm/evm/types/result.go +++ b/fvm/evm/types/result.go @@ -90,6 +90,8 @@ type Result struct { // PrecompiledCalls captures an encoded list of calls to the precompile // during the execution of transaction PrecompiledCalls []byte + // DeltaCommitment captures a commitment over the state delta + DeltaCommitment []byte } // Invalid returns true if transaction has been rejected diff --git a/fvm/evm/types/state.go b/fvm/evm/types/state.go index edff68251ef..10539cef0fb 100644 --- a/fvm/evm/types/state.go +++ b/fvm/evm/types/state.go @@ -2,6 +2,7 @@ package types import ( "github.com/holiman/uint256" + "github.com/onflow/crypto/hash" gethCommon "github.com/onflow/go-ethereum/common" gethTypes "github.com/onflow/go-ethereum/core/types" gethVM "github.com/onflow/go-ethereum/core/vm" @@ -11,12 +12,13 @@ import ( type StateDB interface { gethVM.StateDB - // Commit commits the changes + // Commit commits the changes and + // returns a commitment over changes // setting `finalize` flag // calls a subsequent call to Finalize - // defering finalization and calling it once at the end + // deferring finalization and calling it once at the end // improves efficiency of batch operations. - Commit(finalize bool) error + Commit(finalize bool) (hash.Hash, error) // Finalize flushes all the changes // to the permanent storage From 378798d6a58c8b3d1fd53dcc96f7790dcd6b63be Mon Sep 17 00:00:00 2001 From: ramtinms Date: Mon, 9 Sep 2024 10:38:09 -0700 Subject: [PATCH 2/8] add tests for delta committer --- fvm/evm/emulator/state/deltaCommitter.go | 26 +++- fvm/evm/emulator/state/deltaCommitter_test.go | 121 ++++++++++++++++++ fvm/evm/emulator/state/stateDB.go | 5 +- fvm/evm/emulator/state/stateDB_test.go | 34 +++-- fvm/evm/emulator/state/state_growth_test.go | 2 +- 5 files changed, 167 insertions(+), 21 deletions(-) create mode 100644 fvm/evm/emulator/state/deltaCommitter_test.go diff --git a/fvm/evm/emulator/state/deltaCommitter.go b/fvm/evm/emulator/state/deltaCommitter.go index bc9a047d13a..53cd6017602 100644 --- a/fvm/evm/emulator/state/deltaCommitter.go +++ b/fvm/evm/emulator/state/deltaCommitter.go @@ -2,6 +2,8 @@ package state import ( "encoding/binary" + "encoding/hex" + "fmt" "github.com/holiman/uint256" "github.com/onflow/crypto/hash" @@ -32,22 +34,26 @@ const ( balanceByteSize + hashByteSize accountUpdateBufferSize = accountCreationBufferSize - slotUpdateBufferSize = addressByteSize + hashByteSize + hashByteSize + slotUpdateBufferSize = opcodeByteSize + + addressByteSize + + hashByteSize + + hashByteSize ) -// DeltaCommitter captures a -// commitment over deltas +// DeltaCommitter captures operations (delta) through +// a set of calls (order matters) and constructs a commitment over the deltas. type DeltaCommitter struct { hasher hash.Hasher } -// NewDeltaCommitter constructs a new delta committer +// NewDeltaCommitter constructs a new DeltaCommitter func NewDeltaCommitter() *DeltaCommitter { return &DeltaCommitter{ hasher: hash.NewSHA3_256(), } } +// CreateAccount captures a create account operation func (dc *DeltaCommitter) CreateAccount( addr gethCommon.Address, balance *uint256.Int, @@ -60,15 +66,18 @@ func (dc *DeltaCommitter) CreateAccount( index += opcodeByteSize copy(buffer[index:index+addressByteSize], addr.Bytes()) index += addressByteSize - copy(buffer[index:index+balanceByteSize], balance.Bytes()) + encodedBalance := balance.Bytes32() + copy(buffer[index:index+balanceByteSize], encodedBalance[:]) index += balanceByteSize binary.BigEndian.PutUint64(buffer[index:index+nonceByteSize], nonce) index += nonceByteSize copy(buffer[index:index+hashByteSize], codeHash.Bytes()) + fmt.Println(hex.EncodeToString(buffer)) _, err := dc.hasher.Write(buffer) return err } +// CreateAccount captures an update account operation func (dc *DeltaCommitter) UpdateAccount( addr gethCommon.Address, balance *uint256.Int, @@ -81,7 +90,8 @@ func (dc *DeltaCommitter) UpdateAccount( index += opcodeByteSize copy(buffer[index:index+addressByteSize], addr.Bytes()) index += addressByteSize - copy(buffer[index:index+balanceByteSize], balance.Bytes()) + encodedBalance := balance.Bytes32() + copy(buffer[index:index+balanceByteSize], encodedBalance[:]) index += balanceByteSize binary.BigEndian.PutUint64(buffer[index:index+nonceByteSize], nonce) index += nonceByteSize @@ -90,6 +100,7 @@ func (dc *DeltaCommitter) UpdateAccount( return err } +// CreateAccount captures a delete account operation func (dc *DeltaCommitter) DeleteAccount(addr gethCommon.Address) error { buffer := make([]byte, accountDeletionBufferSize) var index int @@ -100,6 +111,7 @@ func (dc *DeltaCommitter) DeleteAccount(addr gethCommon.Address) error { return err } +// CreateAccount captures a update slot operation func (dc *DeltaCommitter) UpdateSlot( addr gethCommon.Address, key gethCommon.Hash, @@ -114,11 +126,11 @@ func (dc *DeltaCommitter) UpdateSlot( copy(buffer[index:index+hashByteSize], key.Bytes()) index += hashByteSize copy(buffer[index:index+hashByteSize], value.Bytes()) - index += hashByteSize _, err := dc.hasher.Write(buffer) return err } +// Commitment calculates and returns the commitment func (dc *DeltaCommitter) Commitment() hash.Hash { return dc.hasher.SumHash() } diff --git a/fvm/evm/emulator/state/deltaCommitter_test.go b/fvm/evm/emulator/state/deltaCommitter_test.go new file mode 100644 index 00000000000..1eded96db0c --- /dev/null +++ b/fvm/evm/emulator/state/deltaCommitter_test.go @@ -0,0 +1,121 @@ +package state_test + +import ( + "testing" + + "github.com/holiman/uint256" + "github.com/onflow/crypto/hash" + "github.com/onflow/flow-go/fvm/evm/emulator/state" + "github.com/onflow/flow-go/fvm/evm/testutils" + "github.com/stretchr/testify/require" +) + +func TestDeltaCommitter(t *testing.T) { + + addr := testutils.RandomAddress(t).ToCommon() + balance := uint256.NewInt(200) + nonce := uint64(1) + nonceBytes := []byte{0, 0, 0, 0, 0, 0, 0, 1} + randomHash := testutils.RandomCommonHash(t) + key := testutils.RandomCommonHash(t) + value := testutils.RandomCommonHash(t) + + t.Run("test create account", func(t *testing.T) { + dc := state.NewDeltaCommitter() + dc.CreateAccount(addr, balance, nonce, randomHash) + + hasher := hash.NewSHA3_256() + + input := []byte{byte(state.AccountCreationOpCode)} + input = append(input, addr.Bytes()...) + encodedBalance := balance.Bytes32() + input = append(input, encodedBalance[:]...) + input = append(input, nonceBytes...) + input = append(input, randomHash.Bytes()...) + + n, err := hasher.Write(input) + require.NoError(t, err) + require.Equal(t, 93, n) + + expectedCommit := hasher.SumHash() + commit := dc.Commitment() + require.Equal(t, expectedCommit, commit) + }) + + t.Run("test update account", func(t *testing.T) { + dc := state.NewDeltaCommitter() + dc.UpdateAccount(addr, balance, nonce, randomHash) + + hasher := hash.NewSHA3_256() + input := []byte{byte(state.AccountUpdateOpCode)} + input = append(input, addr.Bytes()...) + encodedBalance := balance.Bytes32() + input = append(input, encodedBalance[:]...) + input = append(input, nonceBytes...) + input = append(input, randomHash.Bytes()...) + + n, err := hasher.Write(input) + require.NoError(t, err) + require.Equal(t, 93, n) + + expectedCommit := hasher.SumHash() + commit := dc.Commitment() + require.Equal(t, expectedCommit, commit) + }) + + t.Run("test delete account", func(t *testing.T) { + dc := state.NewDeltaCommitter() + dc.DeleteAccount(addr) + + hasher := hash.NewSHA3_256() + input := []byte{byte(state.AccountDeletionOpCode)} + input = append(input, addr.Bytes()...) + + n, err := hasher.Write(input) + require.NoError(t, err) + require.Equal(t, 21, n) + + expectedCommit := hasher.SumHash() + commit := dc.Commitment() + require.Equal(t, expectedCommit, commit) + }) + + t.Run("test update slot", func(t *testing.T) { + dc := state.NewDeltaCommitter() + dc.UpdateSlot(addr, key, value) + + hasher := hash.NewSHA3_256() + + input := []byte{byte(state.SlotUpdateOpCode)} + input = append(input, addr.Bytes()...) + input = append(input, key[:]...) + input = append(input, value[:]...) + + n, err := hasher.Write(input) + require.NoError(t, err) + require.Equal(t, 85, n) + + expectedCommit := hasher.SumHash() + commit := dc.Commitment() + require.Equal(t, expectedCommit, commit) + }) +} + +func BenchmarkDeltaCommitter(b *testing.B) { + addr := testutils.RandomAddress(b) + balance := uint256.NewInt(200) + nonce := uint64(100) + randomHash := testutils.RandomCommonHash(b) + dc := state.NewDeltaCommitter() + + numberOfAccountUpdates := 10 + for i := 0; i < numberOfAccountUpdates; i++ { + dc.UpdateAccount(addr.ToCommon(), balance, nonce, randomHash) + } + + numberOfSlotUpdates := 10 + for i := 0; i < numberOfSlotUpdates; i++ { + dc.UpdateSlot(addr.ToCommon(), randomHash, randomHash) + } + dc.Commitment() +} diff --git a/fvm/evm/emulator/state/stateDB.go b/fvm/evm/emulator/state/stateDB.go index 6eaacafc3cb..8fa2aa5568c 100644 --- a/fvm/evm/emulator/state/stateDB.go +++ b/fvm/evm/emulator/state/stateDB.go @@ -473,7 +473,10 @@ func (db *StateDB) Commit(finalize bool) (hash.Hash, error) { // don't purge views yet, people might call the logs etc commit := deltaCommitter.Commitment() if finalize { - return commit, db.Finalize() + err := db.Finalize() + if err != nil { + return nil, err + } } return commit, nil } diff --git a/fvm/evm/emulator/state/stateDB_test.go b/fvm/evm/emulator/state/stateDB_test.go index ef76234ee8a..7a6594e8691 100644 --- a/fvm/evm/emulator/state/stateDB_test.go +++ b/fvm/evm/emulator/state/stateDB_test.go @@ -88,8 +88,9 @@ func TestStateDB(t *testing.T) { ret = db.GetCommittedState(addr1, key1) require.Equal(t, gethCommon.Hash{}, ret) - err = db.Commit(true) + commit, err := db.Commit(true) require.NoError(t, err) + require.NotEmpty(t, commit) ret = db.GetCommittedState(addr1, key1) require.Equal(t, value1, ret) @@ -272,10 +273,10 @@ func TestStateDB(t *testing.T) { require.NoError(t, err) db.CreateAccount(testutils.RandomCommonAddress(t)) - - err = db.Commit(true) + commit, err := db.Commit(true) // ret := db.Error() require.Error(t, err) + require.Empty(t, commit) // check wrapping require.True(t, types.IsAStateError(err)) }) @@ -297,9 +298,10 @@ func TestStateDB(t *testing.T) { db.CreateAccount(testutils.RandomCommonAddress(t)) - err = db.Commit(true) + commit, err := db.Commit(true) // ret := db.Error() require.Error(t, err) + require.Empty(t, commit) // check wrapping require.True(t, types.IsAFatalError(err)) }) @@ -321,8 +323,9 @@ func TestStateDB(t *testing.T) { // accounts without slots db.CreateAccount(addr1) require.NoError(t, db.Error()) - err = db.Commit(true) + commit, err := db.Commit(true) require.NoError(t, err) + require.NotEmpty(t, commit) root = db.GetStorageRoot(addr1) require.NoError(t, db.Error()) @@ -330,8 +333,9 @@ func TestStateDB(t *testing.T) { db.AddBalance(addr1, uint256.NewInt(100), tracing.BalanceChangeTouchAccount) require.NoError(t, db.Error()) - err = db.Commit(true) + commit, err = db.Commit(true) require.NoError(t, err) + require.NotEmpty(t, commit) root = db.GetStorageRoot(addr1) require.NoError(t, db.Error()) @@ -344,8 +348,9 @@ func TestStateDB(t *testing.T) { require.NoError(t, db.Error()) db.SetState(addr1, key, value) require.NoError(t, db.Error()) - err = db.Commit(true) + commit, err = db.Commit(true) require.NoError(t, err) + require.NotEmpty(t, commit) root = db.GetStorageRoot(addr1) require.NoError(t, db.Error()) @@ -367,8 +372,9 @@ func TestStateDB(t *testing.T) { db.SetCode(addr1, code1) db.AddBalance(addr1, balance1, tracing.BalanceChangeTransfer) require.NoError(t, db.Error()) - err = db.Commit(true) + commit, err := db.Commit(true) require.NoError(t, err) + require.NotEmpty(t, commit) // renew db db, err = state.NewStateDB(ledger, rootAddr) require.NoError(t, err) @@ -388,8 +394,9 @@ func TestStateDB(t *testing.T) { db.AddBalance(addr2, balance2, tracing.BalanceChangeTransfer) require.NoError(t, db.Error()) // commit and renew db - err = db.Commit(true) + commit, err = db.Commit(true) require.NoError(t, err) + require.NotEmpty(t, commit) db, err = state.NewStateDB(ledger, rootAddr) require.NoError(t, err) // call self destruct should not work @@ -400,8 +407,9 @@ func TestStateDB(t *testing.T) { require.Empty(t, db.GetCode(addr2)) require.NoError(t, db.Error()) // commit and renew db - err = db.Commit(true) + commit, err = db.Commit(true) require.NoError(t, err) + require.NotEmpty(t, commit) db, err = state.NewStateDB(ledger, rootAddr) require.NoError(t, err) // set code and call contract creation @@ -411,8 +419,9 @@ func TestStateDB(t *testing.T) { // now calling selfdestruct should do the job db.Selfdestruct6780(addr2) require.NoError(t, db.Error()) - err = db.Commit(true) + commit, err = db.Commit(true) require.NoError(t, err) + require.NotEmpty(t, commit) db, err = state.NewStateDB(ledger, rootAddr) require.NoError(t, err) // now query @@ -438,8 +447,9 @@ func TestStateDB(t *testing.T) { db.Selfdestruct6780(addr3) require.NoError(t, db.Error()) // commit changes - err = db.Commit(true) + commit, err = db.Commit(true) require.NoError(t, err) + require.NotEmpty(t, commit) // renew db db, err = state.NewStateDB(ledger, rootAddr) require.NoError(t, err) diff --git a/fvm/evm/emulator/state/state_growth_test.go b/fvm/evm/emulator/state/state_growth_test.go index b2622b42a03..2ba0b12c2c3 100644 --- a/fvm/evm/emulator/state/state_growth_test.go +++ b/fvm/evm/emulator/state/state_growth_test.go @@ -64,7 +64,7 @@ func (s *storageTest) run(runner func(state types.StateDB)) error { runner(state) - err = state.Commit(true) + _, err = state.Commit(true) if err != nil { return err } From 30d9e8eb4e7ef56d4ed7e3bb7b9d86970f47184c Mon Sep 17 00:00:00 2001 From: ramtinms Date: Mon, 9 Sep 2024 10:43:55 -0700 Subject: [PATCH 3/8] rename deltaCommitter to updateCommitter --- fvm/evm/emulator/emulator.go | 12 +++++----- fvm/evm/emulator/state/stateDB.go | 2 +- .../{deltaCommitter.go => updateCommitter.go} | 22 +++++++++---------- ...mitter_test.go => updateCommitter_test.go} | 12 +++++----- fvm/evm/types/result.go | 4 ++-- 5 files changed, 26 insertions(+), 26 deletions(-) rename fvm/evm/emulator/state/{deltaCommitter.go => updateCommitter.go} (87%) rename fvm/evm/emulator/state/{deltaCommitter_test.go => updateCommitter_test.go} (93%) diff --git a/fvm/evm/emulator/emulator.go b/fvm/evm/emulator/emulator.go index b8a8d3d7b2f..8019dbd2577 100644 --- a/fvm/evm/emulator/emulator.go +++ b/fvm/evm/emulator/emulator.go @@ -179,7 +179,7 @@ func (bl *BlockView) RunTransaction( } // all commit errors (StateDB errors) has to be returned - res.DeltaCommitment, err = proc.commit(true) + res.StateChangeCommitment, err = proc.commit(true) if err != nil { return nil, err } @@ -226,7 +226,7 @@ func (bl *BlockView) BatchRunTransactions(txs []*gethTypes.Transaction) ([]*type } // all commit errors (StateDB errors) has to be returned - res.DeltaCommitment, err = proc.commit(false) + res.StateChangeCommitment, err = proc.commit(false) if err != nil { return nil, err } @@ -389,7 +389,7 @@ func (proc *procedure) mintTo( } // commit and finalize the state and return any stateDB error - res.DeltaCommitment, err = proc.commit(true) + res.StateChangeCommitment, err = proc.commit(true) return res, err } @@ -436,7 +436,7 @@ func (proc *procedure) withdrawFrom( proc.state.SubBalance(bridge, value, gethTracing.BalanceIncreaseWithdrawal) // commit and finalize the state and return any stateDB error - res.DeltaCommitment, err = proc.commit(true) + res.StateChangeCommitment, err = proc.commit(true) return res, err } @@ -579,7 +579,7 @@ func (proc *procedure) deployAt( res.CumulativeGasUsed = proc.config.BlockTotalGasUsedSoFar + res.GasConsumed proc.state.SetCode(addr, ret) - res.DeltaCommitment, err = proc.commit(true) + res.StateChangeCommitment, err = proc.commit(true) return res, err } @@ -596,7 +596,7 @@ func (proc *procedure) runDirect( return nil, err } // commit and finalize the state and return any stateDB error - res.DeltaCommitment, err = proc.commit(true) + res.StateChangeCommitment, err = proc.commit(true) return res, err } diff --git a/fvm/evm/emulator/state/stateDB.go b/fvm/evm/emulator/state/stateDB.go index 8fa2aa5568c..2063479a5a2 100644 --- a/fvm/evm/emulator/state/stateDB.go +++ b/fvm/evm/emulator/state/stateDB.go @@ -379,7 +379,7 @@ func (db *StateDB) Commit(finalize bool) (hash.Hash, error) { return bytes.Compare(sortedAddresses[i][:], sortedAddresses[j][:]) < 0 }) - deltaCommitter := NewDeltaCommitter() + deltaCommitter := NewUpdateCommitter() // update accounts for _, addr := range sortedAddresses { deleted := false diff --git a/fvm/evm/emulator/state/deltaCommitter.go b/fvm/evm/emulator/state/updateCommitter.go similarity index 87% rename from fvm/evm/emulator/state/deltaCommitter.go rename to fvm/evm/emulator/state/updateCommitter.go index 53cd6017602..f64e8b84c6a 100644 --- a/fvm/evm/emulator/state/deltaCommitter.go +++ b/fvm/evm/emulator/state/updateCommitter.go @@ -40,21 +40,21 @@ const ( hashByteSize ) -// DeltaCommitter captures operations (delta) through -// a set of calls (order matters) and constructs a commitment over the deltas. -type DeltaCommitter struct { +// UpdateCommitter captures operations (delta) through +// a set of calls (order matters) and constructs a commitment over the state changes. +type UpdateCommitter struct { hasher hash.Hasher } -// NewDeltaCommitter constructs a new DeltaCommitter -func NewDeltaCommitter() *DeltaCommitter { - return &DeltaCommitter{ +// NewUpdateCommitter constructs a new UpdateCommitter +func NewUpdateCommitter() *UpdateCommitter { + return &UpdateCommitter{ hasher: hash.NewSHA3_256(), } } // CreateAccount captures a create account operation -func (dc *DeltaCommitter) CreateAccount( +func (dc *UpdateCommitter) CreateAccount( addr gethCommon.Address, balance *uint256.Int, nonce uint64, @@ -78,7 +78,7 @@ func (dc *DeltaCommitter) CreateAccount( } // CreateAccount captures an update account operation -func (dc *DeltaCommitter) UpdateAccount( +func (dc *UpdateCommitter) UpdateAccount( addr gethCommon.Address, balance *uint256.Int, nonce uint64, @@ -101,7 +101,7 @@ func (dc *DeltaCommitter) UpdateAccount( } // CreateAccount captures a delete account operation -func (dc *DeltaCommitter) DeleteAccount(addr gethCommon.Address) error { +func (dc *UpdateCommitter) DeleteAccount(addr gethCommon.Address) error { buffer := make([]byte, accountDeletionBufferSize) var index int buffer[0] = byte(AccountDeletionOpCode) @@ -112,7 +112,7 @@ func (dc *DeltaCommitter) DeleteAccount(addr gethCommon.Address) error { } // CreateAccount captures a update slot operation -func (dc *DeltaCommitter) UpdateSlot( +func (dc *UpdateCommitter) UpdateSlot( addr gethCommon.Address, key gethCommon.Hash, value gethCommon.Hash, @@ -131,6 +131,6 @@ func (dc *DeltaCommitter) UpdateSlot( } // Commitment calculates and returns the commitment -func (dc *DeltaCommitter) Commitment() hash.Hash { +func (dc *UpdateCommitter) Commitment() hash.Hash { return dc.hasher.SumHash() } diff --git a/fvm/evm/emulator/state/deltaCommitter_test.go b/fvm/evm/emulator/state/updateCommitter_test.go similarity index 93% rename from fvm/evm/emulator/state/deltaCommitter_test.go rename to fvm/evm/emulator/state/updateCommitter_test.go index 1eded96db0c..d6287182ea4 100644 --- a/fvm/evm/emulator/state/deltaCommitter_test.go +++ b/fvm/evm/emulator/state/updateCommitter_test.go @@ -10,7 +10,7 @@ import ( "github.com/stretchr/testify/require" ) -func TestDeltaCommitter(t *testing.T) { +func TestChangeCommitter(t *testing.T) { addr := testutils.RandomAddress(t).ToCommon() balance := uint256.NewInt(200) @@ -21,7 +21,7 @@ func TestDeltaCommitter(t *testing.T) { value := testutils.RandomCommonHash(t) t.Run("test create account", func(t *testing.T) { - dc := state.NewDeltaCommitter() + dc := state.NewUpdateCommitter() dc.CreateAccount(addr, balance, nonce, randomHash) hasher := hash.NewSHA3_256() @@ -43,7 +43,7 @@ func TestDeltaCommitter(t *testing.T) { }) t.Run("test update account", func(t *testing.T) { - dc := state.NewDeltaCommitter() + dc := state.NewUpdateCommitter() dc.UpdateAccount(addr, balance, nonce, randomHash) hasher := hash.NewSHA3_256() @@ -64,7 +64,7 @@ func TestDeltaCommitter(t *testing.T) { }) t.Run("test delete account", func(t *testing.T) { - dc := state.NewDeltaCommitter() + dc := state.NewUpdateCommitter() dc.DeleteAccount(addr) hasher := hash.NewSHA3_256() @@ -81,7 +81,7 @@ func TestDeltaCommitter(t *testing.T) { }) t.Run("test update slot", func(t *testing.T) { - dc := state.NewDeltaCommitter() + dc := state.NewUpdateCommitter() dc.UpdateSlot(addr, key, value) hasher := hash.NewSHA3_256() @@ -106,7 +106,7 @@ func BenchmarkDeltaCommitter(b *testing.B) { balance := uint256.NewInt(200) nonce := uint64(100) randomHash := testutils.RandomCommonHash(b) - dc := state.NewDeltaCommitter() + dc := state.NewUpdateCommitter() numberOfAccountUpdates := 10 for i := 0; i < numberOfAccountUpdates; i++ { diff --git a/fvm/evm/types/result.go b/fvm/evm/types/result.go index dadca51a2b6..31176529f7e 100644 --- a/fvm/evm/types/result.go +++ b/fvm/evm/types/result.go @@ -90,8 +90,8 @@ type Result struct { // PrecompiledCalls captures an encoded list of calls to the precompile // during the execution of transaction PrecompiledCalls []byte - // DeltaCommitment captures a commitment over the state delta - DeltaCommitment []byte + // StateChangeCommitment captures a commitment over the state change (delta) + StateChangeCommitment []byte } // Invalid returns true if transaction has been rejected From 716f2e671796b4272df9f6505a0e9390e1bf05f4 Mon Sep 17 00:00:00 2001 From: ramtinms Date: Mon, 9 Sep 2024 10:46:43 -0700 Subject: [PATCH 4/8] rename --- fvm/evm/emulator/emulator.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fvm/evm/emulator/emulator.go b/fvm/evm/emulator/emulator.go index 8019dbd2577..16f45e500ad 100644 --- a/fvm/evm/emulator/emulator.go +++ b/fvm/evm/emulator/emulator.go @@ -336,17 +336,17 @@ type procedure struct { // commit commits the changes to the state (with optional finalization) func (proc *procedure) commit(finalize bool) (hash.Hash, error) { - deltaCommitment, err := proc.state.Commit(finalize) + stateUpdateCommitment, err := proc.state.Commit(finalize) if err != nil { // if known types (state errors) don't do anything and return if types.IsAFatalError(err) || types.IsAStateError(err) || types.IsABackendError(err) { - return deltaCommitment, err + return stateUpdateCommitment, err } // else is a new fatal error - return deltaCommitment, types.NewFatalError(err) + return stateUpdateCommitment, types.NewFatalError(err) } - return deltaCommitment, nil + return stateUpdateCommitment, nil } func (proc *procedure) mintTo( From d316bc519703a0d64bc8338f82e1dd6376abce99 Mon Sep 17 00:00:00 2001 From: ramtinms Date: Mon, 9 Sep 2024 10:48:34 -0700 Subject: [PATCH 5/8] rename --- fvm/evm/emulator/state/stateDB.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/fvm/evm/emulator/state/stateDB.go b/fvm/evm/emulator/state/stateDB.go index 2063479a5a2..6076d193773 100644 --- a/fvm/evm/emulator/state/stateDB.go +++ b/fvm/evm/emulator/state/stateDB.go @@ -379,7 +379,7 @@ func (db *StateDB) Commit(finalize bool) (hash.Hash, error) { return bytes.Compare(sortedAddresses[i][:], sortedAddresses[j][:]) < 0 }) - deltaCommitter := NewUpdateCommitter() + updateCommitter := NewUpdateCommitter() // update accounts for _, addr := range sortedAddresses { deleted := false @@ -389,7 +389,7 @@ func (db *StateDB) Commit(finalize bool) (hash.Hash, error) { if err != nil { return nil, wrapError(err) } - err = deltaCommitter.DeleteAccount(addr) + err = updateCommitter.DeleteAccount(addr) if err != nil { return nil, wrapError(err) } @@ -415,7 +415,7 @@ func (db *StateDB) Commit(finalize bool) (hash.Hash, error) { if err != nil { return nil, wrapError(err) } - err = deltaCommitter.CreateAccount(addr, bal, nonce, codeHash) + err = updateCommitter.CreateAccount(addr, bal, nonce, codeHash) if err != nil { return nil, wrapError(err) } @@ -431,7 +431,7 @@ func (db *StateDB) Commit(finalize bool) (hash.Hash, error) { if err != nil { return nil, wrapError(err) } - err = deltaCommitter.UpdateAccount(addr, bal, nonce, codeHash) + err = updateCommitter.UpdateAccount(addr, bal, nonce, codeHash) if err != nil { return nil, wrapError(err) } @@ -464,21 +464,21 @@ func (db *StateDB) Commit(finalize bool) (hash.Hash, error) { if err != nil { return nil, wrapError(err) } - err = deltaCommitter.UpdateSlot(sk.Address, sk.Key, val) + err = updateCommitter.UpdateSlot(sk.Address, sk.Key, val) if err != nil { return nil, wrapError(err) } } // don't purge views yet, people might call the logs etc - commit := deltaCommitter.Commitment() + updateCommit := updateCommitter.Commitment() if finalize { err := db.Finalize() if err != nil { return nil, err } } - return commit, nil + return updateCommit, nil } // Finalize flushes all the changes From 547de4cdf82683ec611ac87939ffe93b698e95ea Mon Sep 17 00:00:00 2001 From: ramtinms Date: Mon, 9 Sep 2024 22:40:13 -0700 Subject: [PATCH 6/8] lint fix --- fvm/evm/emulator/state/updateCommitter_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fvm/evm/emulator/state/updateCommitter_test.go b/fvm/evm/emulator/state/updateCommitter_test.go index d6287182ea4..56325c292b5 100644 --- a/fvm/evm/emulator/state/updateCommitter_test.go +++ b/fvm/evm/emulator/state/updateCommitter_test.go @@ -5,9 +5,10 @@ import ( "github.com/holiman/uint256" "github.com/onflow/crypto/hash" + "github.com/stretchr/testify/require" + "github.com/onflow/flow-go/fvm/evm/emulator/state" "github.com/onflow/flow-go/fvm/evm/testutils" - "github.com/stretchr/testify/require" ) func TestChangeCommitter(t *testing.T) { From 31bb5444b94a2b953840fc317c2180c4473b0cd6 Mon Sep 17 00:00:00 2001 From: ramtinms Date: Tue, 10 Sep 2024 11:08:58 -0700 Subject: [PATCH 7/8] clean up --- fvm/evm/emulator/state/updateCommitter.go | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/fvm/evm/emulator/state/updateCommitter.go b/fvm/evm/emulator/state/updateCommitter.go index f64e8b84c6a..e2c3f331c6e 100644 --- a/fvm/evm/emulator/state/updateCommitter.go +++ b/fvm/evm/emulator/state/updateCommitter.go @@ -2,8 +2,6 @@ package state import ( "encoding/binary" - "encoding/hex" - "fmt" "github.com/holiman/uint256" "github.com/onflow/crypto/hash" @@ -72,12 +70,11 @@ func (dc *UpdateCommitter) CreateAccount( binary.BigEndian.PutUint64(buffer[index:index+nonceByteSize], nonce) index += nonceByteSize copy(buffer[index:index+hashByteSize], codeHash.Bytes()) - fmt.Println(hex.EncodeToString(buffer)) _, err := dc.hasher.Write(buffer) return err } -// CreateAccount captures an update account operation +// UpdateAccount captures an update account operation func (dc *UpdateCommitter) UpdateAccount( addr gethCommon.Address, balance *uint256.Int, @@ -100,7 +97,7 @@ func (dc *UpdateCommitter) UpdateAccount( return err } -// CreateAccount captures a delete account operation +// DeleteAccount captures a delete account operation func (dc *UpdateCommitter) DeleteAccount(addr gethCommon.Address) error { buffer := make([]byte, accountDeletionBufferSize) var index int @@ -111,7 +108,7 @@ func (dc *UpdateCommitter) DeleteAccount(addr gethCommon.Address) error { return err } -// CreateAccount captures a update slot operation +// UpdateSlot captures a update slot operation func (dc *UpdateCommitter) UpdateSlot( addr gethCommon.Address, key gethCommon.Hash, From ffb2e91cd37fed86fba1a2ada932eff255814333 Mon Sep 17 00:00:00 2001 From: ramtinms Date: Tue, 10 Sep 2024 11:34:52 -0700 Subject: [PATCH 8/8] lint fix --- .../emulator/state/updateCommitter_test.go | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/fvm/evm/emulator/state/updateCommitter_test.go b/fvm/evm/emulator/state/updateCommitter_test.go index 56325c292b5..ab0be67a08f 100644 --- a/fvm/evm/emulator/state/updateCommitter_test.go +++ b/fvm/evm/emulator/state/updateCommitter_test.go @@ -23,7 +23,8 @@ func TestChangeCommitter(t *testing.T) { t.Run("test create account", func(t *testing.T) { dc := state.NewUpdateCommitter() - dc.CreateAccount(addr, balance, nonce, randomHash) + err := dc.CreateAccount(addr, balance, nonce, randomHash) + require.NoError(t, err) hasher := hash.NewSHA3_256() @@ -45,7 +46,8 @@ func TestChangeCommitter(t *testing.T) { t.Run("test update account", func(t *testing.T) { dc := state.NewUpdateCommitter() - dc.UpdateAccount(addr, balance, nonce, randomHash) + err := dc.UpdateAccount(addr, balance, nonce, randomHash) + require.NoError(t, err) hasher := hash.NewSHA3_256() input := []byte{byte(state.AccountUpdateOpCode)} @@ -66,7 +68,8 @@ func TestChangeCommitter(t *testing.T) { t.Run("test delete account", func(t *testing.T) { dc := state.NewUpdateCommitter() - dc.DeleteAccount(addr) + err := dc.DeleteAccount(addr) + require.NoError(t, err) hasher := hash.NewSHA3_256() input := []byte{byte(state.AccountDeletionOpCode)} @@ -83,7 +86,8 @@ func TestChangeCommitter(t *testing.T) { t.Run("test update slot", func(t *testing.T) { dc := state.NewUpdateCommitter() - dc.UpdateSlot(addr, key, value) + err := dc.UpdateSlot(addr, key, value) + require.NoError(t, err) hasher := hash.NewSHA3_256() @@ -111,12 +115,15 @@ func BenchmarkDeltaCommitter(b *testing.B) { numberOfAccountUpdates := 10 for i := 0; i < numberOfAccountUpdates; i++ { - dc.UpdateAccount(addr.ToCommon(), balance, nonce, randomHash) + err := dc.UpdateAccount(addr.ToCommon(), balance, nonce, randomHash) + require.NoError(b, err) } numberOfSlotUpdates := 10 for i := 0; i < numberOfSlotUpdates; i++ { - dc.UpdateSlot(addr.ToCommon(), randomHash, randomHash) + err := dc.UpdateSlot(addr.ToCommon(), randomHash, randomHash) + require.NoError(b, err) } - dc.Commitment() + com := dc.Commitment() + require.NotEmpty(b, com) }