Skip to content

Commit

Permalink
Merge pull request #6451 from onflow/ramtin/evm-add-delta-commitment
Browse files Browse the repository at this point in the history
[EVM] adding commitment over state updates
  • Loading branch information
ramtinms authored Sep 18, 2024
2 parents 2a443de + d55256f commit f498ae8
Show file tree
Hide file tree
Showing 8 changed files with 356 additions and 45 deletions.
29 changes: 18 additions & 11 deletions fvm/evm/emulator/emulator.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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.StateChangeCommitment, err = proc.commit(true)
if err != nil {
return nil, err
}

Expand Down Expand Up @@ -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.StateChangeCommitment, err = proc.commit(false)
if err != nil {
return nil, err
}

Expand Down Expand Up @@ -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) {
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 err
return stateUpdateCommitment, err
}

// else is a new fatal error
return types.NewFatalError(err)
return stateUpdateCommitment, types.NewFatalError(err)
}
return nil
return stateUpdateCommitment, nil
}

func (proc *procedure) mintTo(
Expand Down Expand Up @@ -386,7 +389,8 @@ func (proc *procedure) mintTo(
}

// commit and finalize the state and return any stateDB error
return res, proc.commit(true)
res.StateChangeCommitment, err = proc.commit(true)
return res, err
}

func (proc *procedure) withdrawFrom(
Expand Down Expand Up @@ -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.StateChangeCommitment, err = proc.commit(true)
return res, err
}

// deployAt deploys a contract at the given target address
Expand Down Expand Up @@ -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.StateChangeCommitment, err = proc.commit(true)
return res, err
}

func (proc *procedure) runDirect(
Expand All @@ -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.StateChangeCommitment, err = proc.commit(true)
return res, err
}

// run runs a geth core.message and returns the
Expand Down
64 changes: 46 additions & 18 deletions fvm/evm/emulator/state/stateDB.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -378,43 +379,61 @@ func (db *StateDB) Commit(finalize bool) error {
return bytes.Compare(sortedAddresses[i][:], sortedAddresses[j][:]) < 0
})

updateCommitter := NewUpdateCommitter()
// update accounts
for _, addr := range sortedAddresses {
deleted := false
// first we need to delete accounts
if db.HasSelfDestructed(addr) {
err = db.baseView.DeleteAccount(addr)
if err != nil {
return wrapError(err)
return nil, wrapError(err)
}
err = updateCommitter.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 = updateCommitter.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 = updateCommitter.UpdateAccount(addr, bal, nonce, codeHash)
if err != nil {
return nil, wrapError(err)
}
}

Expand All @@ -437,20 +456,29 @@ 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 = 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
updateCommit := updateCommitter.Commitment()
if finalize {
return db.Finalize()
err := db.Finalize()
if err != nil {
return nil, err
}
}
return nil
return updateCommit, nil
}

// Finalize flushes all the changes
Expand Down
34 changes: 22 additions & 12 deletions fvm/evm/emulator/state/stateDB_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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))
})
Expand All @@ -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))
})
Expand All @@ -321,17 +323,19 @@ 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())
require.Equal(t, gethTypes.EmptyRootHash, root)

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())
Expand All @@ -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())
Expand All @@ -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)
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion fvm/evm/emulator/state/state_growth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
Loading

0 comments on commit f498ae8

Please sign in to comment.