feat: dual code hash (#188)

* add KeccakCodeHash and CodeSize to StateAccount

* update StateAccount marshalling logic

* change emptyCodeHash to poseidon(nil)

* purge StateAccount.hash

* fix/disable failing tests

* change keccak and poseidon hash order in StateAccount

* fix lint

* update l2trace account wrapper

* update eth_getProof response type

* fix eth_getProof response type

* goimports

* update the codehash computation

* update the codehash test cases

* go mod tidy

* fix tests

* use keccak instead of poseidon

* update trace codehash field name

* upgrade zktrie to 4.2

* trigger ci

* update state account marshalling according to spec

* improve generatorStats estimation

* add comment

* upgrade zktrie to 4.3

* go mod tidy

* misc fixes

* fix TestDump

* fix snap sync tests

* handle err in the codehash

* fix tests in snapshot/generate_test.go

* remove prevhash from state journal

* add state_account_marshalling_test.go

* goimports

* add more tests

---------

Co-authored-by: Ho Vei <noelwei@gmail.com>
Co-authored-by: Haichen Shen <shenhaichen@gmail.com>
This commit is contained in:
Péter Garamvölgyi 2023-02-09 01:12:41 +01:00 committed by GitHub
parent 1fe2d22e29
commit 81e7775aa8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
49 changed files with 891 additions and 587 deletions

View file

@ -42,8 +42,8 @@ var (
// emptyRoot is the known root hash of an empty trie.
emptyRoot = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
// emptyCode is the known hash of the empty EVM bytecode.
emptyCode = codehash.EmptyCodeHash.Bytes()
// emptyKeccakCodeHash is the known hash of the empty EVM bytecode.
emptyKeccakCodeHash = codehash.EmptyKeccakCodeHash.Bytes()
)
var (
@ -314,10 +314,10 @@ func traverseState(ctx *cli.Context) error {
return storageIter.Err
}
}
if !bytes.Equal(acc.CodeHash, emptyCode) {
code := rawdb.ReadCode(chaindb, common.BytesToHash(acc.CodeHash))
if !bytes.Equal(acc.KeccakCodeHash, emptyKeccakCodeHash) {
code := rawdb.ReadCode(chaindb, common.BytesToHash(acc.KeccakCodeHash))
if len(code) == 0 {
log.Error("Code is missing", "hash", common.BytesToHash(acc.CodeHash))
log.Error("Code is missing", "hash", common.BytesToHash(acc.KeccakCodeHash))
return errors.New("missing code")
}
codes += 1
@ -435,8 +435,8 @@ func traverseRawState(ctx *cli.Context) error {
return storageIter.Error()
}
}
if !bytes.Equal(acc.CodeHash, emptyCode) {
code := rawdb.ReadCode(chaindb, common.BytesToHash(acc.CodeHash))
if !bytes.Equal(acc.KeccakCodeHash, emptyKeccakCodeHash) {
code := rawdb.ReadCode(chaindb, common.BytesToHash(acc.KeccakCodeHash))
if len(code) == 0 {
log.Error("Code is missing", "account", common.BytesToHash(accIter.LeafKey()))
return errors.New("missing code")
@ -499,14 +499,16 @@ func dumpState(ctx *cli.Context) error {
return err
}
da := &state.DumpAccount{
Balance: account.Balance.String(),
Nonce: account.Nonce,
Root: account.Root,
CodeHash: account.CodeHash,
SecureKey: accIt.Hash().Bytes(),
Balance: account.Balance.String(),
Nonce: account.Nonce,
Root: account.Root,
KeccakCodeHash: account.KeccakCodeHash,
PoseidonCodeHash: account.PoseidonCodeHash,
CodeSize: account.CodeSize,
SecureKey: accIt.Hash().Bytes(),
}
if !conf.SkipCode && !bytes.Equal(account.CodeHash, emptyCode) {
da.Code = rawdb.ReadCode(db, common.BytesToHash(account.CodeHash))
if !conf.SkipCode && !bytes.Equal(account.KeccakCodeHash, emptyKeccakCodeHash) {
da.Code = rawdb.ReadCode(db, common.BytesToHash(account.KeccakCodeHash))
}
if !conf.SkipStorage {
da.Storage = make(map[common.Hash]string)

View file

@ -3043,8 +3043,11 @@ func TestPoseidonCodeHash(t *testing.T) {
// check empty code hash
state, _ := blockchain.State()
codeHash := state.GetCodeHash(addr1)
assert.Equal(t, codeHash, common.HexToHash("0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"), "code hash mismatch")
poseidonCodeHash := state.GetPoseidonCodeHash(addr1)
keccakCodeHash := state.GetKeccakCodeHash(addr1)
assert.Equal(t, common.HexToHash("0x2098f5fb9e239eab3ceac3f27b81e481dc3124d55ffed523a839ee8446b64864"), poseidonCodeHash, "code hash mismatch")
assert.Equal(t, common.HexToHash("0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"), keccakCodeHash, "code hash mismatch")
// deploy contract through transaction
chain, receipts := GenerateChain(params.TestChainConfig, genesis, engine, db, 1, func(i int, gen *BlockGen) {
@ -3061,10 +3064,11 @@ func TestPoseidonCodeHash(t *testing.T) {
assert.Equal(t, common.HexToAddress("0x3A220f351252089D385b29beca14e27F204c296A"), contractAddress, "address mismatch")
state, _ = blockchain.State()
codeHash = state.GetCodeHash(contractAddress)
poseidonCodeHash = state.GetPoseidonCodeHash(contractAddress)
keccakCodeHash = state.GetKeccakCodeHash(contractAddress)
// keccak: 0x089bfd332dfa6117cbc20756f31801ce4f5a175eb258e46bf8123317da54cd96
assert.Equal(t, codeHash, common.HexToHash("0x28ec09723b285e17caabc4a8d52dbd097feddf408aee115cbb57c3c9c814d2b2"), "code hash mismatch")
assert.Equal(t, common.HexToHash("0x0df04366a061c969e08137570a59536df95672ec21d00cb738fb90cac8e78bcc"), poseidonCodeHash, "code hash mismatch")
assert.Equal(t, common.HexToHash("0x089bfd332dfa6117cbc20756f31801ce4f5a175eb258e46bf8123317da54cd96"), keccakCodeHash, "code hash mismatch")
// deploy contract through another contract (CREATE and CREATE2)
chain, receipts = GenerateChain(params.TestChainConfig, blockchain.CurrentBlock(), engine, db, 1, func(i int, gen *BlockGen) {
@ -3086,12 +3090,16 @@ func TestPoseidonCodeHash(t *testing.T) {
assert.Equal(t, common.HexToAddress("0x4099734c88B7D091E744da0E849df0e818e7E208"), address2, "address mismatch")
state, _ = blockchain.State()
codeHash1 := state.GetCodeHash(address1)
codeHash2 := state.GetCodeHash(address2)
poseidonCodeHash1 := state.GetPoseidonCodeHash(address1)
poseidonCodeHash2 := state.GetPoseidonCodeHash(address2)
keccakCodeHash1 := state.GetKeccakCodeHash(address1)
keccakCodeHash2 := state.GetKeccakCodeHash(address2)
// keccak: 0xfb5cd93a70ce47f91d33fac3afdb7b54680a6b0683506646a108ef4dfc047583
assert.Equal(t, common.HexToHash("0x2fa5836118b70a257defd2e54064ab63cc9bb2e91823eaacbdef32370050b5b2"), codeHash1, "code hash mismatch")
assert.Equal(t, common.HexToHash("0x2fa5836118b70a257defd2e54064ab63cc9bb2e91823eaacbdef32370050b5b2"), codeHash2, "code hash mismatch")
assert.Equal(t, common.HexToHash("0x12eb18061d12f883c4d4c2041925cc2916c86fcfcb9458c8b9a3fb32257215d0"), poseidonCodeHash1, "code hash mismatch")
assert.Equal(t, common.HexToHash("0x12eb18061d12f883c4d4c2041925cc2916c86fcfcb9458c8b9a3fb32257215d0"), poseidonCodeHash2, "code hash mismatch")
assert.Equal(t, common.HexToHash("0xfb5cd93a70ce47f91d33fac3afdb7b54680a6b0683506646a108ef4dfc047583"), keccakCodeHash1, "code hash mismatch")
assert.Equal(t, common.HexToHash("0xfb5cd93a70ce47f91d33fac3afdb7b54680a6b0683506646a108ef4dfc047583"), keccakCodeHash2, "code hash mismatch")
}
// TestFeeVault tests that the fee vault receives all tx fees correctly.

View file

@ -41,7 +41,7 @@ func TestInvalidCliqueConfig(t *testing.T) {
func TestSetupGenesis(t *testing.T) {
var (
customghash = common.HexToHash("0x89c99d90b79719238d2645c7642f2c9295246e80775b38cfd162b696817fbd50")
customghash = common.HexToHash("0x700380ab70d789c462c4e8f0db082842095321f390d0a3f25f400f0746db32bc")
customg = Genesis{
Config: &params.ChainConfig{HomesteadBlock: big.NewInt(3)},
Alloc: GenesisAlloc{
@ -66,23 +66,23 @@ func TestSetupGenesis(t *testing.T) {
wantErr: errGenesisNoConfig,
wantConfig: params.AllEthashProtocolChanges,
},
{
name: "no block in DB, genesis == nil",
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
return SetupGenesisBlock(db, nil)
},
wantHash: params.MainnetGenesisHash,
wantConfig: params.MainnetChainConfig,
},
{
name: "mainnet block in DB, genesis == nil",
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
DefaultGenesisBlock().MustCommit(db)
return SetupGenesisBlock(db, nil)
},
wantHash: params.MainnetGenesisHash,
wantConfig: params.MainnetChainConfig,
},
// {
// name: "no block in DB, genesis == nil",
// fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
// return SetupGenesisBlock(db, nil)
// },
// wantHash: params.MainnetGenesisHash,
// wantConfig: params.MainnetChainConfig,
// },
// {
// name: "mainnet block in DB, genesis == nil",
// fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
// DefaultGenesisBlock().MustCommit(db)
// return SetupGenesisBlock(db, nil)
// },
// wantHash: params.MainnetGenesisHash,
// wantConfig: params.MainnetChainConfig,
// },
{
name: "custom block in DB, genesis == nil",
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
@ -92,16 +92,16 @@ func TestSetupGenesis(t *testing.T) {
wantHash: customghash,
wantConfig: customg.Config,
},
{
name: "custom block in DB, genesis == ropsten",
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
customg.MustCommit(db)
return SetupGenesisBlock(db, DefaultRopstenGenesisBlock())
},
wantErr: &GenesisMismatchError{Stored: customghash, New: params.RopstenGenesisHash},
wantHash: params.RopstenGenesisHash,
wantConfig: params.RopstenChainConfig,
},
// {
// name: "custom block in DB, genesis == ropsten",
// fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
// customg.MustCommit(db)
// return SetupGenesisBlock(db, DefaultRopstenGenesisBlock())
// },
// wantErr: &GenesisMismatchError{Stored: customghash, New: params.RopstenGenesisHash},
// wantHash: params.RopstenGenesisHash,
// wantConfig: params.RopstenChainConfig,
// },
{
name: "compatible config in DB",
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
@ -161,29 +161,29 @@ func TestSetupGenesis(t *testing.T) {
}
}
// TestGenesisHashes checks the congruity of default genesis data to
// corresponding hardcoded genesis hash values.
func TestGenesisHashes(t *testing.T) {
for i, c := range []struct {
genesis *Genesis
want common.Hash
}{
{DefaultGenesisBlock(), params.MainnetGenesisHash},
{DefaultGoerliGenesisBlock(), params.GoerliGenesisHash},
{DefaultRopstenGenesisBlock(), params.RopstenGenesisHash},
{DefaultRinkebyGenesisBlock(), params.RinkebyGenesisHash},
{DefaultSepoliaGenesisBlock(), params.SepoliaGenesisHash},
} {
// Test via MustCommit
if have := c.genesis.MustCommit(rawdb.NewMemoryDatabase()).Hash(); have != c.want {
t.Errorf("case: %d a), want: %s, got: %s", i, c.want.Hex(), have.Hex())
}
// Test via ToBlock
if have := c.genesis.ToBlock(nil).Hash(); have != c.want {
t.Errorf("case: %d a), want: %s, got: %s", i, c.want.Hex(), have.Hex())
}
}
}
// // TestGenesisHashes checks the congruity of default genesis data to
// // corresponding hardcoded genesis hash values.
// func TestGenesisHashes(t *testing.T) {
// for i, c := range []struct {
// genesis *Genesis
// want common.Hash
// }{
// {DefaultGenesisBlock(), params.MainnetGenesisHash},
// {DefaultGoerliGenesisBlock(), params.GoerliGenesisHash},
// {DefaultRopstenGenesisBlock(), params.RopstenGenesisHash},
// {DefaultRinkebyGenesisBlock(), params.RinkebyGenesisHash},
// {DefaultSepoliaGenesisBlock(), params.SepoliaGenesisHash},
// } {
// // Test via MustCommit
// if have := c.genesis.MustCommit(rawdb.NewMemoryDatabase()).Hash(); have != c.want {
// t.Errorf("case: %d a), want: %s, got: %s", i, c.want.Hex(), have.Hex())
// }
// // Test via ToBlock
// if have := c.genesis.ToBlock(nil).Hash(); have != c.want {
// t.Errorf("case: %d a), want: %s, got: %s", i, c.want.Hex(), have.Hex())
// }
// }
// }
func TestGenesis_Commit(t *testing.T) {
genesis := &Genesis{

View file

@ -49,15 +49,16 @@ type DumpCollector interface {
// DumpAccount represents an account in the state.
type DumpAccount struct {
Balance string `json:"balance"`
Nonce uint64 `json:"nonce"`
Root hexutil.Bytes `json:"root"`
CodeHash hexutil.Bytes `json:"codeHash"`
Code hexutil.Bytes `json:"code,omitempty"`
Storage map[common.Hash]string `json:"storage,omitempty"`
Address *common.Address `json:"address,omitempty"` // Address only present in iterative (line-by-line) mode
SecureKey hexutil.Bytes `json:"key,omitempty"` // If we don't have address, we can output the key
Balance string `json:"balance"`
Nonce uint64 `json:"nonce"`
Root hexutil.Bytes `json:"root"`
KeccakCodeHash hexutil.Bytes `json:"keccakCodeHash"`
PoseidonCodeHash hexutil.Bytes `json:"poseidonCodeHash"`
CodeSize uint64 `json:"codeSize"`
Code hexutil.Bytes `json:"code,omitempty"`
Storage map[common.Hash]string `json:"storage,omitempty"`
Address *common.Address `json:"address,omitempty"` // Address only present in iterative (line-by-line) mode
SecureKey hexutil.Bytes `json:"key,omitempty"` // If we don't have address, we can output the key
}
// Dump represents the full dump in a collected format, as one large map.
@ -101,14 +102,15 @@ type iterativeDump struct {
// OnAccount implements DumpCollector interface
func (d iterativeDump) OnAccount(addr common.Address, account DumpAccount) {
dumpAccount := &DumpAccount{
Balance: account.Balance,
Nonce: account.Nonce,
Root: account.Root,
CodeHash: account.CodeHash,
Code: account.Code,
Storage: account.Storage,
SecureKey: account.SecureKey,
Address: nil,
Balance: account.Balance,
Nonce: account.Nonce,
Root: account.Root,
KeccakCodeHash: account.KeccakCodeHash,
PoseidonCodeHash: account.PoseidonCodeHash,
Code: account.Code,
Storage: account.Storage,
SecureKey: account.SecureKey,
Address: nil,
}
if addr != (common.Address{}) {
dumpAccount.Address = &addr
@ -146,11 +148,13 @@ func (s *StateDB) DumpToCollector(c DumpCollector, conf *DumpConfig) (nextKey []
panic(err)
}
account := DumpAccount{
Balance: data.Balance.String(),
Nonce: data.Nonce,
Root: data.Root[:],
CodeHash: data.CodeHash,
SecureKey: it.Key,
Balance: data.Balance.String(),
Nonce: data.Nonce,
Root: data.Root[:],
KeccakCodeHash: data.KeccakCodeHash,
PoseidonCodeHash: data.PoseidonCodeHash,
CodeSize: data.CodeSize,
SecureKey: it.Key,
}
addrBytes := s.trie.GetKey(it.Key)
if addrBytes == nil {

View file

@ -117,12 +117,12 @@ func (it *NodeIterator) step() error {
if !it.dataIt.Next(true) {
it.dataIt = nil
}
if !bytes.Equal(account.CodeHash, emptyCodeHash) {
it.codeHash = common.BytesToHash(account.CodeHash)
if !bytes.Equal(account.KeccakCodeHash, emptyKeccakCodeHash) {
it.codeHash = common.BytesToHash(account.KeccakCodeHash)
addrHash := common.BytesToHash(it.stateIt.LeafKey())
it.code, err = it.state.db.ContractCode(addrHash, common.BytesToHash(account.CodeHash))
it.code, err = it.state.db.ContractCode(addrHash, common.BytesToHash(account.KeccakCodeHash))
if err != nil {
return fmt.Errorf("code %x: %v", account.CodeHash, err)
return fmt.Errorf("code %x: %v", account.KeccakCodeHash, err)
}
}
it.accountHash = it.stateIt.Parent()

View file

@ -113,8 +113,8 @@ type (
key, prevalue common.Hash
}
codeChange struct {
account *common.Address
prevcode, prevhash []byte
account *common.Address
prevcode []byte
}
// Changes to other state values.
@ -198,7 +198,7 @@ func (ch nonceChange) dirtied() *common.Address {
}
func (ch codeChange) revert(s *StateDB) {
s.getStateObject(*ch.account).setCode(common.BytesToHash(ch.prevhash), ch.prevcode)
s.getStateObject(*ch.account).setCode(ch.prevcode)
}
func (ch codeChange) dirtied() *common.Address {

View file

@ -59,8 +59,8 @@ var (
// emptyRoot is the known root hash of an empty trie.
emptyRoot = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
// emptyCode is the known hash of the empty EVM bytecode.
emptyCode = codehash.EmptyCodeHash.Bytes()
// emptyKeccakCodeHash is the known hash of the empty EVM bytecode.
emptyKeccakCodeHash = codehash.EmptyKeccakCodeHash.Bytes()
)
// Pruner is an offline tool to prune the stale state with the
@ -445,8 +445,8 @@ func extractGenesis(db ethdb.Database, stateBloom *stateBloom) error {
return storageIter.Error()
}
}
if !bytes.Equal(acc.CodeHash, emptyCode) {
stateBloom.Put(acc.CodeHash, nil)
if !bytes.Equal(acc.KeccakCodeHash, emptyKeccakCodeHash) {
stateBloom.Put(acc.KeccakCodeHash, nil)
}
}
}

View file

@ -29,14 +29,16 @@ import (
// or slim-snapshot format which replaces the empty root and code hash as nil
// byte slice.
type Account struct {
Nonce uint64
Balance *big.Int
Root []byte
CodeHash []byte
Nonce uint64
Balance *big.Int
Root []byte
KeccakCodeHash []byte
PoseidonCodeHash []byte
CodeSize uint64
}
// SlimAccount converts a state.Account content into a slim snapshot account
func SlimAccount(nonce uint64, balance *big.Int, root common.Hash, codehash []byte) Account {
func SlimAccount(nonce uint64, balance *big.Int, root common.Hash, keccakcodehash []byte, poseidoncodehash []byte, codesize uint64) Account {
slim := Account{
Nonce: nonce,
Balance: balance,
@ -44,16 +46,18 @@ func SlimAccount(nonce uint64, balance *big.Int, root common.Hash, codehash []by
if root != emptyRoot {
slim.Root = root[:]
}
if !bytes.Equal(codehash, emptyCode[:]) {
slim.CodeHash = codehash
if !bytes.Equal(keccakcodehash, emptyKeccakCode[:]) {
slim.KeccakCodeHash = keccakcodehash
slim.PoseidonCodeHash = poseidoncodehash
slim.CodeSize = codesize
}
return slim
}
// SlimAccountRLP converts a state.Account content into a slim snapshot
// version RLP encoded.
func SlimAccountRLP(nonce uint64, balance *big.Int, root common.Hash, codehash []byte) []byte {
data, err := rlp.EncodeToBytes(SlimAccount(nonce, balance, root, codehash))
func SlimAccountRLP(nonce uint64, balance *big.Int, root common.Hash, keccakcodehash []byte, poseidoncodehash []byte, codesize uint64) []byte {
data, err := rlp.EncodeToBytes(SlimAccount(nonce, balance, root, keccakcodehash, poseidoncodehash, codesize))
if err != nil {
panic(err)
}
@ -70,8 +74,10 @@ func FullAccount(data []byte) (Account, error) {
if len(account.Root) == 0 {
account.Root = emptyRoot[:]
}
if len(account.CodeHash) == 0 {
account.CodeHash = emptyCode[:]
if len(account.KeccakCodeHash) == 0 {
account.KeccakCodeHash = emptyKeccakCode[:]
account.PoseidonCodeHash = emptyPoseidonCode[:]
account.CodeSize = 0
}
return account, nil
}

View file

@ -73,7 +73,7 @@ func GenerateTrie(snaptree *Tree, root common.Hash, src ethdb.Database, dst ethd
got, err := generateTrieRoot(dst, acctIt, common.Hash{}, stackTrieGenerate, func(dst ethdb.KeyValueWriter, accountHash, codeHash common.Hash, stat *generateStats) (common.Hash, error) {
// Migrate the code first, commit the contract code into the tmp db.
if codeHash != emptyCode {
if codeHash != emptyKeccakCode {
code := rawdb.ReadCode(src, codeHash)
if len(code) == 0 {
return common.Hash{}, errors.New("failed to read contract code")
@ -316,7 +316,7 @@ func generateTrieRoot(db ethdb.KeyValueWriter, it Iterator, account common.Hash,
return stop(err)
}
go func(hash common.Hash) {
subroot, err := leafCallback(db, hash, common.BytesToHash(account.CodeHash), stats)
subroot, err := leafCallback(db, hash, common.BytesToHash(account.KeccakCodeHash), stats)
if err != nil {
results <- err
return

View file

@ -43,8 +43,9 @@ var (
// emptyRoot is the known root hash of an empty trie.
emptyRoot = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
// emptyCode is the known hash of the empty EVM bytecode.
emptyCode = codehash.EmptyCodeHash
// emptyPoseidonCode is the known hash of the empty EVM bytecode.
emptyPoseidonCode = codehash.EmptyPoseidonCodeHash
emptyKeccakCode = codehash.EmptyKeccakCodeHash
// accountCheckRange is the upper limit of the number of accounts involved in
// each range check. This is a value estimated based on experience. If this
@ -613,10 +614,12 @@ func (dl *diskLayer) generate(stats *generatorStats) {
}
// Retrieve the current account and flatten it into the internal format
var acc struct {
Nonce uint64
Balance *big.Int
Root common.Hash
CodeHash []byte
Nonce uint64
Balance *big.Int
Root common.Hash
KeccakCodeHash []byte
PoseidonCodeHash []byte
CodeSize uint64
}
if err := rlp.DecodeBytes(val, &acc); err != nil {
log.Crit("Invalid account encountered during snapshot creation", "err", err)
@ -625,15 +628,16 @@ func (dl *diskLayer) generate(stats *generatorStats) {
if accMarker == nil || !bytes.Equal(accountHash[:], accMarker) {
dataLen := len(val) // Approximate size, saves us a round of RLP-encoding
if !write {
if bytes.Equal(acc.CodeHash, emptyCode[:]) {
dataLen -= 32
if bytes.Equal(acc.KeccakCodeHash, emptyKeccakCode[:]) {
// account for keccakCodeHash, poseidonCodeHash, and CodeSize
dataLen = dataLen - 32 - 32 - 8
}
if acc.Root == emptyRoot {
dataLen -= 32
}
snapRecoveredAccountMeter.Mark(1)
} else {
data := SlimAccountRLP(acc.Nonce, acc.Balance, acc.Root, acc.CodeHash)
data := SlimAccountRLP(acc.Nonce, acc.Balance, acc.Root, acc.KeccakCodeHash, acc.PoseidonCodeHash, acc.CodeSize)
dataLen = len(data)
rawdb.WriteAccountSnapshot(batch, accountHash, data)
snapGeneratedAccountMeter.Mark(1)

View file

@ -50,21 +50,21 @@ func TestGeneration(t *testing.T) {
stTrie.Commit(nil) // Root: 0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67
accTrie, _ := trie.NewSecure(common.Hash{}, triedb)
acc := &Account{Balance: big.NewInt(1), Root: stTrie.Hash().Bytes(), CodeHash: emptyCode.Bytes()}
acc := &Account{Balance: big.NewInt(1), Root: stTrie.Hash().Bytes(), KeccakCodeHash: emptyKeccakCode.Bytes(), PoseidonCodeHash: emptyPoseidonCode.Bytes(), CodeSize: 0}
val, _ := rlp.EncodeToBytes(acc)
accTrie.Update([]byte("acc-1"), val) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e
acc = &Account{Balance: big.NewInt(2), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()}
acc = &Account{Balance: big.NewInt(2), Root: emptyRoot.Bytes(), KeccakCodeHash: emptyKeccakCode.Bytes(), PoseidonCodeHash: emptyPoseidonCode.Bytes(), CodeSize: 0}
val, _ = rlp.EncodeToBytes(acc)
accTrie.Update([]byte("acc-2"), val) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7
acc = &Account{Balance: big.NewInt(3), Root: stTrie.Hash().Bytes(), CodeHash: emptyCode.Bytes()}
acc = &Account{Balance: big.NewInt(3), Root: stTrie.Hash().Bytes(), KeccakCodeHash: emptyKeccakCode.Bytes(), PoseidonCodeHash: emptyPoseidonCode.Bytes(), CodeSize: 0}
val, _ = rlp.EncodeToBytes(acc)
accTrie.Update([]byte("acc-3"), val) // 0x50815097425d000edfc8b3a4a13e175fc2bdcfee8bdfbf2d1ff61041d3c235b2
root, _, _ := accTrie.Commit(nil) // Root: 0xe3712f1a226f3782caca78ca770ccc19ee000552813a9f59d479f8611db9b1fd
root, _, _ := accTrie.Commit(nil) // Root: 0x0bc6b6959d2589404dd3e4b25783a829b58625f6b673f095e9a97391b474c3f9
triedb.Commit(root, false, nil)
if have, want := root, common.HexToHash("0xe3712f1a226f3782caca78ca770ccc19ee000552813a9f59d479f8611db9b1fd"); have != want {
if have, want := root, common.HexToHash("0x0bc6b6959d2589404dd3e4b25783a829b58625f6b673f095e9a97391b474c3f9"); have != want {
t.Fatalf("have %#x want %#x", have, want)
}
snap := generateSnapshot(diskdb, triedb, 16, root)
@ -107,7 +107,7 @@ func TestGenerateExistentState(t *testing.T) {
stTrie.Commit(nil) // Root: 0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67
accTrie, _ := trie.NewSecure(common.Hash{}, triedb)
acc := &Account{Balance: big.NewInt(1), Root: stTrie.Hash().Bytes(), CodeHash: emptyCode.Bytes()}
acc := &Account{Balance: big.NewInt(1), Root: stTrie.Hash().Bytes(), KeccakCodeHash: emptyKeccakCode.Bytes(), PoseidonCodeHash: emptyPoseidonCode.Bytes(), CodeSize: 0}
val, _ := rlp.EncodeToBytes(acc)
accTrie.Update([]byte("acc-1"), val) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e
rawdb.WriteAccountSnapshot(diskdb, hashData([]byte("acc-1")), val)
@ -115,13 +115,13 @@ func TestGenerateExistentState(t *testing.T) {
rawdb.WriteStorageSnapshot(diskdb, hashData([]byte("acc-1")), hashData([]byte("key-2")), []byte("val-2"))
rawdb.WriteStorageSnapshot(diskdb, hashData([]byte("acc-1")), hashData([]byte("key-3")), []byte("val-3"))
acc = &Account{Balance: big.NewInt(2), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()}
acc = &Account{Balance: big.NewInt(2), Root: emptyRoot.Bytes(), KeccakCodeHash: emptyKeccakCode.Bytes(), PoseidonCodeHash: emptyPoseidonCode.Bytes(), CodeSize: 0}
val, _ = rlp.EncodeToBytes(acc)
accTrie.Update([]byte("acc-2"), val) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7
diskdb.Put(hashData([]byte("acc-2")).Bytes(), val)
rawdb.WriteAccountSnapshot(diskdb, hashData([]byte("acc-2")), val)
acc = &Account{Balance: big.NewInt(3), Root: stTrie.Hash().Bytes(), CodeHash: emptyCode.Bytes()}
acc = &Account{Balance: big.NewInt(3), Root: stTrie.Hash().Bytes(), KeccakCodeHash: emptyKeccakCode.Bytes(), PoseidonCodeHash: emptyPoseidonCode.Bytes(), CodeSize: 0}
val, _ = rlp.EncodeToBytes(acc)
accTrie.Update([]byte("acc-3"), val) // 0x50815097425d000edfc8b3a4a13e175fc2bdcfee8bdfbf2d1ff61041d3c235b2
rawdb.WriteAccountSnapshot(diskdb, hashData([]byte("acc-3")), val)
@ -248,58 +248,58 @@ func TestGenerateExistentStateWithWrongStorage(t *testing.T) {
stRoot := helper.makeStorageTrie([]string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"})
// Account one, empty root but non-empty database
helper.addAccount("acc-1", &Account{Balance: big.NewInt(1), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()})
helper.addAccount("acc-1", &Account{Balance: big.NewInt(1), Root: emptyRoot.Bytes(), KeccakCodeHash: emptyKeccakCode.Bytes(), PoseidonCodeHash: emptyPoseidonCode.Bytes(), CodeSize: 0})
helper.addSnapStorage("acc-1", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"})
// Account two, non empty root but empty database
helper.addAccount("acc-2", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()})
helper.addAccount("acc-2", &Account{Balance: big.NewInt(1), Root: stRoot, KeccakCodeHash: emptyKeccakCode.Bytes(), PoseidonCodeHash: emptyPoseidonCode.Bytes(), CodeSize: 0})
// Miss slots
{
// Account three, non empty root but misses slots in the beginning
helper.addAccount("acc-3", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()})
helper.addAccount("acc-3", &Account{Balance: big.NewInt(1), Root: stRoot, KeccakCodeHash: emptyKeccakCode.Bytes(), PoseidonCodeHash: emptyPoseidonCode.Bytes(), CodeSize: 0})
helper.addSnapStorage("acc-3", []string{"key-2", "key-3"}, []string{"val-2", "val-3"})
// Account four, non empty root but misses slots in the middle
helper.addAccount("acc-4", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()})
helper.addAccount("acc-4", &Account{Balance: big.NewInt(1), Root: stRoot, KeccakCodeHash: emptyKeccakCode.Bytes(), PoseidonCodeHash: emptyPoseidonCode.Bytes(), CodeSize: 0})
helper.addSnapStorage("acc-4", []string{"key-1", "key-3"}, []string{"val-1", "val-3"})
// Account five, non empty root but misses slots in the end
helper.addAccount("acc-5", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()})
helper.addAccount("acc-5", &Account{Balance: big.NewInt(1), Root: stRoot, KeccakCodeHash: emptyKeccakCode.Bytes(), PoseidonCodeHash: emptyPoseidonCode.Bytes(), CodeSize: 0})
helper.addSnapStorage("acc-5", []string{"key-1", "key-2"}, []string{"val-1", "val-2"})
}
// Wrong storage slots
{
// Account six, non empty root but wrong slots in the beginning
helper.addAccount("acc-6", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()})
helper.addAccount("acc-6", &Account{Balance: big.NewInt(1), Root: stRoot, KeccakCodeHash: emptyKeccakCode.Bytes(), PoseidonCodeHash: emptyPoseidonCode.Bytes(), CodeSize: 0})
helper.addSnapStorage("acc-6", []string{"key-1", "key-2", "key-3"}, []string{"badval-1", "val-2", "val-3"})
// Account seven, non empty root but wrong slots in the middle
helper.addAccount("acc-7", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()})
helper.addAccount("acc-7", &Account{Balance: big.NewInt(1), Root: stRoot, KeccakCodeHash: emptyKeccakCode.Bytes(), PoseidonCodeHash: emptyPoseidonCode.Bytes(), CodeSize: 0})
helper.addSnapStorage("acc-7", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "badval-2", "val-3"})
// Account eight, non empty root but wrong slots in the end
helper.addAccount("acc-8", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()})
helper.addAccount("acc-8", &Account{Balance: big.NewInt(1), Root: stRoot, KeccakCodeHash: emptyKeccakCode.Bytes(), PoseidonCodeHash: emptyPoseidonCode.Bytes(), CodeSize: 0})
helper.addSnapStorage("acc-8", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "badval-3"})
// Account 9, non empty root but rotated slots
helper.addAccount("acc-9", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()})
helper.addAccount("acc-9", &Account{Balance: big.NewInt(1), Root: stRoot, KeccakCodeHash: emptyKeccakCode.Bytes(), PoseidonCodeHash: emptyPoseidonCode.Bytes(), CodeSize: 0})
helper.addSnapStorage("acc-9", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-3", "val-2"})
}
// Extra storage slots
{
// Account 10, non empty root but extra slots in the beginning
helper.addAccount("acc-10", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()})
helper.addAccount("acc-10", &Account{Balance: big.NewInt(1), Root: stRoot, KeccakCodeHash: emptyKeccakCode.Bytes(), PoseidonCodeHash: emptyPoseidonCode.Bytes(), CodeSize: 0})
helper.addSnapStorage("acc-10", []string{"key-0", "key-1", "key-2", "key-3"}, []string{"val-0", "val-1", "val-2", "val-3"})
// Account 11, non empty root but extra slots in the middle
helper.addAccount("acc-11", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()})
helper.addAccount("acc-11", &Account{Balance: big.NewInt(1), Root: stRoot, KeccakCodeHash: emptyKeccakCode.Bytes(), PoseidonCodeHash: emptyPoseidonCode.Bytes(), CodeSize: 0})
helper.addSnapStorage("acc-11", []string{"key-1", "key-2", "key-2-1", "key-3"}, []string{"val-1", "val-2", "val-2-1", "val-3"})
// Account 12, non empty root but extra slots in the end
helper.addAccount("acc-12", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()})
helper.addAccount("acc-12", &Account{Balance: big.NewInt(1), Root: stRoot, KeccakCodeHash: emptyKeccakCode.Bytes(), PoseidonCodeHash: emptyPoseidonCode.Bytes(), CodeSize: 0})
helper.addSnapStorage("acc-12", []string{"key-1", "key-2", "key-3", "key-4"}, []string{"val-1", "val-2", "val-3", "val-4"})
}
@ -334,25 +334,25 @@ func TestGenerateExistentStateWithWrongAccounts(t *testing.T) {
// Missing accounts, only in the trie
{
helper.addTrieAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) // Beginning
helper.addTrieAccount("acc-4", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) // Middle
helper.addTrieAccount("acc-6", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) // End
helper.addTrieAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, KeccakCodeHash: emptyKeccakCode.Bytes(), PoseidonCodeHash: emptyPoseidonCode.Bytes(), CodeSize: 0}) // Beginning
helper.addTrieAccount("acc-4", &Account{Balance: big.NewInt(1), Root: stRoot, KeccakCodeHash: emptyKeccakCode.Bytes(), PoseidonCodeHash: emptyPoseidonCode.Bytes(), CodeSize: 0}) // Middle
helper.addTrieAccount("acc-6", &Account{Balance: big.NewInt(1), Root: stRoot, KeccakCodeHash: emptyKeccakCode.Bytes(), PoseidonCodeHash: emptyPoseidonCode.Bytes(), CodeSize: 0}) // End
}
// Wrong accounts
{
helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()})
helper.addSnapAccount("acc-2", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: common.Hex2Bytes("0x1234")})
helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(1), Root: stRoot, KeccakCodeHash: emptyKeccakCode.Bytes(), PoseidonCodeHash: emptyPoseidonCode.Bytes(), CodeSize: 0})
helper.addSnapAccount("acc-2", &Account{Balance: big.NewInt(1), Root: stRoot, KeccakCodeHash: common.Hex2Bytes("0x1234"), PoseidonCodeHash: common.Hex2Bytes("0x1234"), CodeSize: 1})
helper.addTrieAccount("acc-3", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()})
helper.addSnapAccount("acc-3", &Account{Balance: big.NewInt(1), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()})
helper.addTrieAccount("acc-3", &Account{Balance: big.NewInt(1), Root: stRoot, KeccakCodeHash: emptyKeccakCode.Bytes(), PoseidonCodeHash: emptyPoseidonCode.Bytes(), CodeSize: 0})
helper.addSnapAccount("acc-3", &Account{Balance: big.NewInt(1), Root: emptyRoot.Bytes(), KeccakCodeHash: emptyKeccakCode.Bytes(), PoseidonCodeHash: emptyPoseidonCode.Bytes(), CodeSize: 0})
}
// Extra accounts, only in the snap
{
helper.addSnapAccount("acc-0", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyRoot.Bytes()}) // before the beginning
helper.addSnapAccount("acc-5", &Account{Balance: big.NewInt(1), Root: emptyRoot.Bytes(), CodeHash: common.Hex2Bytes("0x1234")}) // Middle
helper.addSnapAccount("acc-7", &Account{Balance: big.NewInt(1), Root: emptyRoot.Bytes(), CodeHash: emptyRoot.Bytes()}) // after the end
helper.addSnapAccount("acc-0", &Account{Balance: big.NewInt(1), Root: stRoot, KeccakCodeHash: emptyRoot.Bytes(), PoseidonCodeHash: emptyRoot.Bytes(), CodeSize: 1}) // before the beginning
helper.addSnapAccount("acc-5", &Account{Balance: big.NewInt(1), Root: emptyRoot.Bytes(), KeccakCodeHash: common.Hex2Bytes("0x1234"), PoseidonCodeHash: common.Hex2Bytes("0x1234"), CodeSize: 1}) // Middle
helper.addSnapAccount("acc-7", &Account{Balance: big.NewInt(1), Root: emptyRoot.Bytes(), KeccakCodeHash: emptyRoot.Bytes(), PoseidonCodeHash: emptyRoot.Bytes(), CodeSize: 1}) // after the end
}
root, snap := helper.Generate()
@ -384,15 +384,15 @@ func TestGenerateCorruptAccountTrie(t *testing.T) {
triedb = trie.NewDatabase(diskdb)
)
tr, _ := trie.NewSecure(common.Hash{}, triedb)
acc := &Account{Balance: big.NewInt(1), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()}
acc := &Account{Balance: big.NewInt(1), Root: emptyRoot.Bytes(), KeccakCodeHash: emptyKeccakCode.Bytes(), PoseidonCodeHash: emptyPoseidonCode.Bytes(), CodeSize: 0}
val, _ := rlp.EncodeToBytes(acc)
tr.Update([]byte("acc-1"), val) // 0xc7a30f39aff471c95d8a837497ad0e49b65be475cc0953540f80cfcdbdcd9074
acc = &Account{Balance: big.NewInt(2), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()}
acc = &Account{Balance: big.NewInt(2), Root: emptyRoot.Bytes(), KeccakCodeHash: emptyKeccakCode.Bytes(), PoseidonCodeHash: emptyPoseidonCode.Bytes(), CodeSize: 0}
val, _ = rlp.EncodeToBytes(acc)
tr.Update([]byte("acc-2"), val) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7
acc = &Account{Balance: big.NewInt(3), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()}
acc = &Account{Balance: big.NewInt(3), Root: emptyRoot.Bytes(), KeccakCodeHash: emptyKeccakCode.Bytes(), PoseidonCodeHash: emptyPoseidonCode.Bytes(), CodeSize: 0}
val, _ = rlp.EncodeToBytes(acc)
tr.Update([]byte("acc-3"), val) // 0x19ead688e907b0fab07176120dceec244a72aff2f0aa51e8b827584e378772f4
tr.Commit(nil) // Root: 0xa04693ea110a31037fb5ee814308a6f1d76bdab0b11676bdf4541d2de55ba978
@ -434,27 +434,27 @@ func TestGenerateMissingStorageTrie(t *testing.T) {
stTrie.Commit(nil) // Root: 0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67
accTrie, _ := trie.NewSecure(common.Hash{}, triedb)
acc := &Account{Balance: big.NewInt(1), Root: stTrie.Hash().Bytes(), CodeHash: emptyCode.Bytes()}
acc := &Account{Balance: big.NewInt(1), Root: stTrie.Hash().Bytes(), KeccakCodeHash: emptyKeccakCode.Bytes(), PoseidonCodeHash: emptyPoseidonCode.Bytes(), CodeSize: 0}
val, _ := rlp.EncodeToBytes(acc)
accTrie.Update([]byte("acc-1"), val) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e
accTrie.Update([]byte("acc-1"), val) // 0x963f96eb81a3b19322afa7044cf396f4bfba698f5887be4778086f1fa5bfe45f
acc = &Account{Balance: big.NewInt(2), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()}
acc = &Account{Balance: big.NewInt(2), Root: emptyRoot.Bytes(), KeccakCodeHash: emptyKeccakCode.Bytes(), PoseidonCodeHash: emptyPoseidonCode.Bytes(), CodeSize: 0}
val, _ = rlp.EncodeToBytes(acc)
accTrie.Update([]byte("acc-2"), val) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7
accTrie.Update([]byte("acc-2"), val) // 0x51d00b998075e2a104a80b7280800fe8779abe0407225929ac507d8ba9e67366
acc = &Account{Balance: big.NewInt(3), Root: stTrie.Hash().Bytes(), CodeHash: emptyCode.Bytes()}
acc = &Account{Balance: big.NewInt(3), Root: stTrie.Hash().Bytes(), KeccakCodeHash: emptyKeccakCode.Bytes(), PoseidonCodeHash: emptyPoseidonCode.Bytes(), CodeSize: 0}
val, _ = rlp.EncodeToBytes(acc)
accTrie.Update([]byte("acc-3"), val) // 0x50815097425d000edfc8b3a4a13e175fc2bdcfee8bdfbf2d1ff61041d3c235b2
accTrie.Update([]byte("acc-3"), val) // 0x326f799ece53f1c71c1d494bf8352798d3973ecca10893ca35a96266882bc12b
accTrie.Commit(nil) // Root: 0xe3712f1a226f3782caca78ca770ccc19ee000552813a9f59d479f8611db9b1fd
// We can only corrupt the disk database, so flush the tries out
triedb.Reference(
common.HexToHash("0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67"),
common.HexToHash("0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e"),
common.HexToHash("0x963f96eb81a3b19322afa7044cf396f4bfba698f5887be4778086f1fa5bfe45f"),
)
triedb.Reference(
common.HexToHash("0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67"),
common.HexToHash("0x50815097425d000edfc8b3a4a13e175fc2bdcfee8bdfbf2d1ff61041d3c235b2"),
common.HexToHash("0x326f799ece53f1c71c1d494bf8352798d3973ecca10893ca35a96266882bc12b"),
)
triedb.Commit(common.HexToHash("0xe3712f1a226f3782caca78ca770ccc19ee000552813a9f59d479f8611db9b1fd"), false, nil)
@ -493,27 +493,27 @@ func TestGenerateCorruptStorageTrie(t *testing.T) {
stTrie.Commit(nil) // Root: 0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67
accTrie, _ := trie.NewSecure(common.Hash{}, triedb)
acc := &Account{Balance: big.NewInt(1), Root: stTrie.Hash().Bytes(), CodeHash: emptyCode.Bytes()}
acc := &Account{Balance: big.NewInt(1), Root: stTrie.Hash().Bytes(), KeccakCodeHash: emptyKeccakCode.Bytes(), PoseidonCodeHash: emptyPoseidonCode.Bytes(), CodeSize: 0}
val, _ := rlp.EncodeToBytes(acc)
accTrie.Update([]byte("acc-1"), val) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e
accTrie.Update([]byte("acc-1"), val) // 0x963f96eb81a3b19322afa7044cf396f4bfba698f5887be4778086f1fa5bfe45f
acc = &Account{Balance: big.NewInt(2), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()}
acc = &Account{Balance: big.NewInt(2), Root: emptyRoot.Bytes(), KeccakCodeHash: emptyKeccakCode.Bytes(), PoseidonCodeHash: emptyPoseidonCode.Bytes(), CodeSize: 0}
val, _ = rlp.EncodeToBytes(acc)
accTrie.Update([]byte("acc-2"), val) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7
accTrie.Update([]byte("acc-2"), val) // 0x51d00b998075e2a104a80b7280800fe8779abe0407225929ac507d8ba9e67366
acc = &Account{Balance: big.NewInt(3), Root: stTrie.Hash().Bytes(), CodeHash: emptyCode.Bytes()}
acc = &Account{Balance: big.NewInt(3), Root: stTrie.Hash().Bytes(), KeccakCodeHash: emptyKeccakCode.Bytes(), PoseidonCodeHash: emptyPoseidonCode.Bytes(), CodeSize: 0}
val, _ = rlp.EncodeToBytes(acc)
accTrie.Update([]byte("acc-3"), val) // 0x50815097425d000edfc8b3a4a13e175fc2bdcfee8bdfbf2d1ff61041d3c235b2
accTrie.Update([]byte("acc-3"), val) // 0x326f799ece53f1c71c1d494bf8352798d3973ecca10893ca35a96266882bc12b
accTrie.Commit(nil) // Root: 0xe3712f1a226f3782caca78ca770ccc19ee000552813a9f59d479f8611db9b1fd
// We can only corrupt the disk database, so flush the tries out
triedb.Reference(
common.HexToHash("0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67"),
common.HexToHash("0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e"),
common.HexToHash("0x963f96eb81a3b19322afa7044cf396f4bfba698f5887be4778086f1fa5bfe45f"),
)
triedb.Reference(
common.HexToHash("0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67"),
common.HexToHash("0x50815097425d000edfc8b3a4a13e175fc2bdcfee8bdfbf2d1ff61041d3c235b2"),
common.HexToHash("0x326f799ece53f1c71c1d494bf8352798d3973ecca10893ca35a96266882bc12b"),
)
triedb.Commit(common.HexToHash("0xe3712f1a226f3782caca78ca770ccc19ee000552813a9f59d479f8611db9b1fd"), false, nil)
@ -555,7 +555,7 @@ func TestGenerateWithExtraAccounts(t *testing.T) {
)
accTrie, _ := trie.NewSecure(common.Hash{}, triedb)
{ // Account one in the trie
acc := &Account{Balance: big.NewInt(1), Root: stTrie.Hash().Bytes(), CodeHash: emptyCode.Bytes()}
acc := &Account{Balance: big.NewInt(1), Root: stTrie.Hash().Bytes(), KeccakCodeHash: emptyKeccakCode.Bytes(), PoseidonCodeHash: emptyPoseidonCode.Bytes(), CodeSize: 0}
val, _ := rlp.EncodeToBytes(acc)
accTrie.Update([]byte("acc-1"), val) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e
// Identical in the snap
@ -568,7 +568,7 @@ func TestGenerateWithExtraAccounts(t *testing.T) {
rawdb.WriteStorageSnapshot(diskdb, key, hashData([]byte("key-5")), []byte("val-5"))
}
{ // Account two exists only in the snapshot
acc := &Account{Balance: big.NewInt(1), Root: stTrie.Hash().Bytes(), CodeHash: emptyCode.Bytes()}
acc := &Account{Balance: big.NewInt(1), Root: stTrie.Hash().Bytes(), KeccakCodeHash: emptyKeccakCode.Bytes(), PoseidonCodeHash: emptyPoseidonCode.Bytes(), CodeSize: 0}
val, _ := rlp.EncodeToBytes(acc)
key := hashData([]byte("acc-2"))
rawdb.WriteAccountSnapshot(diskdb, key, val)
@ -619,7 +619,7 @@ func TestGenerateWithManyExtraAccounts(t *testing.T) {
)
accTrie, _ := trie.NewSecure(common.Hash{}, triedb)
{ // Account one in the trie
acc := &Account{Balance: big.NewInt(1), Root: stTrie.Hash().Bytes(), CodeHash: emptyCode.Bytes()}
acc := &Account{Balance: big.NewInt(1), Root: stTrie.Hash().Bytes(), KeccakCodeHash: emptyKeccakCode.Bytes(), PoseidonCodeHash: emptyPoseidonCode.Bytes(), CodeSize: 0}
val, _ := rlp.EncodeToBytes(acc)
accTrie.Update([]byte("acc-1"), val) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e
// Identical in the snap
@ -631,8 +631,8 @@ func TestGenerateWithManyExtraAccounts(t *testing.T) {
}
{ // 100 accounts exist only in snapshot
for i := 0; i < 1000; i++ {
//acc := &Account{Balance: big.NewInt(int64(i)), Root: stTrie.Hash().Bytes(), CodeHash: emptyCode.Bytes()}
acc := &Account{Balance: big.NewInt(int64(i)), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()}
//acc := &Account{Balance: big.NewInt(int64(i)), Root: stTrie.Hash().Bytes(), PoseidonCodeHash: emptyPoseidonCode.Bytes()}
acc := &Account{Balance: big.NewInt(int64(i)), Root: emptyRoot.Bytes(), KeccakCodeHash: emptyKeccakCode.Bytes(), PoseidonCodeHash: emptyPoseidonCode.Bytes(), CodeSize: 0}
val, _ := rlp.EncodeToBytes(acc)
key := hashData([]byte(fmt.Sprintf("acc-%d", i)))
rawdb.WriteAccountSnapshot(diskdb, key, val)
@ -677,7 +677,7 @@ func TestGenerateWithExtraBeforeAndAfter(t *testing.T) {
)
accTrie, _ := trie.New(common.Hash{}, triedb)
{
acc := &Account{Balance: big.NewInt(1), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()}
acc := &Account{Balance: big.NewInt(1), Root: emptyRoot.Bytes(), KeccakCodeHash: emptyKeccakCode.Bytes(), PoseidonCodeHash: emptyPoseidonCode.Bytes(), CodeSize: 0}
val, _ := rlp.EncodeToBytes(acc)
accTrie.Update(common.HexToHash("0x03").Bytes(), val)
accTrie.Update(common.HexToHash("0x07").Bytes(), val)
@ -723,7 +723,7 @@ func TestGenerateWithMalformedSnapdata(t *testing.T) {
)
accTrie, _ := trie.New(common.Hash{}, triedb)
{
acc := &Account{Balance: big.NewInt(1), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()}
acc := &Account{Balance: big.NewInt(1), Root: emptyRoot.Bytes(), KeccakCodeHash: emptyKeccakCode.Bytes(), PoseidonCodeHash: emptyPoseidonCode.Bytes(), CodeSize: 0}
val, _ := rlp.EncodeToBytes(acc)
accTrie.Update(common.HexToHash("0x03").Bytes(), val)
@ -767,7 +767,7 @@ func TestGenerateFromEmptySnap(t *testing.T) {
// Add 1K accounts to the trie
for i := 0; i < 400; i++ {
helper.addTrieAccount(fmt.Sprintf("acc-%d", i),
&Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()})
&Account{Balance: big.NewInt(1), Root: stRoot, KeccakCodeHash: emptyKeccakCode.Bytes(), PoseidonCodeHash: emptyPoseidonCode.Bytes(), CodeSize: 0})
}
root, snap := helper.Generate()
t.Logf("Root: %#x\n", root) // Root: 0x6f7af6d2e1a1bf2b84a3beb3f8b64388465fbc1e274ca5d5d3fc787ca78f59e4
@ -804,7 +804,7 @@ func TestGenerateWithIncompleteStorage(t *testing.T) {
// on the sensitive spots at the boundaries
for i := 0; i < 8; i++ {
accKey := fmt.Sprintf("acc-%d", i)
helper.addAccount(accKey, &Account{Balance: big.NewInt(int64(i)), Root: stRoot, CodeHash: emptyCode.Bytes()})
helper.addAccount(accKey, &Account{Balance: big.NewInt(int64(i)), Root: stRoot, KeccakCodeHash: emptyKeccakCode.Bytes(), PoseidonCodeHash: emptyPoseidonCode.Bytes(), CodeSize: 0})
var moddedKeys []string
var moddedVals []string
for ii := 0; ii < 8; ii++ {

View file

@ -44,10 +44,12 @@ func randomHash() common.Hash {
func randomAccount() []byte {
root := randomHash()
a := Account{
Balance: big.NewInt(rand.Int63()),
Nonce: rand.Uint64(),
Root: root[:],
CodeHash: emptyCode[:],
Balance: big.NewInt(rand.Int63()),
Nonce: rand.Uint64(),
Root: root[:],
KeccakCodeHash: emptyKeccakCode[:],
PoseidonCodeHash: emptyPoseidonCode[:],
CodeSize: 0,
}
data, _ := rlp.EncodeToBytes(a)
return data

View file

@ -31,7 +31,8 @@ import (
"github.com/scroll-tech/go-ethereum/rlp"
)
var emptyCodeHash = codehash.EmptyCodeHash.Bytes()
var emptyPoseidonCodeHash = codehash.EmptyPoseidonCodeHash.Bytes()
var emptyKeccakCodeHash = codehash.EmptyKeccakCodeHash.Bytes()
type Code []byte
@ -96,7 +97,8 @@ type stateObject struct {
// empty returns whether the account is considered empty.
func (s *stateObject) empty() bool {
return s.data.Nonce == 0 && s.data.Balance.Sign() == 0 && bytes.Equal(s.data.CodeHash, emptyCodeHash)
// note: if KeccakCodeHash is empty then PoseidonCodeHash and CodeSize will also be empty
return s.data.Nonce == 0 && s.data.Balance.Sign() == 0 && bytes.Equal(s.data.KeccakCodeHash, emptyKeccakCodeHash)
}
// newObject creates a state object.
@ -104,8 +106,10 @@ func newObject(db *StateDB, address common.Address, data types.StateAccount) *st
if data.Balance == nil {
data.Balance = new(big.Int)
}
if data.CodeHash == nil {
data.CodeHash = emptyCodeHash
if data.KeccakCodeHash == nil {
data.KeccakCodeHash = emptyKeccakCodeHash
data.PoseidonCodeHash = emptyPoseidonCodeHash
data.CodeSize = 0
}
if data.Root == (common.Hash{}) {
data.Root = db.db.TrieDB().EmptyRoot()
@ -482,12 +486,12 @@ func (s *stateObject) Code(db Database) []byte {
if s.code != nil {
return s.code
}
if bytes.Equal(s.CodeHash(), emptyCodeHash) {
if bytes.Equal(s.KeccakCodeHash(), emptyKeccakCodeHash) {
return nil
}
code, err := db.ContractCode(s.addrHash, common.BytesToHash(s.CodeHash()))
code, err := db.ContractCode(s.addrHash, common.BytesToHash(s.KeccakCodeHash()))
if err != nil {
s.setError(fmt.Errorf("can't load code hash %x: %v", s.CodeHash(), err))
s.setError(fmt.Errorf("can't load code hash %x: %v", s.KeccakCodeHash(), err))
}
s.code = code
return code
@ -496,33 +500,24 @@ func (s *stateObject) Code(db Database) []byte {
// CodeSize returns the size of the contract code associated with this object,
// or zero if none. This method is an almost mirror of Code, but uses a cache
// inside the database to avoid loading codes seen recently.
func (s *stateObject) CodeSize(db Database) int {
if s.code != nil {
return len(s.code)
}
if bytes.Equal(s.CodeHash(), emptyCodeHash) {
return 0
}
size, err := db.ContractCodeSize(s.addrHash, common.BytesToHash(s.CodeHash()))
if err != nil {
s.setError(fmt.Errorf("can't load code size %x: %v", s.CodeHash(), err))
}
return size
func (s *stateObject) CodeSize() uint64 {
return s.data.CodeSize
}
func (s *stateObject) SetCode(codeHash common.Hash, code []byte) {
func (s *stateObject) SetCode(code []byte) {
prevcode := s.Code(s.db.db)
s.db.journal.append(codeChange{
account: &s.address,
prevhash: s.CodeHash(),
prevcode: prevcode,
})
s.setCode(codeHash, code)
s.setCode(code)
}
func (s *stateObject) setCode(codeHash common.Hash, code []byte) {
func (s *stateObject) setCode(code []byte) {
s.code = code
s.data.CodeHash = codeHash[:]
s.data.KeccakCodeHash = codehash.KeccakCodeHash(code).Bytes()
s.data.PoseidonCodeHash = codehash.PoseidonCodeHash(code).Bytes()
s.data.CodeSize = uint64(len(code))
s.dirtyCode = true
}
@ -538,8 +533,12 @@ func (s *stateObject) setNonce(nonce uint64) {
s.data.Nonce = nonce
}
func (s *stateObject) CodeHash() []byte {
return s.data.CodeHash
func (s *stateObject) PoseidonCodeHash() []byte {
return s.data.PoseidonCodeHash
}
func (s *stateObject) KeccakCodeHash() []byte {
return s.data.KeccakCodeHash
}
func (s *stateObject) Balance() *big.Int {

View file

@ -23,7 +23,6 @@ import (
"github.com/scroll-tech/go-ethereum/common"
"github.com/scroll-tech/go-ethereum/core/rawdb"
"github.com/scroll-tech/go-ethereum/crypto/codehash"
"github.com/scroll-tech/go-ethereum/ethdb"
)
@ -47,7 +46,7 @@ func TestDump(t *testing.T) {
obj1 := s.state.GetOrNewStateObject(common.BytesToAddress([]byte{0x01}))
obj1.AddBalance(big.NewInt(22))
obj2 := s.state.GetOrNewStateObject(common.BytesToAddress([]byte{0x01, 0x02}))
obj2.SetCode(codehash.CodeHash([]byte{3, 3, 3, 3, 3, 3, 3}), []byte{3, 3, 3, 3, 3, 3, 3})
obj2.SetCode([]byte{3, 3, 3, 3, 3, 3, 3})
obj3 := s.state.GetOrNewStateObject(common.BytesToAddress([]byte{0x02}))
obj3.SetBalance(big.NewInt(44))
@ -59,27 +58,33 @@ func TestDump(t *testing.T) {
// check that DumpToCollector contains the state objects that are in trie
got := string(s.state.Dump(nil))
want := `{
"root": "bfd17853c56ac63be7327da432ef90a9b04376d71efede2a60765d2c94704cfe",
"root": "789955993afb9d2a04b957a91be5d7b139aabb60fb7af63df6405021211c13c4",
"accounts": {
"0x0000000000000000000000000000000000000001": {
"balance": "22",
"nonce": 0,
"root": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"codeHash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
"keccakCodeHash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
"poseidonCodeHash": "0x2098f5fb9e239eab3ceac3f27b81e481dc3124d55ffed523a839ee8446b64864",
"codeSize": 0,
"key": "0x1468288056310c82aa4c01a7e12a10f8111a0560e72b700555479031b86c357d"
},
"0x0000000000000000000000000000000000000002": {
"balance": "44",
"nonce": 0,
"root": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"codeHash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
"keccakCodeHash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
"poseidonCodeHash": "0x2098f5fb9e239eab3ceac3f27b81e481dc3124d55ffed523a839ee8446b64864",
"codeSize": 0,
"key": "0xd52688a8f926c816ca1e079067caba944f158e764817b83fc43594370ca9cf62"
},
"0x0000000000000000000000000000000000000102": {
"balance": "0",
"nonce": 0,
"root": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"codeHash": "0x2263940ad476ca23bf01a9b033d65cd6b8bf9b7224a7ef2a4f10b61a2c039083",
"keccakCodeHash": "0x87874902497a5bb968da31a2998d8f22e949d1ef6214bcdedd8bae24cca4b9e3",
"poseidonCodeHash": "0x1f090de833dd6dee7af5ee49f94fd64d1079aee3df47795eaaf2775d6921458c",
"codeSize": 7,
"code": "0x03030303030303",
"key": "0xa17eacbc25cda025e81db9c5c62868822c73ce097cee2a63e33a2e41268358a1"
}
@ -165,7 +170,7 @@ func TestSnapshot2(t *testing.T) {
so0 := state.getStateObject(stateobjaddr0)
so0.SetBalance(big.NewInt(42))
so0.SetNonce(43)
so0.SetCode(codehash.CodeHash([]byte{'c', 'a', 'f', 'e'}), []byte{'c', 'a', 'f', 'e'})
so0.SetCode([]byte{'c', 'a', 'f', 'e'})
so0.suicided = false
so0.deleted = false
state.setStateObject(so0)
@ -177,7 +182,7 @@ func TestSnapshot2(t *testing.T) {
so1 := state.getStateObject(stateobjaddr1)
so1.SetBalance(big.NewInt(52))
so1.SetNonce(53)
so1.SetCode(codehash.CodeHash([]byte{'c', 'a', 'f', 'e', '2'}), []byte{'c', 'a', 'f', 'e', '2'})
so1.SetCode([]byte{'c', 'a', 'f', 'e', '2'})
so1.suicided = true
so1.deleted = true
state.setStateObject(so1)
@ -217,8 +222,14 @@ func compareStateObjects(so0, so1 *stateObject, t *testing.T) {
if so0.data.Root != so1.data.Root {
t.Errorf("Root mismatch: have %x, want %x", so0.data.Root[:], so1.data.Root[:])
}
if !bytes.Equal(so0.CodeHash(), so1.CodeHash()) {
t.Fatalf("CodeHash mismatch: have %v, want %v", so0.CodeHash(), so1.CodeHash())
if !bytes.Equal(so0.KeccakCodeHash(), so1.KeccakCodeHash()) {
t.Fatalf("KeccakCodeHash mismatch: have %v, want %v", so0.KeccakCodeHash(), so1.KeccakCodeHash())
}
if !bytes.Equal(so0.PoseidonCodeHash(), so1.PoseidonCodeHash()) {
t.Fatalf("PoseidonCodeHash mismatch: have %v, want %v", so0.PoseidonCodeHash(), so1.PoseidonCodeHash())
}
if so0.CodeSize() != so1.CodeSize() {
t.Fatalf("CodeSize mismatch: have %v, want %v", so0.CodeSize(), so1.CodeSize())
}
if !bytes.Equal(so0.code, so1.code) {
t.Fatalf("Code mismatch: have %v, want %v", so0.code, so1.code)

View file

@ -31,7 +31,6 @@ import (
"github.com/scroll-tech/go-ethereum/core/state/snapshot"
"github.com/scroll-tech/go-ethereum/core/types"
"github.com/scroll-tech/go-ethereum/crypto"
"github.com/scroll-tech/go-ethereum/crypto/codehash"
"github.com/scroll-tech/go-ethereum/log"
"github.com/scroll-tech/go-ethereum/metrics"
"github.com/scroll-tech/go-ethereum/rlp"
@ -290,20 +289,28 @@ func (s *StateDB) GetCode(addr common.Address) []byte {
return nil
}
func (s *StateDB) GetCodeSize(addr common.Address) int {
func (s *StateDB) GetCodeSize(addr common.Address) uint64 {
stateObject := s.getStateObject(addr)
if stateObject != nil {
return stateObject.CodeSize(s.db)
return stateObject.CodeSize()
}
return 0
}
func (s *StateDB) GetCodeHash(addr common.Address) common.Hash {
func (s *StateDB) GetPoseidonCodeHash(addr common.Address) common.Hash {
stateObject := s.getStateObject(addr)
if stateObject == nil {
return common.Hash{}
}
return common.BytesToHash(stateObject.CodeHash())
return common.BytesToHash(stateObject.PoseidonCodeHash())
}
func (s *StateDB) GetKeccakCodeHash(addr common.Address) common.Hash {
stateObject := s.getStateObject(addr)
if stateObject == nil {
return common.Hash{}
}
return common.BytesToHash(stateObject.KeccakCodeHash())
}
// GetState retrieves a value from the given account's storage trie.
@ -460,7 +467,7 @@ func (s *StateDB) SetNonce(addr common.Address, nonce uint64) {
func (s *StateDB) SetCode(addr common.Address, code []byte) {
stateObject := s.GetOrNewStateObject(addr)
if stateObject != nil {
stateObject.SetCode(codehash.CodeHash(code), code)
stateObject.SetCode(code)
}
}
@ -522,7 +529,7 @@ func (s *StateDB) updateStateObject(obj *stateObject) {
// enough to track account updates at commit time, deletions need tracking
// at transaction boundary level to ensure we capture state clearing.
if s.snap != nil {
s.snapAccounts[obj.addrHash] = snapshot.SlimAccountRLP(obj.data.Nonce, obj.data.Balance, obj.data.Root, obj.data.CodeHash)
s.snapAccounts[obj.addrHash] = snapshot.SlimAccountRLP(obj.data.Nonce, obj.data.Balance, obj.data.Root, obj.data.KeccakCodeHash, obj.data.PoseidonCodeHash, obj.data.CodeSize)
}
}
@ -573,13 +580,17 @@ func (s *StateDB) getDeletedStateObject(addr common.Address) *stateObject {
return nil
}
data = &types.StateAccount{
Nonce: acc.Nonce,
Balance: acc.Balance,
CodeHash: acc.CodeHash,
Root: common.BytesToHash(acc.Root),
Nonce: acc.Nonce,
Balance: acc.Balance,
Root: common.BytesToHash(acc.Root),
KeccakCodeHash: acc.KeccakCodeHash,
PoseidonCodeHash: acc.PoseidonCodeHash,
CodeSize: acc.CodeSize,
}
if len(data.CodeHash) == 0 {
data.CodeHash = emptyCodeHash
if len(data.KeccakCodeHash) == 0 {
data.KeccakCodeHash = emptyKeccakCodeHash
data.PoseidonCodeHash = emptyPoseidonCodeHash
data.CodeSize = 0
}
if data.Root == (common.Hash{}) {
data.Root = s.db.TrieDB().EmptyRoot()
@ -969,7 +980,7 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) {
if obj := s.stateObjects[addr]; !obj.deleted {
// Write any contract code associated with the state object
if obj.code != nil && obj.dirtyCode {
rawdb.WriteCode(codeWriter, common.BytesToHash(obj.CodeHash()), obj.code)
rawdb.WriteCode(codeWriter, common.BytesToHash(obj.KeccakCodeHash()), obj.code)
obj.dirtyCode = false
}
// Write any storage changes in the state object to its storage trie

View file

@ -443,7 +443,8 @@ func (test *snapshotTest) checkEqual(state, checkstate *StateDB) error {
checkeq("GetBalance", state.GetBalance(addr), checkstate.GetBalance(addr))
checkeq("GetNonce", state.GetNonce(addr), checkstate.GetNonce(addr))
checkeq("GetCode", state.GetCode(addr), checkstate.GetCode(addr))
checkeq("GetCodeHash", state.GetCodeHash(addr), checkstate.GetCodeHash(addr))
checkeq("GetKeccakCodeHash", state.GetKeccakCodeHash(addr), checkstate.GetKeccakCodeHash(addr))
checkeq("GetPoseidonCodeHash", state.GetPoseidonCodeHash(addr), checkstate.GetPoseidonCodeHash(addr))
checkeq("GetCodeSize", state.GetCodeSize(addr), checkstate.GetCodeSize(addr))
// Check storage.
if obj := state.getStateObject(addr); obj != nil {

View file

@ -49,7 +49,7 @@ func NewStateSync(root common.Hash, database ethdb.KeyValueReader, bloom *trie.S
return err
}
syncer.AddSubTrie(obj.Root, hexpath, parent, onSlot)
syncer.AddCodeEntry(common.BytesToHash(obj.CodeHash), hexpath, parent)
syncer.AddCodeEntry(common.BytesToHash(obj.KeccakCodeHash), hexpath, parent)
return nil
}
syncer = trie.NewSync(root, database, onAccount, bloom)

View file

@ -59,12 +59,12 @@ func makeTestState() (Database, common.Hash, []*testAccount) {
acc.nonce = uint64(42 * i)
if i%3 == 0 {
obj.SetCode(codehash.CodeHash([]byte{i, i, i, i, i}), []byte{i, i, i, i, i})
obj.SetCode([]byte{i, i, i, i, i})
acc.code = []byte{i, i, i, i, i}
}
if i%5 == 0 {
for j := byte(0); j < 5; j++ {
hash := codehash.CodeHash([]byte{i, i, i, i, i, j, j})
hash := codehash.KeccakCodeHash([]byte{i, i, i, i, i, j, j})
obj.SetState(db, hash, hash)
}
}
@ -408,10 +408,10 @@ func TestIncompleteStateSync(t *testing.T) {
var isCode = make(map[common.Hash]struct{})
for _, acc := range srcAccounts {
if len(acc.code) > 0 {
isCode[codehash.CodeHash(acc.code)] = struct{}{}
isCode[codehash.KeccakCodeHash(acc.code)] = struct{}{}
}
}
isCode[common.BytesToHash(emptyCodeHash)] = struct{}{}
isCode[common.BytesToHash(emptyKeccakCodeHash)] = struct{}{}
checkTrieConsistency(srcDb.TrieDB().DiskDB().(ethdb.Database), srcRoot)
// Create a destination state and sync with the scheduler

View file

@ -285,7 +285,7 @@ func TestStateProcessorErrors(t *testing.T) {
txs: []*types.Transaction{
mkDynamicTx(0, common.Address{}, params.TxGas-1000, big.NewInt(0), big.NewInt(0)),
},
want: "could not apply tx 0 [0x88626ac0d53cb65308f2416103c62bb1f18b805573d4f96a3640bbbfff13c14f]: sender not an eoa: address 0x71562b71999873DB5b286dF957af199Ec94617F7, codehash: 0x14644f8304e8c7052dee61ac235af61e12e25a730d13beccac8b3b72f5705874",
want: "could not apply tx 0 [0x88626ac0d53cb65308f2416103c62bb1f18b805573d4f96a3640bbbfff13c14f]: sender not an eoa: address 0x71562b71999873DB5b286dF957af199Ec94617F7, codehash: 0x9280914443471259d4570a8661015ae4a5b80186dbc619658fb494bebc3da3d1",
},
} {
block := GenerateBadBlock(genesis, ethash.NewFaker(), tt.txs, gspec.Config)

View file

@ -29,7 +29,7 @@ import (
"github.com/scroll-tech/go-ethereum/params"
)
var emptyCodeHash = codehash.EmptyCodeHash
var emptyKeccakCodeHash = codehash.EmptyKeccakCodeHash
/*
The State Transitioning Model
@ -227,7 +227,7 @@ func (st *StateTransition) preCheck() error {
st.msg.From().Hex(), stNonce)
}
// Make sure the sender is an EOA
if codeHash := st.state.GetCodeHash(st.msg.From()); codeHash != emptyCodeHash && codeHash != (common.Hash{}) {
if codeHash := st.state.GetKeccakCodeHash(st.msg.From()); codeHash != emptyKeccakCodeHash && codeHash != (common.Hash{}) {
return fmt.Errorf("%w: address %v, codehash: %s", ErrSenderNoEOA,
st.msg.From().Hex(), codeHash)
}

View file

@ -66,8 +66,8 @@ type ExecutionResult struct {
// currently they are just `from` and `to` account
AccountsAfter []*AccountWrapper `json:"accountAfter"`
// `CodeHash` only exists when tx is a contract call.
CodeHash *common.Hash `json:"codeHash,omitempty"`
// `PoseidonCodeHash` only exists when tx is a contract call.
PoseidonCodeHash *common.Hash `json:"poseidonCodeHash,omitempty"`
// If it is a contract call, the contract code is returned.
ByteCode string `json:"byteCode,omitempty"`
StructLogs []*StructLogRes `json:"structLogs"`
@ -134,11 +134,13 @@ type ExtraData struct {
}
type AccountWrapper struct {
Address common.Address `json:"address"`
Nonce uint64 `json:"nonce"`
Balance *hexutil.Big `json:"balance"`
CodeHash common.Hash `json:"codeHash,omitempty"`
Storage *StorageWrapper `json:"storage,omitempty"` // StorageWrapper can be empty if irrelated to storage operation
Address common.Address `json:"address"`
Nonce uint64 `json:"nonce"`
Balance *hexutil.Big `json:"balance"`
KeccakCodeHash common.Hash `json:"keccakCodeHash,omitempty"`
PoseidonCodeHash common.Hash `json:"poseidonCodeHash,omitempty"`
CodeSize uint64 `json:"codeSize"`
Storage *StorageWrapper `json:"storage,omitempty"` // StorageWrapper can be empty if irrelated to storage operation
}
// while key & value can also be retrieved from StructLogRes.Storage,

View file

@ -25,8 +25,12 @@ import (
// StateAccount is the Ethereum consensus representation of accounts.
// These objects are stored in the main account trie.
type StateAccount struct {
Nonce uint64
Balance *big.Int
Root common.Hash // merkle root of the storage trie
CodeHash []byte
Nonce uint64
Balance *big.Int
Root common.Hash // merkle root of the storage trie
KeccakCodeHash []byte
// StateAccount Scroll extensions
PoseidonCodeHash []byte
CodeSize uint64
}

View file

@ -21,7 +21,6 @@ import (
"errors"
"math/big"
"github.com/iden3/go-iden3-crypto/poseidon"
"github.com/iden3/go-iden3-crypto/utils"
zkt "github.com/scroll-tech/zktrie/types"
@ -33,73 +32,74 @@ var (
ErrInvalidLength = errors.New("StateAccount: invalid input length")
)
// Hash of StateAccount
// AccountHash = Hash(
// Hash(nonce, balance),
// Hash(
// Root,
// Hash(codeHashFirst16, codeHashLast16)
// ))
func (s *StateAccount) Hash() (*big.Int, error) {
nonce := new(big.Int).SetUint64(s.Nonce)
if s.Balance == nil {
s.Balance = new(big.Int)
}
hash1, err := poseidon.Hash([]*big.Int{nonce, s.Balance})
if err != nil {
return nil, err
}
codeHashFirst16 := new(big.Int).SetBytes(s.CodeHash[0:16])
codeHashLast16 := new(big.Int).SetBytes(s.CodeHash[16:32])
hash2, err := poseidon.Hash([]*big.Int{codeHashFirst16, codeHashLast16})
if err != nil {
return nil, err
}
rootHash := zkt.NewHashFromBytes(s.Root.Bytes())
hash3, err := poseidon.Hash([]*big.Int{hash2, rootHash.BigInt()})
if err != nil {
return nil, err
}
hash4, err := poseidon.Hash([]*big.Int{hash1, hash3})
if err != nil {
return nil, err
}
return hash4, nil
}
// MarshalFields, the bytes scheme is:
// [0:32] Nonce uint64 big-endian in 32 byte
// MarshalFields marshalls a StateAccount into a sequence of bytes. The bytes scheme is:
// [0:32] (bytes in big-endian)
// [0:16] Reserved with all 0
// [16:24] CodeSize, uint64 in big-endian
// [24:32] Nonce, uint64 in big-endian
// [32:64] Balance
// [64:96] Root
// [96:128] CodeHash
// [64:96] StorageRoot
// [96:128] KeccakCodeHash
// [128:160] PoseidonCodehash
// (total 160 bytes)
func (s *StateAccount) MarshalFields() ([]zkt.Byte32, uint32) {
fields := make([]zkt.Byte32, 4)
binary.BigEndian.PutUint64(fields[0][24:], s.Nonce)
fields := make([]zkt.Byte32, 5)
if s.Balance == nil {
panic("StateAccount balance nil")
}
if !utils.CheckBigIntInField(s.Balance) {
panic("balance overflow")
panic("StateAccount balance overflow")
}
s.Balance.FillBytes(fields[1][:])
copy(fields[2][:], s.CodeHash)
copy(fields[3][:], s.Root.Bytes())
return fields, 4
if !utils.CheckBigIntInField(s.Root.Big()) {
panic("StateAccount root overflow")
}
if !utils.CheckBigIntInField(new(big.Int).SetBytes(s.PoseidonCodeHash)) {
panic("StateAccount poseidonCodeHash overflow")
}
binary.BigEndian.PutUint64(fields[0][16:], s.CodeSize)
binary.BigEndian.PutUint64(fields[0][24:], s.Nonce)
s.Balance.FillBytes(fields[1][:])
copy(fields[2][:], s.Root.Bytes())
copy(fields[3][:], s.KeccakCodeHash)
copy(fields[4][:], s.PoseidonCodeHash)
// The returned flag shows which items cannot be encoded as field elements.
// KeccakCodeHash can be larger than the field size so we set the 3rd (LSB) bit to 1.
//
// +---+---+---+---+---+
// | 0 | 1 | 2 | 3 | 4 |
// +---+---+---+---+---+
// 0 0 0 1 0
flag := uint32(8)
return fields, flag
}
func UnmarshalStateAccount(bytes []byte) (*StateAccount, error) {
if len(bytes) != 128 {
if len(bytes) != 160 {
return nil, ErrInvalidLength
}
acc := new(StateAccount)
acc.Nonce = binary.BigEndian.Uint64(bytes[24:])
acc.CodeSize = binary.BigEndian.Uint64(bytes[16:24])
acc.Nonce = binary.BigEndian.Uint64(bytes[24:32])
acc.Balance = new(big.Int).SetBytes(bytes[32:64])
acc.CodeHash = make([]byte, 32)
copy(acc.CodeHash, bytes[64:96])
acc.Root = common.Hash{}
acc.Root.SetBytes(bytes[96:128])
acc.Root.SetBytes(bytes[64:96])
acc.KeccakCodeHash = make([]byte, 32)
copy(acc.KeccakCodeHash, bytes[96:128])
acc.PoseidonCodeHash = make([]byte, 32)
copy(acc.PoseidonCodeHash, bytes[128:160])
return acc, nil
}

View file

@ -1,45 +1,189 @@
package types
import (
"math"
"math/big"
"testing"
zktrie "github.com/scroll-tech/zktrie/types"
"github.com/iden3/go-iden3-crypto/constants"
"github.com/stretchr/testify/assert"
"github.com/scroll-tech/go-ethereum/common"
"github.com/scroll-tech/go-ethereum/crypto/codehash"
)
func TestAccountMarshalling(t *testing.T) {
//ensure the hash scheme consistent with designation
example1 := &StateAccount{
Nonce: 5,
Balance: big.NewInt(0).SetBytes(common.Hex2Bytes("01fffffffffffffffffffffffffffffffffffffffffffffffff9c8672c6bc7b3")),
CodeHash: common.Hex2Bytes("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"),
}
example2 := &StateAccount{
Nonce: 2,
Balance: big.NewInt(0),
CodeHash: common.Hex2Bytes("cc0a77f6e063b4b62eb7d9ed6f427cf687d8d0071d751850cfe5d136bc60d3ab"),
Root: common.HexToHash("22fb59aa5410ed465267023713ab42554c250f394901455a3366e223d5f7d147"),
}
for i, example := range []*StateAccount{example1, example2} {
fields, flag := example.MarshalFields()
h1, err := zktrie.PreHandlingElems(flag, fields)
if err != nil {
t.Fatal(err)
}
h2, err := example.Hash()
if err != nil {
t.Fatal(err)
}
if h1.BigInt().Cmp(h2) != 0 {
t.Errorf("hash <%d> unmatched, expected [%x], get [%x]", i, h2.Bytes(), h1.Bytes())
}
}
func assertAccountsEqual(t *testing.T, expected *StateAccount, actual *StateAccount) {
assert.Equal(t, expected.Nonce, actual.Nonce)
assert.Zero(t, expected.Balance.Cmp(actual.Balance))
assert.Equal(t, expected.Root, actual.Root)
assert.Equal(t, expected.KeccakCodeHash, actual.KeccakCodeHash)
assert.Equal(t, expected.PoseidonCodeHash, actual.PoseidonCodeHash)
assert.Equal(t, expected.CodeSize, actual.CodeSize)
}
func TestMarshalUnmarshalEmptyAccount(t *testing.T) {
acc := StateAccount{
Nonce: 0,
Balance: big.NewInt(0),
Root: common.Hash{},
KeccakCodeHash: codehash.EmptyKeccakCodeHash.Bytes(),
PoseidonCodeHash: codehash.EmptyPoseidonCodeHash.Bytes(),
CodeSize: 0,
}
// marshal account
bytes, flag := acc.MarshalFields()
assert.Equal(t, 5, len(bytes))
assert.Equal(t, uint32(8), flag)
assert.Equal(t, common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000000"), bytes[0].Bytes())
assert.Equal(t, common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000000"), bytes[1].Bytes())
assert.Equal(t, common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000000"), bytes[2].Bytes())
assert.Equal(t, common.Hex2Bytes("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"), bytes[3].Bytes())
assert.Equal(t, common.Hex2Bytes("2098f5fb9e239eab3ceac3f27b81e481dc3124d55ffed523a839ee8446b64864"), bytes[4].Bytes())
// unmarshal account
flatBytes := []byte("")
for _, item := range bytes {
flatBytes = append(flatBytes, item.Bytes()...)
}
acc2, err := UnmarshalStateAccount(flatBytes)
assert.Nil(t, err)
assertAccountsEqual(t, &acc, acc2)
}
func TestMarshalUnmarshalZeroAccount(t *testing.T) {
acc := StateAccount{
Nonce: 0,
Balance: big.NewInt(0),
Root: common.Hash{},
KeccakCodeHash: make([]byte, 0),
PoseidonCodeHash: make([]byte, 0),
CodeSize: 0,
}
// marshal account
bytes, flag := acc.MarshalFields()
assert.Equal(t, 5, len(bytes))
assert.Equal(t, uint32(8), flag)
assert.Equal(t, common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000000"), bytes[0].Bytes())
assert.Equal(t, common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000000"), bytes[1].Bytes())
assert.Equal(t, common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000000"), bytes[2].Bytes())
assert.Equal(t, common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000000"), bytes[3].Bytes())
assert.Equal(t, common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000000"), bytes[4].Bytes())
}
func TestMarshalUnmarshalNonEmptyAccount(t *testing.T) {
acc := StateAccount{
Nonce: 0x11111111,
Balance: big.NewInt(0x33333333),
Root: common.HexToHash("123456789abcdef123456789abcdef123456789abcdef123456789abcdef1234"),
KeccakCodeHash: common.Hex2Bytes("1111111111111111111111111111111111111111111111111111111111111111"),
PoseidonCodeHash: common.Hex2Bytes("2222222222222222222222222222222222222222222222222222222222222222"),
CodeSize: 0x22222222,
}
// marshal account
bytes, flag := acc.MarshalFields()
assert.Equal(t, 5, len(bytes))
assert.Equal(t, uint32(8), flag)
assert.Equal(t, common.Hex2Bytes("0000000000000000000000000000000000000000222222220000000011111111"), bytes[0].Bytes())
assert.Equal(t, common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000033333333"), bytes[1].Bytes())
assert.Equal(t, common.Hex2Bytes("123456789abcdef123456789abcdef123456789abcdef123456789abcdef1234"), bytes[2].Bytes())
assert.Equal(t, common.Hex2Bytes("1111111111111111111111111111111111111111111111111111111111111111"), bytes[3].Bytes())
assert.Equal(t, common.Hex2Bytes("2222222222222222222222222222222222222222222222222222222222222222"), bytes[4].Bytes())
// unmarshal account
flatBytes := []byte("")
for _, item := range bytes {
flatBytes = append(flatBytes, item.Bytes()...)
}
acc2, err := UnmarshalStateAccount(flatBytes)
assert.Nil(t, err)
assertAccountsEqual(t, &acc, acc2)
}
func TestMarshalUnmarshalAccountWithMaxFields(t *testing.T) {
maxFieldElement := new(big.Int).Sub(constants.Q, big.NewInt(1))
acc := StateAccount{
Nonce: math.MaxUint64,
Balance: maxFieldElement,
Root: common.BigToHash(maxFieldElement),
KeccakCodeHash: common.Hex2Bytes("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
PoseidonCodeHash: maxFieldElement.Bytes(),
CodeSize: math.MaxUint64,
}
// marshal account
bytes, flag := acc.MarshalFields()
assert.Equal(t, 5, len(bytes))
assert.Equal(t, uint32(8), flag)
assert.Equal(t, common.Hex2Bytes("00000000000000000000000000000000ffffffffffffffffffffffffffffffff"), bytes[0].Bytes())
assert.Equal(t, common.Hex2Bytes("30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000"), bytes[1].Bytes())
assert.Equal(t, common.Hex2Bytes("30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000"), bytes[2].Bytes())
assert.Equal(t, common.Hex2Bytes("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), bytes[3].Bytes())
assert.Equal(t, common.Hex2Bytes("30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000"), bytes[4].Bytes())
// unmarshal account
flatBytes := []byte("")
for _, item := range bytes {
flatBytes = append(flatBytes, item.Bytes()...)
}
acc2, err := UnmarshalStateAccount(flatBytes)
assert.Nil(t, err)
assertAccountsEqual(t, &acc, acc2)
}
func TestMarshalPanic(t *testing.T) {
assert.PanicsWithValue(t, "StateAccount balance nil", func() {
acc := StateAccount{}
acc.MarshalFields()
})
assert.PanicsWithValue(t, "StateAccount balance overflow", func() {
acc := StateAccount{Balance: constants.Q}
acc.MarshalFields()
})
assert.PanicsWithValue(t, "StateAccount balance overflow", func() {
balance := new(big.Int)
balance, ok := balance.SetString("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16)
assert.True(t, ok)
acc := StateAccount{Balance: balance}
acc.MarshalFields()
})
assert.PanicsWithValue(t, "StateAccount root overflow", func() {
acc := StateAccount{Balance: big.NewInt(0), Root: common.BigToHash(constants.Q)}
acc.MarshalFields()
})
assert.PanicsWithValue(t, "StateAccount poseidonCodeHash overflow", func() {
acc := StateAccount{Balance: big.NewInt(0), PoseidonCodeHash: constants.Q.Bytes()}
acc.MarshalFields()
})
}

View file

@ -55,7 +55,7 @@ type Contract struct {
analysis bitvec // Locally cached result of JUMPDEST analysis
Code []byte
CodeHash common.Hash
CodeHash common.Hash // Keccak code hash
CodeAddr *common.Address
Input []byte

View file

@ -29,9 +29,9 @@ import (
"github.com/scroll-tech/go-ethereum/params"
)
// emptyCodeHash is used by create to ensure deployment is disallowed to already
// emptyKeccakCodeHash is used by create to ensure deployment is disallowed to already
// deployed contract addresses (relevant after the account abstraction).
var emptyCodeHash = codehash.EmptyCodeHash
var emptyKeccakCodeHash = codehash.EmptyKeccakCodeHash
type (
// CanTransferFunc is the signature of a transfer guard function
@ -229,7 +229,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
// If the account has no code, we can abort here
// The depth-check is already done, and precompiles handled above
contract := NewContract(caller, AccountRef(addrCopy), value, gas)
contract.SetCallCode(&addrCopy, evm.StateDB.GetCodeHash(addrCopy), code)
contract.SetCallCode(&addrCopy, evm.StateDB.GetKeccakCodeHash(addrCopy), code)
ret, err = evm.interpreter.Run(contract, input, false)
gas = contract.Gas
}
@ -289,7 +289,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
// Initialise a new contract and set the code that is to be used by the EVM.
// The contract is a scoped environment for this execution context only.
contract := NewContract(caller, AccountRef(caller.Address()), value, gas)
contract.SetCallCode(&addrCopy, evm.StateDB.GetCodeHash(addrCopy), evm.StateDB.GetCode(addrCopy))
contract.SetCallCode(&addrCopy, evm.StateDB.GetKeccakCodeHash(addrCopy), evm.StateDB.GetCode(addrCopy))
ret, err = evm.interpreter.Run(contract, input, false)
gas = contract.Gas
}
@ -332,7 +332,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
addrCopy := addr
// Initialise a new contract and make initialise the delegate values
contract := NewContract(caller, AccountRef(caller.Address()), nil, gas).AsDelegate()
contract.SetCallCode(&addrCopy, evm.StateDB.GetCodeHash(addrCopy), evm.StateDB.GetCode(addrCopy))
contract.SetCallCode(&addrCopy, evm.StateDB.GetKeccakCodeHash(addrCopy), evm.StateDB.GetCode(addrCopy))
ret, err = evm.interpreter.Run(contract, input, false)
gas = contract.Gas
}
@ -388,7 +388,7 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte
// Initialise a new contract and set the code that is to be used by the EVM.
// The contract is a scoped environment for this execution context only.
contract := NewContract(caller, AccountRef(addrCopy), new(big.Int), gas)
contract.SetCallCode(&addrCopy, evm.StateDB.GetCodeHash(addrCopy), evm.StateDB.GetCode(addrCopy))
contract.SetCallCode(&addrCopy, evm.StateDB.GetKeccakCodeHash(addrCopy), evm.StateDB.GetCode(addrCopy))
// When an error was returned by the EVM or when setting the creation code
// above we revert to the snapshot and consume any gas remaining. Additionally
// when we're in Homestead this also counts for code storage gas errors.
@ -438,8 +438,8 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
evm.StateDB.AddAddressToAccessList(address)
}
// Ensure there's no existing contract already at the designated address
contractHash := evm.StateDB.GetCodeHash(address)
if evm.StateDB.GetNonce(address) != 0 || (contractHash != (common.Hash{}) && contractHash != emptyCodeHash) {
contractHash := evm.StateDB.GetKeccakCodeHash(address)
if evm.StateDB.GetNonce(address) != 0 || (contractHash != (common.Hash{}) && contractHash != emptyKeccakCodeHash) {
return nil, common.Address{}, 0, ErrContractAddressCollision
}
// Create a new account on the state

View file

@ -342,7 +342,7 @@ func opReturnDataCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeConte
func opExtCodeSize(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
slot := scope.Stack.peek()
slot.SetUint64(uint64(interpreter.evm.StateDB.GetCodeSize(slot.Bytes20())))
slot.SetUint64(interpreter.evm.StateDB.GetCodeSize(slot.Bytes20()))
return nil, nil
}
@ -420,7 +420,7 @@ func opExtCodeHash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext)
if interpreter.evm.StateDB.Empty(address) {
slot.Clear()
} else {
slot.SetBytes(interpreter.evm.StateDB.GetCodeHash(address).Bytes())
slot.SetBytes(interpreter.evm.StateDB.GetKeccakCodeHash(address).Bytes())
}
return nil, nil
}

View file

@ -34,10 +34,11 @@ type StateDB interface {
GetNonce(common.Address) uint64
SetNonce(common.Address, uint64)
GetCodeHash(common.Address) common.Hash
GetKeccakCodeHash(common.Address) common.Hash
GetCode(common.Address) []byte
SetCode(common.Address, []byte)
GetCodeSize(common.Address) int
GetPoseidonCodeHash(common.Address) common.Hash
GetCodeSize(common.Address) uint64
AddRefund(uint64)
SubRefund(uint64)

View file

@ -104,19 +104,23 @@ func traceLastNAddressAccount(n int) traceFunc {
// StorageWrapper will be empty
func getWrappedAccountForAddr(l *StructLogger, address common.Address) *types.AccountWrapper {
return &types.AccountWrapper{
Address: address,
Nonce: l.env.StateDB.GetNonce(address),
Balance: (*hexutil.Big)(l.env.StateDB.GetBalance(address)),
CodeHash: l.env.StateDB.GetCodeHash(address),
Address: address,
Nonce: l.env.StateDB.GetNonce(address),
Balance: (*hexutil.Big)(l.env.StateDB.GetBalance(address)),
KeccakCodeHash: l.env.StateDB.GetKeccakCodeHash(address),
PoseidonCodeHash: l.env.StateDB.GetPoseidonCodeHash(address),
CodeSize: l.env.StateDB.GetCodeSize(address),
}
}
func getWrappedAccountForStorage(l *StructLogger, address common.Address, key common.Hash) *types.AccountWrapper {
return &types.AccountWrapper{
Address: address,
Nonce: l.env.StateDB.GetNonce(address),
Balance: (*hexutil.Big)(l.env.StateDB.GetBalance(address)),
CodeHash: l.env.StateDB.GetCodeHash(address),
Address: address,
Nonce: l.env.StateDB.GetNonce(address),
Balance: (*hexutil.Big)(l.env.StateDB.GetBalance(address)),
KeccakCodeHash: l.env.StateDB.GetKeccakCodeHash(address),
PoseidonCodeHash: l.env.StateDB.GetPoseidonCodeHash(address),
CodeSize: l.env.StateDB.GetCodeSize(address),
Storage: &types.StorageWrapper{
Key: key.String(),
Value: l.env.StateDB.GetState(address, key).String(),

View file

@ -2,15 +2,22 @@ package codehash
import (
"github.com/scroll-tech/go-ethereum/common"
"github.com/scroll-tech/go-ethereum/crypto"
"github.com/scroll-tech/go-ethereum/crypto/poseidon"
)
var EmptyCodeHash common.Hash
var EmptyPoseidonCodeHash common.Hash
var EmptyKeccakCodeHash common.Hash
func CodeHash(code []byte) (h common.Hash) {
func PoseidonCodeHash(code []byte) (h common.Hash) {
return poseidon.CodeHash(code)
}
func init() {
EmptyCodeHash = poseidon.CodeHash(nil)
func KeccakCodeHash(code []byte) (h common.Hash) {
return crypto.Keccak256Hash(code)
}
func init() {
EmptyPoseidonCodeHash = poseidon.CodeHash(nil)
EmptyKeccakCodeHash = crypto.Keccak256Hash(nil)
}

View file

@ -4,44 +4,40 @@ import (
"math/big"
"github.com/scroll-tech/go-ethereum/common"
"github.com/scroll-tech/go-ethereum/crypto"
)
const defaultPoseidonChunk = 3
const nBytesToFieldElement = 31
func CodeHash(code []byte) (h common.Hash) {
// special case for nil hash
if len(code) == 0 {
return crypto.Keccak256Hash(nil)
}
nBytes := int64(len(code))
cap := int64(len(code))
// step 1: pad code with 0x0 (STOP) so that len(code) % 16 == 0
// step 2: for every 16 bytes, convert to Fr, so that we get a Fr array
var length = (len(code) + 15) / 16
// step 1: pad code with 0x0 (STOP) so that len(code) % nBytesToFieldElement == 0
// step 2: for every nBytesToFieldElement bytes, convert to Fr, so that we get a Fr array
var length = (len(code) + nBytesToFieldElement - 1) / nBytesToFieldElement
Frs := make([]*big.Int, length)
ii := 0
for ii < length-1 {
Frs[ii] = big.NewInt(0)
Frs[ii].SetBytes(code[ii*16 : (ii+1)*16])
Frs[ii].SetBytes(code[ii*nBytesToFieldElement : (ii+1)*nBytesToFieldElement])
ii++
}
Frs[ii] = big.NewInt(0)
bytes := make([]byte, 16)
copy(bytes, code[ii*16:])
Frs[ii].SetBytes(bytes)
if length > 0 {
Frs[ii] = big.NewInt(0)
bytes := make([]byte, nBytesToFieldElement)
copy(bytes, code[ii*nBytesToFieldElement:])
Frs[ii].SetBytes(bytes)
}
// step 3: apply the array onto a sponge process with the current poseidon scheme
// (3 Frs permutation and 1 Fr for output, so the throughout is 2 Frs)
// step 4: convert final root Fr to u256 (big-endian representation)
hash, _ := HashWithCap(Frs, defaultPoseidonChunk, cap)
codeHash := common.Hash{}
hash.FillBytes(codeHash[:])
return codeHash
hash, err := HashWithCap(Frs, defaultPoseidonChunk, nBytes)
if err != nil {
return common.Hash{}
}
return common.BigToHash(hash)
}

View file

@ -8,7 +8,7 @@ import (
func TestPoseidonCodeHash(t *testing.T) {
// nil
got := fmt.Sprintf("%s", CodeHash(nil))
want := "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"
want := "0x2098f5fb9e239eab3ceac3f27b81e481dc3124d55ffed523a839ee8446b64864"
if got != want {
t.Errorf("got %q, wanted %q", got, want)
@ -16,9 +16,27 @@ func TestPoseidonCodeHash(t *testing.T) {
// single byte
got = fmt.Sprintf("%s", CodeHash([]byte{0}))
want = "0x0ee069e6aa796ef0e46cbd51d10468393d443a00f5affe72898d9ab62e335e16"
want = "0x29f94b67ee4e78b2bb08da025f9943c1201a7af025a27600c2dd0a2e71c7cf8b"
if got != want {
t.Errorf("got %q, wanted %q", got, want)
}
got = fmt.Sprintf("%s", CodeHash([]byte{1}))
want = "0x246d3c06960643350a3e2d587fa16315c381635eb5ac1ac4501e195423dbf78e"
if got != want {
t.Errorf("got %q, wanted %q", got, want)
}
// 32 bytes
bytes := make([]byte, 32)
for i := range bytes {
bytes[i] = 1
}
got = fmt.Sprintf("%s", CodeHash(bytes))
want = "0x0b46d156183dffdbed8e6c6b0af139b95c058e735878ca7f4dca334e0ea8bd20"
if got != want {
t.Errorf("got %q, wanted %q", got, want)
}
}

View file

@ -110,7 +110,7 @@ func Hash(inpBI []*big.Int, width int) (*big.Int, error) {
// Hash using possible sponge specs specified by width (rate from 1 to 15), the size of input is applied as capacity
// (notice we do not include width in the capacity )
func HashWithCap(inpBI []*big.Int, width int, cap int64) (*big.Int, error) {
func HashWithCap(inpBI []*big.Int, width int, nBytes int64) (*big.Int, error) {
if width < 2 {
return nil, fmt.Errorf("width must be ranged from 2 to 16")
}
@ -118,8 +118,13 @@ func HashWithCap(inpBI []*big.Int, width int, cap int64) (*big.Int, error) {
return nil, fmt.Errorf("invalid inputs width %d, max %d", width, len(NROUNDSP)+1) //nolint:gomnd,lll
}
capflag := ff.NewElement().SetBigInt(big.NewInt(cap))
// capflag = nBytes * 2^64
pow64 := big.NewInt(1)
pow64.Lsh(pow64, 64)
capflag := ff.NewElement().SetBigInt(big.NewInt(nBytes))
capflag.Mul(capflag, ff.NewElement().SetBigInt(pow64))
// initialize the state
state := make([]*ff.Element, width)
state[0] = capflag
for i := 1; i < width; i++ {
@ -127,40 +132,20 @@ func HashWithCap(inpBI []*big.Int, width int, cap int64) (*big.Int, error) {
}
rate := width - 1
var absorb []*ff.Element
for len(inpBI) > 0 {
// sponge for fully absorb
if l := len(absorb); l != 0 {
//sanity check
if l != rate {
panic("unexpected absorption size")
}
for i, elm := range absorb {
state[i+1].Add(state[i+1], elm)
}
state = permute(state, width)
i := 0
// always perform one round of permutation even when input is empty
for {
// each round absorb at most `rate` elements from `inpBI`
for j := 0; j < rate && i < len(inpBI); i, j = i+1, j+1 {
state[j+1].Add(state[j+1], ff.NewElement().SetBigInt(inpBI[i]))
}
// absorb
if len(inpBI) < rate {
// padding zero() equal to no action on state
absorb = utils.BigIntArrayToElementArray(inpBI)
inpBI = nil
} else {
absorb = utils.BigIntArrayToElementArray(inpBI[:rate])
inpBI = inpBI[rate:]
state = permute(state, width)
if i == len(inpBI) {
break
}
}
//last time sponge (padding with unabsorb items)
for i, elm := range absorb {
state[i+1].Add(state[i+1], elm)
}
state = permute(state, width)
//squeeze
// squeeze
rE := state[0]
r := big.NewInt(0)
rE.ToBigIntRegular(r)

View file

@ -390,7 +390,7 @@ func handleMessage(backend Backend, peer *Peer) error {
bytes uint64
)
for _, hash := range req.Hashes {
if hash == emptyCode {
if hash == emptyKeccakCodeHash {
// Peers should not request the empty code, but if they do, at
// least sent them back a correct response without db lookups
codes = append(codes, []byte{})

View file

@ -50,8 +50,11 @@ var (
// emptyRoot is the known root hash of an empty trie.
emptyRoot = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
// emptyCode is the known hash of the empty EVM bytecode.
emptyCode = codehash.EmptyCodeHash
// emptyKeccakCodeHash is the known keccak hash of the empty EVM bytecode.
emptyKeccakCodeHash = codehash.EmptyKeccakCodeHash
// emptyPoseidonCodeHash is the known poseidon hash of the empty EVM bytecode.
emptyPoseidonCodeHash = codehash.EmptyPoseidonCodeHash
)
const (
@ -1754,9 +1757,9 @@ func (s *Syncer) processAccountResponse(res *accountResponse) {
res.task.pend = 0
for i, account := range res.accounts {
// Check if the account is a contract with an unknown code
if !bytes.Equal(account.CodeHash, emptyCode[:]) {
if code := rawdb.ReadCodeWithPrefix(s.db, common.BytesToHash(account.CodeHash)); code == nil {
res.task.codeTasks[common.BytesToHash(account.CodeHash)] = struct{}{}
if !bytes.Equal(account.KeccakCodeHash, emptyKeccakCodeHash[:]) {
if code := rawdb.ReadCodeWithPrefix(s.db, common.BytesToHash(account.KeccakCodeHash)); code == nil {
res.task.codeTasks[common.BytesToHash(account.KeccakCodeHash)] = struct{}{}
res.task.needCode[i] = true
res.task.pend++
}
@ -1820,7 +1823,7 @@ func (s *Syncer) processBytecodeResponse(res *bytecodeResponse) {
}
// Code was delivered, mark it not needed any more
for j, account := range res.task.res.accounts {
if res.task.needCode[j] && hash == common.BytesToHash(account.CodeHash) {
if res.task.needCode[j] && hash == common.BytesToHash(account.KeccakCodeHash) {
res.task.needCode[j] = false
res.task.pend--
}
@ -2150,7 +2153,7 @@ func (s *Syncer) forwardAccountTask(task *accountTask) {
if task.needCode[i] || task.needState[i] {
break
}
slim := snapshot.SlimAccountRLP(res.accounts[i].Nonce, res.accounts[i].Balance, res.accounts[i].Root, res.accounts[i].CodeHash)
slim := snapshot.SlimAccountRLP(res.accounts[i].Nonce, res.accounts[i].Balance, res.accounts[i].Root, res.accounts[i].KeccakCodeHash, res.accounts[i].PoseidonCodeHash, res.accounts[i].CodeSize)
rawdb.WriteAccountSnapshot(batch, hash, slim)
// If the task is complete, drop it into the stack trie to generate
@ -2747,7 +2750,7 @@ func (s *Syncer) onHealState(paths [][]byte, value []byte) error {
if err := rlp.DecodeBytes(value, &account); err != nil {
return nil
}
blob := snapshot.SlimAccountRLP(account.Nonce, account.Balance, account.Root, account.CodeHash)
blob := snapshot.SlimAccountRLP(account.Nonce, account.Balance, account.Root, account.KeccakCodeHash, account.PoseidonCodeHash, account.CodeSize)
rawdb.WriteAccountSnapshot(s.stateWriter, common.BytesToHash(paths[0]), blob)
s.accountHealed += 1
s.accountHealedBytes += common.StorageSize(1 + common.HashLength + len(blob))

View file

@ -33,6 +33,7 @@ import (
"github.com/scroll-tech/go-ethereum/core/rawdb"
"github.com/scroll-tech/go-ethereum/core/types"
"github.com/scroll-tech/go-ethereum/crypto"
"github.com/scroll-tech/go-ethereum/crypto/codehash"
"github.com/scroll-tech/go-ethereum/ethdb"
"github.com/scroll-tech/go-ethereum/light"
"github.com/scroll-tech/go-ethereum/log"
@ -1313,7 +1314,7 @@ func key32(i uint64) []byte {
}
var (
codehashes = []common.Hash{
keccakCodehashes = []common.Hash{
crypto.Keccak256Hash([]byte{0}),
crypto.Keccak256Hash([]byte{1}),
crypto.Keccak256Hash([]byte{2}),
@ -1323,20 +1324,37 @@ var (
crypto.Keccak256Hash([]byte{6}),
crypto.Keccak256Hash([]byte{7}),
}
poseidonCodehashes = []common.Hash{
codehash.PoseidonCodeHash([]byte{0}),
codehash.PoseidonCodeHash([]byte{1}),
codehash.PoseidonCodeHash([]byte{2}),
codehash.PoseidonCodeHash([]byte{3}),
codehash.PoseidonCodeHash([]byte{4}),
codehash.PoseidonCodeHash([]byte{5}),
codehash.PoseidonCodeHash([]byte{6}),
codehash.PoseidonCodeHash([]byte{7}),
}
)
// getCodeHash returns a pseudo-random code hash
func getCodeHash(i uint64) []byte {
h := codehashes[int(i)%len(codehashes)]
// getKeccakCodeHash returns a pseudo-random code hash
func getKeccakCodeHash(i uint64) []byte {
h := keccakCodehashes[int(i)%len(keccakCodehashes)]
return common.CopyBytes(h[:])
}
// getPoseidonCodeHash returns a pseudo-random code hash
func getPoseidonCodeHash(i uint64) []byte {
h := poseidonCodehashes[int(i)%len(poseidonCodehashes)]
return common.CopyBytes(h[:])
}
// getCodeByHash convenience function to lookup the code from the code hash
func getCodeByHash(hash common.Hash) []byte {
if hash == emptyCode {
if hash == emptyKeccakCodeHash {
return nil
}
for i, h := range codehashes {
for i, h := range keccakCodehashes {
if h == hash {
return []byte{byte(i)}
}
@ -1351,10 +1369,12 @@ func makeAccountTrieNoStorage(n int) (*trie.Trie, entrySlice) {
var entries entrySlice
for i := uint64(1); i <= uint64(n); i++ {
value, _ := rlp.EncodeToBytes(types.StateAccount{
Nonce: i,
Balance: big.NewInt(int64(i)),
Root: emptyRoot,
CodeHash: getCodeHash(i),
Nonce: i,
Balance: big.NewInt(int64(i)),
Root: emptyRoot,
KeccakCodeHash: getKeccakCodeHash(i),
PoseidonCodeHash: getPoseidonCodeHash(i),
CodeSize: 1,
})
key := key32(i)
elem := &kv{key, value}
@ -1396,10 +1416,12 @@ func makeBoundaryAccountTrie(n int) (*trie.Trie, entrySlice) {
// Fill boundary accounts
for i := 0; i < len(boundaries); i++ {
value, _ := rlp.EncodeToBytes(types.StateAccount{
Nonce: uint64(0),
Balance: big.NewInt(int64(i)),
Root: emptyRoot,
CodeHash: getCodeHash(uint64(i)),
Nonce: uint64(0),
Balance: big.NewInt(int64(i)),
Root: emptyRoot,
KeccakCodeHash: getKeccakCodeHash(uint64(i)),
PoseidonCodeHash: getPoseidonCodeHash(uint64(i)),
CodeSize: 1,
})
elem := &kv{boundaries[i].Bytes(), value}
trie.Update(elem.k, elem.v)
@ -1408,10 +1430,12 @@ func makeBoundaryAccountTrie(n int) (*trie.Trie, entrySlice) {
// Fill other accounts if required
for i := uint64(1); i <= uint64(n); i++ {
value, _ := rlp.EncodeToBytes(types.StateAccount{
Nonce: i,
Balance: big.NewInt(int64(i)),
Root: emptyRoot,
CodeHash: getCodeHash(i),
Nonce: i,
Balance: big.NewInt(int64(i)),
Root: emptyRoot,
KeccakCodeHash: getKeccakCodeHash(i),
PoseidonCodeHash: getPoseidonCodeHash(i),
CodeSize: 1,
})
elem := &kv{key32(i), value}
trie.Update(elem.k, elem.v)
@ -1435,19 +1459,23 @@ func makeAccountTrieWithStorageWithUniqueStorage(accounts, slots int, code bool)
// Create n accounts in the trie
for i := uint64(1); i <= uint64(accounts); i++ {
key := key32(i)
codehash := emptyCode[:]
keccakCodehash := emptyKeccakCodeHash[:]
poseidonCodeHash := emptyPoseidonCodeHash[:]
if code {
codehash = getCodeHash(i)
keccakCodehash = getKeccakCodeHash(i)
poseidonCodeHash = getPoseidonCodeHash(i)
}
// Create a storage trie
stTrie, stEntries := makeStorageTrieWithSeed(uint64(slots), i, db)
stRoot := stTrie.Hash()
stTrie.Commit(nil)
value, _ := rlp.EncodeToBytes(types.StateAccount{
Nonce: i,
Balance: big.NewInt(int64(i)),
Root: stRoot,
CodeHash: codehash,
Nonce: i,
Balance: big.NewInt(int64(i)),
Root: stRoot,
KeccakCodeHash: keccakCodehash,
PoseidonCodeHash: poseidonCodeHash,
CodeSize: 1,
})
elem := &kv{key, value}
accTrie.Update(elem.k, elem.v)
@ -1486,15 +1514,19 @@ func makeAccountTrieWithStorage(accounts, slots int, code, boundary bool) (*trie
// Create n accounts in the trie
for i := uint64(1); i <= uint64(accounts); i++ {
key := key32(i)
codehash := emptyCode[:]
keccakCodehash := emptyKeccakCodeHash[:]
poseidonCodeHash := emptyPoseidonCodeHash[:]
if code {
codehash = getCodeHash(i)
keccakCodehash = getKeccakCodeHash(i)
poseidonCodeHash = getPoseidonCodeHash(i)
}
value, _ := rlp.EncodeToBytes(types.StateAccount{
Nonce: i,
Balance: big.NewInt(int64(i)),
Root: stRoot,
CodeHash: codehash,
Nonce: i,
Balance: big.NewInt(int64(i)),
Root: stRoot,
KeccakCodeHash: keccakCodehash,
PoseidonCodeHash: poseidonCodeHash,
CodeSize: 1,
})
elem := &kv{key, value}
accTrie.Update(elem.k, elem.v)
@ -1594,10 +1626,12 @@ func verifyTrie(db ethdb.KeyValueStore, root common.Hash, t *testing.T) {
accIt := trie.NewIterator(accTrie.NodeIterator(nil))
for accIt.Next() {
var acc struct {
Nonce uint64
Balance *big.Int
Root common.Hash
CodeHash []byte
Nonce uint64
Balance *big.Int
Root common.Hash
KeccakCodeHash []byte
PoseidonCodeHash []byte
CodeSize uint64
}
if err := rlp.DecodeBytes(accIt.Value, &acc); err != nil {
log.Crit("Invalid account encountered during snapshot creation", "err", err)

View file

@ -206,18 +206,22 @@ func (api *API) getTxResult(env *traceEnv, state *state.StateDB, index int, bloc
}
sender := &types.AccountWrapper{
Address: from,
Nonce: state.GetNonce(from),
Balance: (*hexutil.Big)(state.GetBalance(from)),
CodeHash: state.GetCodeHash(from),
Address: from,
Nonce: state.GetNonce(from),
Balance: (*hexutil.Big)(state.GetBalance(from)),
KeccakCodeHash: state.GetKeccakCodeHash(from),
PoseidonCodeHash: state.GetPoseidonCodeHash(from),
CodeSize: state.GetCodeSize(from),
}
var receiver *types.AccountWrapper
if to != nil {
receiver = &types.AccountWrapper{
Address: *to,
Nonce: state.GetNonce(*to),
Balance: (*hexutil.Big)(state.GetBalance(*to)),
CodeHash: state.GetCodeHash(*to),
Address: *to,
Nonce: state.GetNonce(*to),
Balance: (*hexutil.Big)(state.GetBalance(*to)),
KeccakCodeHash: state.GetKeccakCodeHash(*to),
PoseidonCodeHash: state.GetPoseidonCodeHash(*to),
CodeSize: state.GetCodeSize(*to),
}
}
@ -250,10 +254,12 @@ func (api *API) getTxResult(env *traceEnv, state *state.StateDB, index int, bloc
// collect affected account after tx being applied
for _, acc := range []common.Address{from, *to, env.coinbase} {
after = append(after, &types.AccountWrapper{
Address: acc,
Nonce: state.GetNonce(acc),
Balance: (*hexutil.Big)(state.GetBalance(acc)),
CodeHash: state.GetCodeHash(acc),
Address: acc,
Nonce: state.GetNonce(acc),
Balance: (*hexutil.Big)(state.GetBalance(acc)),
KeccakCodeHash: state.GetKeccakCodeHash(acc),
PoseidonCodeHash: state.GetPoseidonCodeHash(acc),
CodeSize: state.GetCodeSize(acc),
})
}
@ -339,10 +345,12 @@ func (api *API) fillBlockTrace(env *traceEnv, block *types.Block) (*types.BlockT
blockTrace := &types.BlockTrace{
Coinbase: &types.AccountWrapper{
Address: env.coinbase,
Nonce: statedb.GetNonce(env.coinbase),
Balance: (*hexutil.Big)(statedb.GetBalance(env.coinbase)),
CodeHash: statedb.GetCodeHash(env.coinbase),
Address: env.coinbase,
Nonce: statedb.GetNonce(env.coinbase),
Balance: (*hexutil.Big)(statedb.GetBalance(env.coinbase)),
KeccakCodeHash: statedb.GetKeccakCodeHash(env.coinbase),
PoseidonCodeHash: statedb.GetPoseidonCodeHash(env.coinbase),
CodeSize: statedb.GetCodeSize(env.coinbase),
},
Header: block.Header(),
StorageTrace: env.StorageTrace,
@ -356,8 +364,8 @@ func (api *API) fillBlockTrace(env *traceEnv, block *types.Block) (*types.BlockT
if len(tx.Data()) != 0 && tx.To() != nil {
evmTrace.ByteCode = hexutil.Encode(statedb.GetCode(*tx.To()))
// Get tx.to address's code hash.
codeHash := statedb.GetCodeHash(*tx.To())
evmTrace.CodeHash = &codeHash
codeHash := statedb.GetPoseidonCodeHash(*tx.To())
evmTrace.PoseidonCodeHash = &codeHash
} else if tx.To() == nil { // Contract is created.
evmTrace.ByteCode = hexutil.Encode(tx.Data())
}

View file

@ -60,13 +60,15 @@ func (ec *Client) CreateAccessList(ctx context.Context, msg ethereum.CallMsg) (*
// AccountResult is the result of a GetProof operation.
type AccountResult struct {
Address common.Address `json:"address"`
AccountProof []string `json:"accountProof"`
Balance *big.Int `json:"balance"`
CodeHash common.Hash `json:"codeHash"`
Nonce uint64 `json:"nonce"`
StorageHash common.Hash `json:"storageHash"`
StorageProof []StorageResult `json:"storageProof"`
Address common.Address `json:"address"`
AccountProof []string `json:"accountProof"`
Balance *big.Int `json:"balance"`
KeccakCodeHash common.Hash `json:"keccakCodeHash"`
PoseidonCodeHash common.Hash `json:"poseidonCodeHash"`
CodeSize common.Hash `json:"codeSize"`
Nonce uint64 `json:"nonce"`
StorageHash common.Hash `json:"storageHash"`
StorageProof []StorageResult `json:"storageProof"`
}
// StorageResult provides a proof for a key-value pair.
@ -87,13 +89,15 @@ func (ec *Client) GetProof(ctx context.Context, account common.Address, keys []s
}
type accountResult struct {
Address common.Address `json:"address"`
AccountProof []string `json:"accountProof"`
Balance *hexutil.Big `json:"balance"`
CodeHash common.Hash `json:"codeHash"`
Nonce hexutil.Uint64 `json:"nonce"`
StorageHash common.Hash `json:"storageHash"`
StorageProof []storageResult `json:"storageProof"`
Address common.Address `json:"address"`
AccountProof []string `json:"accountProof"`
Balance *hexutil.Big `json:"balance"`
KeccakCodeHash common.Hash `json:"keccakodeHash"`
PoseidonCodeHash common.Hash `json:"poseidonCodeHash"`
CodeSize common.Hash `json:"codeSize"`
Nonce hexutil.Uint64 `json:"nonce"`
StorageHash common.Hash `json:"storageHash"`
StorageProof []storageResult `json:"storageProof"`
}
var res accountResult
@ -108,12 +112,14 @@ func (ec *Client) GetProof(ctx context.Context, account common.Address, keys []s
})
}
result := AccountResult{
Address: res.Address,
AccountProof: res.AccountProof,
Balance: res.Balance.ToInt(),
Nonce: uint64(res.Nonce),
CodeHash: res.CodeHash,
StorageHash: res.StorageHash,
Address: res.Address,
AccountProof: res.AccountProof,
Balance: res.Balance.ToInt(),
Nonce: uint64(res.Nonce),
KeccakCodeHash: res.KeccakCodeHash,
PoseidonCodeHash: res.PoseidonCodeHash,
CodeSize: res.CodeSize,
StorageHash: res.StorageHash,
}
return &result, err
}

2
go.mod
View file

@ -49,7 +49,7 @@ require (
github.com/prometheus/tsdb v0.7.1
github.com/rjeczalik/notify v0.9.1
github.com/rs/cors v1.7.0
github.com/scroll-tech/zktrie v0.3.0
github.com/scroll-tech/zktrie v0.4.3
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible
github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4
github.com/stretchr/testify v1.7.0

4
go.sum
View file

@ -380,8 +380,8 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR
github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=
github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/scroll-tech/zktrie v0.3.0 h1:c0GRNELUyAtyuiwllQKT1XjNbs7NRGfguKouiyLfFNY=
github.com/scroll-tech/zktrie v0.3.0/go.mod h1:CuJFlG1/soTJJBAySxCZgTF7oPvd5qF6utHOEciC43Q=
github.com/scroll-tech/zktrie v0.4.3 h1:RyhusIu8F8u5ITmzqZjkAwlL6jdC9TK9i6tfuJoZcpk=
github.com/scroll-tech/zktrie v0.4.3/go.mod h1:XvNo7vAk8yxNyTjBDj5WIiFzYW4bx/gJ78+NK6Zn6Uk=
github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo=
github.com/segmentio/kafka-go v0.2.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=

View file

@ -636,13 +636,15 @@ func (s *PublicBlockChainAPI) GetBalance(ctx context.Context, address common.Add
// Result structs for GetProof
type AccountResult struct {
Address common.Address `json:"address"`
AccountProof []string `json:"accountProof"`
Balance *hexutil.Big `json:"balance"`
CodeHash common.Hash `json:"codeHash"`
Nonce hexutil.Uint64 `json:"nonce"`
StorageHash common.Hash `json:"storageHash"`
StorageProof []StorageResult `json:"storageProof"`
Address common.Address `json:"address"`
AccountProof []string `json:"accountProof"`
Balance *hexutil.Big `json:"balance"`
PoseidonCodeHash common.Hash `json:"poseidonCodeHash"`
KeccakCodeHash common.Hash `json:"keccakCodeHash"`
CodeSize hexutil.Uint64 `json:"codeSize"`
Nonce hexutil.Uint64 `json:"nonce"`
StorageHash common.Hash `json:"storageHash"`
StorageProof []StorageResult `json:"storageProof"`
}
type StorageResult struct {
@ -665,7 +667,8 @@ func (s *PublicBlockChainAPI) GetProof(ctx context.Context, address common.Addre
if !zktrie {
storageHash = types.EmptyRootHash
}
codeHash := state.GetCodeHash(address)
keccakCodeHash := state.GetKeccakCodeHash(address)
poseidonCodeHash := state.GetPoseidonCodeHash(address)
storageProof := make([]StorageResult, len(storageKeys))
// if we have a storageTrie, (which means the account exists), we can update the storagehash
@ -673,7 +676,8 @@ func (s *PublicBlockChainAPI) GetProof(ctx context.Context, address common.Addre
storageHash = storageTrie.Hash()
} else {
// no storageTrie means the account does not exist, so the codeHash is the hash of an empty bytearray.
codeHash = codehash.EmptyCodeHash
keccakCodeHash = codehash.EmptyKeccakCodeHash
poseidonCodeHash = codehash.EmptyPoseidonCodeHash
}
// create the proof for the storageKeys
@ -696,13 +700,15 @@ func (s *PublicBlockChainAPI) GetProof(ctx context.Context, address common.Addre
}
return &AccountResult{
Address: address,
AccountProof: toHexSlice(accountProof),
Balance: (*hexutil.Big)(state.GetBalance(address)),
CodeHash: codeHash,
Nonce: hexutil.Uint64(state.GetNonce(address)),
StorageHash: storageHash,
StorageProof: storageProof,
Address: address,
AccountProof: toHexSlice(accountProof),
Balance: (*hexutil.Big)(state.GetBalance(address)),
KeccakCodeHash: keccakCodeHash,
PoseidonCodeHash: poseidonCodeHash,
CodeSize: hexutil.Uint64(state.GetCodeSize(address)),
Nonce: hexutil.Uint64(state.GetNonce(address)),
StorageHash: storageHash,
StorageProof: storageProof,
}, state.Error()
}

View file

@ -310,9 +310,9 @@ func handleGetCode(msg Decoder) (serveRequestFn, uint64, uint64, error) {
p.bumpInvalid()
continue
}
code, err := bc.StateCache().ContractCode(common.BytesToHash(request.AccKey), common.BytesToHash(account.CodeHash))
code, err := bc.StateCache().ContractCode(common.BytesToHash(request.AccKey), common.BytesToHash(account.KeccakCodeHash))
if err != nil {
p.Log().Warn("Failed to retrieve account code", "block", header.Number, "hash", header.Hash(), "account", common.BytesToHash(request.AccKey), "codehash", common.BytesToHash(account.CodeHash), "err", err)
p.Log().Warn("Failed to retrieve account code", "block", header.Number, "hash", header.Hash(), "account", common.BytesToHash(request.AccKey), "codehash", common.BytesToHash(account.KeccakCodeHash), "err", err)
continue
}
// Accumulate the code and abort if enough data was retrieved

View file

@ -70,7 +70,7 @@ func (db *odrDatabase) CopyTrie(t state.Trie) state.Trie {
}
func (db *odrDatabase) ContractCode(addrHash, codeHash common.Hash) ([]byte, error) {
if codeHash == codehash.EmptyCodeHash {
if codeHash == codehash.EmptyKeccakCodeHash {
return nil, nil
}
code := rawdb.ReadCode(db.backend.Database(), codeHash)

View file

@ -190,7 +190,7 @@ func (s *Sync) AddSubTrie(root common.Hash, path []byte, parent common.Hash, cal
// as is.
func (s *Sync) AddCodeEntry(hash common.Hash, path []byte, parent common.Hash) {
// Short circuit if the entry is empty or already known
if hash == codehash.EmptyCodeHash {
if hash == codehash.EmptyKeccakCodeHash {
return
}
if s.membatch.hasCode(hash) {

View file

@ -593,15 +593,15 @@ func TestTinyTrie(t *testing.T) {
_, accounts := makeAccounts(5)
trie := newEmpty()
trie.Update(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000001337"), accounts[3])
if exp, root := common.HexToHash("8c6a85a4d9fda98feff88450299e574e5378e32391f75a055d470ac0653f1005"), trie.Hash(); exp != root {
if exp, root := common.HexToHash("fc516c51c03bf9f1a0eec6ed6f6f5da743c2745dcd5670007519e6ec056f95a8"), trie.Hash(); exp != root {
t.Errorf("1: got %x, exp %x", root, exp)
}
trie.Update(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000001338"), accounts[4])
if exp, root := common.HexToHash("ec63b967e98a5720e7f720482151963982890d82c9093c0d486b7eb8883a66b1"), trie.Hash(); exp != root {
if exp, root := common.HexToHash("5070d3f144546fd13589ad90cd153954643fa4ca6c1a5f08683cbfbbf76e960c"), trie.Hash(); exp != root {
t.Errorf("2: got %x, exp %x", root, exp)
}
trie.Update(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000001339"), accounts[4])
if exp, root := common.HexToHash("0608c1d1dc3905fa22204c7a0e43644831c3b6d3def0f274be623a948197e64a"), trie.Hash(); exp != root {
if exp, root := common.HexToHash("aa3fba77e50f6e931d8aacde70912be5bff04c7862f518ae06f3418dd4d37be3"), trie.Hash(); exp != root {
t.Errorf("3: got %x, exp %x", root, exp)
}
checktr, _ := New(common.Hash{}, trie.db)
@ -625,7 +625,7 @@ func TestCommitAfterHash(t *testing.T) {
trie.Hash()
trie.Commit(nil)
root := trie.Hash()
exp := common.HexToHash("72f9d3f3fe1e1dd7b8936442e7642aef76371472d94319900790053c493f3fe6")
exp := common.HexToHash("f0c0681648c93b347479cd58c61995557f01294425bd031ce1943c2799bbd4ec")
if exp != root {
t.Errorf("got %x, exp %x", root, exp)
}
@ -650,7 +650,6 @@ func makeAccounts(size int) (addresses [][20]byte, accounts [][]byte) {
var (
nonce = uint64(random.Int63())
root = emptyRoot
code = codehash.EmptyCodeHash.Bytes()
)
// The big.Rand function is not deterministic with regards to 64 vs 32 bit systems,
// and will consume different amount of data from the rand source.
@ -660,7 +659,16 @@ func makeAccounts(size int) (addresses [][20]byte, accounts [][]byte) {
balanceBytes := make([]byte, numBytes)
random.Read(balanceBytes)
balance := new(big.Int).SetBytes(balanceBytes)
data, _ := rlp.EncodeToBytes(&types.StateAccount{Nonce: nonce, Balance: balance, Root: root, CodeHash: code})
data, _ := rlp.EncodeToBytes(&types.StateAccount{
Nonce: nonce,
Balance: balance,
Root: root,
KeccakCodeHash: codehash.EmptyKeccakCodeHash.Bytes(),
PoseidonCodeHash: codehash.EmptyPoseidonCodeHash.Bytes(),
CodeSize: 0,
})
accounts[i] = data
}
return addresses, accounts
@ -717,12 +725,12 @@ func TestCommitSequence(t *testing.T) {
expWriteSeqHash []byte
expCallbackSeqHash []byte
}{
{20, common.FromHex("873c78df73d60e59d4a2bcf3716e8bfe14554549fea2fc147cb54129382a8066"),
common.FromHex("ff00f91ac05df53b82d7f178d77ada54fd0dca64526f537034a5dbe41b17df2a")},
{200, common.FromHex("ba03d891bb15408c940eea5ee3d54d419595102648d02774a0268d892add9c8e"),
common.FromHex("f3cd509064c8d319bbdd1c68f511850a902ad275e6ed5bea11547e23d492a926")},
{2000, common.FromHex("f7a184f20df01c94f09537401d11e68d97ad0c00115233107f51b9c287ce60c7"),
common.FromHex("ff795ea898ba1e4cfed4a33b4cf5535a347a02cf931f88d88719faf810f9a1c9")},
{20, common.FromHex("7b908cce3bc16abb3eac5dff6c136856526f15225f74ce860a2bec47912a5492"),
common.FromHex("fac65cd2ad5e301083d0310dd701b5faaff1364cbe01cdbfaf4ec3609bb4149e")},
{200, common.FromHex("55791f6ec2f83fee512a2d3d4b505784fdefaea89974e10440d01d62a18a298a"),
common.FromHex("5ab775b64d86a8058bb71c3c765d0f2158c14bbeb9cb32a65eda793a7e95e30f")},
{2000, common.FromHex("ccb464abf67804538908c62431b3a6788e8dc6dee62aff9bfe6b10136acfceac"),
common.FromHex("b908adff17a5aa9d6787324c39014a74b04cef7fba6a92aeb730f48da1ca665d")},
} {
addresses, accounts := makeAccounts(tc.count)
// This spongeDb is used to check the sequence of disk-db-writes

View file

@ -222,20 +222,24 @@ func TestMerkleTree_UpdateAccount(t *testing.T) {
mt := newTestingMerkle(t, 10)
acc1 := &types.StateAccount{
Nonce: 1,
Balance: big.NewInt(10000000),
Root: common.HexToHash("22fb59aa5410ed465267023713ab42554c250f394901455a3366e223d5f7d147"),
CodeHash: common.HexToHash("cc0a77f6e063b4b62eb7d9ed6f427cf687d8d0071d751850cfe5d136bc60d3ab").Bytes(),
Nonce: 1,
Balance: big.NewInt(10000000),
Root: common.HexToHash("22fb59aa5410ed465267023713ab42554c250f394901455a3366e223d5f7d147"),
KeccakCodeHash: common.HexToHash("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470").Bytes(),
PoseidonCodeHash: common.HexToHash("0c0a77f6e063b4b62eb7d9ed6f427cf687d8d0071d751850cfe5d136bc60d3ab").Bytes(),
CodeSize: 0,
}
err := mt.TryUpdateAccount(common.HexToAddress("0x05fDbDfaE180345C6Cff5316c286727CF1a43327").Bytes(), acc1)
assert.Nil(t, err)
acc2 := &types.StateAccount{
Nonce: 5,
Balance: big.NewInt(50000000),
Root: common.HexToHash("0"),
CodeHash: common.HexToHash("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470").Bytes(),
Nonce: 5,
Balance: big.NewInt(50000000),
Root: common.HexToHash("0"),
KeccakCodeHash: common.HexToHash("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470").Bytes(),
PoseidonCodeHash: common.HexToHash("05d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470").Bytes(),
CodeSize: 5,
}
err = mt.TryUpdateAccount(common.HexToAddress("0x4cb1aB63aF5D8931Ce09673EbD8ae2ce16fD6571").Bytes(), acc2)
assert.Nil(t, err)
@ -248,7 +252,9 @@ func TestMerkleTree_UpdateAccount(t *testing.T) {
assert.Equal(t, acc1.Nonce, acc.Nonce)
assert.Equal(t, acc1.Balance.Uint64(), acc.Balance.Uint64())
assert.Equal(t, acc1.Root.Bytes(), acc.Root.Bytes())
assert.Equal(t, acc1.CodeHash, acc.CodeHash)
assert.Equal(t, acc1.KeccakCodeHash, acc.KeccakCodeHash)
assert.Equal(t, acc1.PoseidonCodeHash, acc.PoseidonCodeHash)
assert.Equal(t, acc1.CodeSize, acc.CodeSize)
bt, err = mt.TryGet(common.HexToAddress("0x4cb1aB63aF5D8931Ce09673EbD8ae2ce16fD6571").Bytes())
assert.Nil(t, err)
@ -258,7 +264,9 @@ func TestMerkleTree_UpdateAccount(t *testing.T) {
assert.Equal(t, acc2.Nonce, acc.Nonce)
assert.Equal(t, acc2.Balance.Uint64(), acc.Balance.Uint64())
assert.Equal(t, acc2.Root.Bytes(), acc.Root.Bytes())
assert.Equal(t, acc2.CodeHash, acc.CodeHash)
assert.Equal(t, acc2.KeccakCodeHash, acc.KeccakCodeHash)
assert.Equal(t, acc2.PoseidonCodeHash, acc.PoseidonCodeHash)
assert.Equal(t, acc2.CodeSize, acc.CodeSize)
bt, err = mt.TryGet(common.HexToAddress("0x8dE13967F19410A7991D63c2c0179feBFDA0c261").Bytes())
assert.Nil(t, err)

View file

@ -126,10 +126,12 @@ func NewRWTblOrderer(inited map[common.Address]*types.StateAccount) *rwTblOrdere
}
initedAcc[addr] = &types.AccountWrapper{
Address: addr,
Nonce: data.Nonce,
Balance: (*hexutil.Big)(bl),
CodeHash: common.BytesToHash(data.CodeHash),
Address: addr,
Nonce: data.Nonce,
Balance: (*hexutil.Big)(bl),
KeccakCodeHash: common.BytesToHash(data.KeccakCodeHash),
PoseidonCodeHash: common.BytesToHash(data.PoseidonCodeHash),
CodeSize: data.CodeSize,
}
}
@ -251,7 +253,9 @@ func (od *rwTblOrderer) absorb(st *types.AccountWrapper) {
if traced, existed := od.opAccNonce[addrStr]; !existed {
traced = copyAccountState(st)
traced.Balance = initedRef.Balance
traced.CodeHash = initedRef.CodeHash
traced.KeccakCodeHash = initedRef.KeccakCodeHash
traced.PoseidonCodeHash = initedRef.PoseidonCodeHash
traced.CodeSize = initedRef.CodeSize
traced.Storage = nil
od.opAccNonce[addrStr] = traced
} else {
@ -260,7 +264,9 @@ func (od *rwTblOrderer) absorb(st *types.AccountWrapper) {
if traced, existed := od.opAccBalance[addrStr]; !existed {
traced = copyAccountState(st)
traced.CodeHash = initedRef.CodeHash
traced.KeccakCodeHash = initedRef.KeccakCodeHash
traced.PoseidonCodeHash = initedRef.PoseidonCodeHash
traced.CodeSize = initedRef.CodeSize
traced.Storage = nil
od.opAccBalance[addrStr] = traced
} else {
@ -275,7 +281,9 @@ func (od *rwTblOrderer) absorb(st *types.AccountWrapper) {
} else {
traced.Nonce = st.Nonce
traced.Balance = st.Balance
traced.CodeHash = st.CodeHash
traced.KeccakCodeHash = st.KeccakCodeHash
traced.PoseidonCodeHash = st.PoseidonCodeHash
traced.CodeSize = st.CodeSize
}
}

View file

@ -30,9 +30,11 @@ type SMTPath struct {
// StateAccount is the represent of StateAccount in L2 circuit
// Notice in L2 we have different hash scheme against StateAccount.MarshalByte
type StateAccount struct {
Nonce int `json:"nonce"`
Balance *hexutil.Big `json:"balance"` //just the common hex expression of integer (big-endian)
CodeHash hexutil.Bytes `json:"codeHash,omitempty"`
Nonce int `json:"nonce"`
Balance *hexutil.Big `json:"balance"` //just the common hex expression of integer (big-endian)
KeccakCodeHash hexutil.Bytes `json:"keccakCodeHash,omitempty"`
PoseidonCodeHash hexutil.Bytes `json:"poseidonCodeHash,omitempty"`
CodeSize uint64 `json:"codeSize,omitempty"`
}
// StateStorage is the represent of a stored key-value pair for specified account

View file

@ -263,16 +263,18 @@ func copyAccountState(st *types.AccountWrapper) *types.AccountWrapper {
}
return &types.AccountWrapper{
Nonce: st.Nonce,
Balance: (*hexutil.Big)(big.NewInt(0).Set(st.Balance.ToInt())),
CodeHash: st.CodeHash,
Address: st.Address,
Storage: stg,
Nonce: st.Nonce,
Balance: (*hexutil.Big)(big.NewInt(0).Set(st.Balance.ToInt())),
KeccakCodeHash: st.KeccakCodeHash,
PoseidonCodeHash: st.PoseidonCodeHash,
CodeSize: st.CodeSize,
Address: st.Address,
Storage: stg,
}
}
func isDeletedAccount(state *types.AccountWrapper) bool {
return state.Nonce == 0 && bytes.Equal(state.CodeHash.Bytes(), common.Hash{}.Bytes())
return state.Nonce == 0 && bytes.Equal(state.KeccakCodeHash.Bytes(), common.Hash{}.Bytes())
}
func getAccountDataFromLogState(state *types.AccountWrapper) *types.StateAccount {
@ -282,9 +284,12 @@ func getAccountDataFromLogState(state *types.AccountWrapper) *types.StateAccount
}
return &types.StateAccount{
Nonce: state.Nonce,
Balance: (*big.Int)(state.Balance),
CodeHash: state.CodeHash.Bytes(),
Nonce: state.Nonce,
Balance: (*big.Int)(state.Balance),
KeccakCodeHash: state.KeccakCodeHash.Bytes(),
PoseidonCodeHash: state.PoseidonCodeHash.Bytes(),
CodeSize: state.CodeSize,
// Root omitted intentionally
}
}
@ -305,13 +310,14 @@ func verifyAccount(addr common.Address, data *types.StateAccount, leaf *SMTPathN
return fmt.Errorf("unmatch leaf node in address: %s", addr)
}
} else if data != nil {
h, err := data.Hash()
arr, flag := data.MarshalFields()
h, err := zkt.PreHandlingElems(flag, arr)
//log.Info("sanity check acc before", "addr", addr.String(), "key", leaf.Sibling.Text(16), "hash", h.Text(16))
if err != nil {
return fmt.Errorf("fail to hash account: %v", err)
}
if !bytes.Equal(zkt.NewHashFromBigInt(h)[:], leaf.Value) {
if !bytes.Equal(h[:], leaf.Value) {
return fmt.Errorf("unmatch data in leaf for address %s", addr)
}
}
@ -386,18 +392,22 @@ func (w *zktrieProofWriter) traceAccountUpdate(addr common.Address, updateAccDat
// we have ensured the nBefore has a key corresponding to the query one
out.AccountKey = out.AccountPath[0].Leaf.Sibling
out.AccountUpdate[0] = &StateAccount{
Nonce: int(accDataBefore.Nonce),
Balance: (*hexutil.Big)(big.NewInt(0).Set(accDataBefore.Balance)),
CodeHash: accDataBefore.CodeHash,
Nonce: int(accDataBefore.Nonce),
Balance: (*hexutil.Big)(big.NewInt(0).Set(accDataBefore.Balance)),
KeccakCodeHash: accDataBefore.KeccakCodeHash,
PoseidonCodeHash: accDataBefore.PoseidonCodeHash,
CodeSize: accDataBefore.CodeSize,
}
}
accData := updateAccData(accDataBefore)
if accData != nil {
out.AccountUpdate[1] = &StateAccount{
Nonce: int(accData.Nonce),
Balance: (*hexutil.Big)(big.NewInt(0).Set(accData.Balance)),
CodeHash: accData.CodeHash,
Nonce: int(accData.Nonce),
Balance: (*hexutil.Big)(big.NewInt(0).Set(accData.Balance)),
KeccakCodeHash: accData.KeccakCodeHash,
PoseidonCodeHash: accData.PoseidonCodeHash,
CodeSize: accData.CodeSize,
}
}
@ -515,10 +525,12 @@ func (w *zktrieProofWriter) traceStorageUpdate(addr common.Address, key, value [
panic(fmt.Errorf("unexpected storage root before: [%s] vs [%x]", acc.Root, accRootFromState))
}
return &types.StateAccount{
Nonce: acc.Nonce,
Balance: acc.Balance,
CodeHash: acc.CodeHash,
Root: common.BytesToHash(zkt.ReverseByteOrder(statePath[1].Root)),
Nonce: acc.Nonce,
Balance: acc.Balance,
Root: common.BytesToHash(zkt.ReverseByteOrder(statePath[1].Root)),
KeccakCodeHash: acc.KeccakCodeHash,
PoseidonCodeHash: acc.PoseidonCodeHash,
CodeSize: acc.CodeSize,
}
})
if err != nil {