mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-28 07:36:44 +00:00
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:
parent
1fe2d22e29
commit
81e7775aa8
49 changed files with 891 additions and 587 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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: ¶ms.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{
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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++ {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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{})
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
2
go.mod
|
|
@ -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
4
go.sum
|
|
@ -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=
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
Loading…
Reference in a new issue