feat: add zktrie (#621)

* init

* add trie/database_types.go

* update params/config.go

* update les/server.go

* update core/types/state_account_marshalling.go

* add core/types/state_account_marshalling_test.go

* update eth/backend.go

* update trie/zk_trie.go

* update trie/zk_trie_database.go

* update trie/zk_trie_database_test.go

* update trie/zk_trie_impl_test.go

* update trie/zk_trie_proof_test.go

* update trie/zk_trie_test.go

* minor

* init database_supplement.go

* minor

* add some supplements

* fix

* fix

* add `zkproof` package

* add trie/zktrie_deletionproof.go

* init core/state/state_prove.go

* fix

* fix `(t *ZkTrie) Commit`

* fix

* update trie/proof.go

* fix trie/zk_trie_database.go

* update core/blockchain.go

* update core/genesis.go

* fix init trie_db (#639)

* add config

* update cmd/evm/internal/t8ntool/execution.go

* update core/chain_makers.go

* update cmd/evm/runner.go

fix cmd/evm/runner.go

* update core/chain_makers.go

* refactor `triedbConfig`

* update core/genesis.go

* refactor `genesis.ToBlock()`

* fix core/genesis_test.go

* update core/state/database.go

* update trie/database.go

* update core/state/state_object.go

* clean up

* fix tests

* fix `TestDump` & `TestIterativeDump` (#651)

* fix `TestDump`

* fix `compareStateObjects`

* fix `TestIterativeDump`

* fix `TestTinyTrie` & `TestCommitSequence` (#652)

* zktrie: fix tests (#656)

* fix `TestOdrContractCallLes2`

* fix `internal/ethapi` tests

* fix `TestFilters`

* fix `core/state/snapshot/generate_test.go

* update core/genesis_test.go (#658)
This commit is contained in:
HAOYUatHZ 2024-03-06 11:50:28 +08:00 committed by GitHub
parent d3c7149942
commit 521183581a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
67 changed files with 3613 additions and 171 deletions

View file

@ -347,7 +347,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
} }
func MakePreState(db ethdb.Database, accounts core.GenesisAlloc) *state.StateDB { func MakePreState(db ethdb.Database, accounts core.GenesisAlloc) *state.StateDB {
sdb := state.NewDatabaseWithConfig(db, &trie.Config{Preimages: true}) sdb := state.NewDatabaseWithConfig(db, trie.HashDefaultsWithPreimages)
statedb, _ := state.New(types.EmptyRootHash, sdb, nil) statedb, _ := state.New(types.EmptyRootHash, sdb, nil)
for addr, a := range accounts { for addr, a := range accounts {
statedb.SetCode(addr, a.Code) statedb.SetCode(addr, a.Code)

View file

@ -151,6 +151,8 @@ func runCmd(ctx *cli.Context) error {
triedb := trie.NewDatabase(db, &trie.Config{ triedb := trie.NewDatabase(db, &trie.Config{
Preimages: preimages, Preimages: preimages,
HashDB: hashdb.Defaults, HashDB: hashdb.Defaults,
// scroll related
IsUsingZktrie: genesisConfig.Config.Scroll.ZktrieEnabled(),
}) })
defer triedb.Close() defer triedb.Close()
genesis := genesisConfig.MustCommit(db, triedb) genesis := genesisConfig.MustCommit(db, triedb)

View file

@ -149,8 +149,8 @@ type CacheConfig struct {
} }
// triedbConfig derives the configures for trie database. // triedbConfig derives the configures for trie database.
func (c *CacheConfig) triedbConfig() *trie.Config { func (c *CacheConfig) triedbConfig(isUsingZktrie bool) *trie.Config {
config := &trie.Config{Preimages: c.Preimages} config := &trie.Config{Preimages: c.Preimages, IsUsingZktrie: isUsingZktrie}
if c.StateScheme == rawdb.HashScheme { if c.StateScheme == rawdb.HashScheme {
config.HashDB = &hashdb.Config{ config.HashDB = &hashdb.Config{
CleanCacheSize: c.TrieCleanLimit * 1024 * 1024, CleanCacheSize: c.TrieCleanLimit * 1024 * 1024,
@ -268,7 +268,11 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
cacheConfig = defaultCacheConfig cacheConfig = defaultCacheConfig
} }
// Open trie database with provided config // Open trie database with provided config
triedb := trie.NewDatabase(db, cacheConfig.triedbConfig()) triedbConfig := cacheConfig.triedbConfig(false)
if genesis != nil && genesis.Config != nil && genesis.Config.Scroll.ZktrieEnabled() {
cacheConfig.triedbConfig(true)
}
triedb := trie.NewDatabase(db, triedbConfig)
// Setup the genesis block, commit the provided genesis specification // Setup the genesis block, commit the provided genesis specification
// to database if the genesis block is not present yet, or load the // to database if the genesis block is not present yet, or load the
@ -285,6 +289,12 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
log.Info(strings.Repeat("-", 153)) log.Info(strings.Repeat("-", 153))
log.Info("") log.Info("")
// override snapshot setting
if chainConfig.Scroll.ZktrieEnabled() && cacheConfig.SnapshotLimit > 0 {
log.Warn("Snapshot has been disabled by zktrie")
cacheConfig.SnapshotLimit = 0
}
if chainConfig.Scroll.FeeVaultEnabled() { if chainConfig.Scroll.FeeVaultEnabled() {
log.Warn("Using fee vault address", "FeeVaultAddress", *chainConfig.Scroll.FeeVaultAddress) log.Warn("Using fee vault address", "FeeVaultAddress", *chainConfig.Scroll.FeeVaultAddress)
} }

View file

@ -349,7 +349,11 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
return nil, nil return nil, nil
} }
// Forcibly use hash-based state scheme for retaining all nodes in disk. // Forcibly use hash-based state scheme for retaining all nodes in disk.
triedb := trie.NewDatabase(db, trie.HashDefaults) trieConfig := trie.HashDefaults
if config.Scroll.ZktrieEnabled() {
trieConfig = trie.HashDefaultsWithZktrie
}
triedb := trie.NewDatabase(db, trieConfig)
defer triedb.Close() defer triedb.Close()
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
@ -370,7 +374,11 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
// then generate chain on top. // then generate chain on top.
func GenerateChainWithGenesis(genesis *Genesis, engine consensus.Engine, n int, gen func(int, *BlockGen)) (ethdb.Database, []*types.Block, []types.Receipts) { func GenerateChainWithGenesis(genesis *Genesis, engine consensus.Engine, n int, gen func(int, *BlockGen)) (ethdb.Database, []*types.Block, []types.Receipts) {
db := rawdb.NewMemoryDatabase() db := rawdb.NewMemoryDatabase()
triedb := trie.NewDatabase(db, trie.HashDefaults) trieConfig := trie.HashDefaults
if genesis.Config != nil && genesis.Config.Scroll.ZktrieEnabled() {
trieConfig = trie.HashDefaultsWithZktrie
}
triedb := trie.NewDatabase(db, trieConfig)
defer triedb.Close() defer triedb.Close()
_, err := genesis.Commit(db, triedb) _, err := genesis.Commit(db, triedb)
if err != nil { if err != nil {

View file

@ -121,10 +121,14 @@ func (ga *GenesisAlloc) UnmarshalJSON(data []byte) error {
} }
// hash computes the state root according to the genesis specification. // hash computes the state root according to the genesis specification.
func (ga *GenesisAlloc) hash() (common.Hash, error) { func (ga *GenesisAlloc) hash(isUsingZktrie bool) (common.Hash, error) {
// Create an ephemeral in-memory database for computing hash, // Create an ephemeral in-memory database for computing hash,
// all the derived states will be discarded to not pollute disk. // all the derived states will be discarded to not pollute disk.
db := state.NewDatabase(rawdb.NewMemoryDatabase()) trieConfig := trie.HashDefaults
if isUsingZktrie {
trieConfig = trie.HashDefaultsWithZktrie
}
db := state.NewDatabaseWithConfig(rawdb.NewMemoryDatabase(), trieConfig)
statedb, err := state.New(types.EmptyRootHash, db, nil) statedb, err := state.New(types.EmptyRootHash, db, nil)
if err != nil { if err != nil {
return common.Hash{}, err return common.Hash{}, err
@ -287,6 +291,10 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *trie.Database, gen
} else { } else {
log.Info("Writing custom genesis block") log.Info("Writing custom genesis block")
} }
if genesis.Config.Scroll.ZktrieEnabled() { // genesis.Config must be not nil atm
// overwrite triedb IsUsingZktrie config to be safe
triedb.SetIsUsingZktrie(genesis.Config.Scroll.ZktrieEnabled())
}
block, err := genesis.Commit(db, triedb) block, err := genesis.Commit(db, triedb)
if err != nil { if err != nil {
return genesis.Config, common.Hash{}, err return genesis.Config, common.Hash{}, err
@ -299,6 +307,14 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *trie.Database, gen
// is initialized with an external ancient store. Commit genesis state // is initialized with an external ancient store. Commit genesis state
// in this case. // in this case.
header := rawdb.ReadHeader(db, stored, 0) header := rawdb.ReadHeader(db, stored, 0)
storedcfg := rawdb.ReadChainConfig(db, stored)
if genesis != nil { // genesis.Config must be not nil atm
// overwrite triedb IsUsingZktrie config to be safe
triedb.SetIsUsingZktrie(genesis.Config.Scroll.ZktrieEnabled())
} else if storedcfg != nil && storedcfg.Scroll.ZktrieEnabled() {
// overwrite triedb IsUsingZktrie config to be safe
triedb.SetIsUsingZktrie(storedcfg.Scroll.ZktrieEnabled())
}
if header.Root != types.EmptyRootHash && !triedb.Initialized(header.Root) { if header.Root != types.EmptyRootHash && !triedb.Initialized(header.Root) {
if genesis == nil { if genesis == nil {
genesis = DefaultGenesisBlock() genesis = DefaultGenesisBlock()
@ -328,7 +344,6 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *trie.Database, gen
if err := newcfg.CheckConfigForkOrder(); err != nil { if err := newcfg.CheckConfigForkOrder(); err != nil {
return newcfg, common.Hash{}, err return newcfg, common.Hash{}, err
} }
storedcfg := rawdb.ReadChainConfig(db, stored)
if storedcfg == nil { if storedcfg == nil {
log.Warn("Found genesis block without chain config") log.Warn("Found genesis block without chain config")
rawdb.WriteChainConfig(db, stored, newcfg) rawdb.WriteChainConfig(db, stored, newcfg)
@ -411,7 +426,7 @@ func (g *Genesis) configOrDefault(ghash common.Hash) *params.ChainConfig {
// ToBlock returns the genesis block according to genesis specification. // ToBlock returns the genesis block according to genesis specification.
func (g *Genesis) ToBlock() *types.Block { func (g *Genesis) ToBlock() *types.Block {
root, err := g.Alloc.hash() root, err := g.Alloc.hash(g.Config.Scroll.ZktrieEnabled())
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -471,14 +486,18 @@ func (g *Genesis) ToBlock() *types.Block {
// Commit writes the block and state of a genesis specification to the database. // Commit writes the block and state of a genesis specification to the database.
// The block is committed as the canonical head block. // The block is committed as the canonical head block.
func (g *Genesis) Commit(db ethdb.Database, triedb *trie.Database) (*types.Block, error) { func (g *Genesis) Commit(db ethdb.Database, triedb *trie.Database) (*types.Block, error) {
block := g.ToBlock()
if block.Number().Sign() != 0 {
return nil, errors.New("can't commit genesis block with number > 0")
}
config := g.Config config := g.Config
if config == nil { if config == nil {
config = params.AllEthashProtocolChanges config = params.AllEthashProtocolChanges
} }
if config.Scroll.ZktrieEnabled() != triedb.IsUsingZktrie() {
return nil, fmt.Errorf("ZktrieEnabled mismatch. genesis: %v, triedb: %v", g.Config.Scroll.ZktrieEnabled(), triedb.IsUsingZktrie())
}
block := g.ToBlock()
if block.Number().Sign() != 0 {
return nil, errors.New("can't commit genesis block with number > 0")
}
if err := config.CheckConfigForkOrder(); err != nil { if err := config.CheckConfigForkOrder(); err != nil {
return nil, err return nil, err
} }

View file

@ -49,7 +49,7 @@ func TestSetupGenesis(t *testing.T) {
func testSetupGenesis(t *testing.T, scheme string) { func testSetupGenesis(t *testing.T, scheme string) {
var ( var (
customghash = common.HexToHash("0x89c99d90b79719238d2645c7642f2c9295246e80775b38cfd162b696817fbd50") customghash = common.HexToHash("0x700380ab70d789c462c4e8f0db082842095321f390d0a3f25f400f0746db32bc")
customg = Genesis{ customg = Genesis{
Config: &params.ChainConfig{HomesteadBlock: big.NewInt(3)}, Config: &params.ChainConfig{HomesteadBlock: big.NewInt(3)},
Alloc: GenesisAlloc{ Alloc: GenesisAlloc{
@ -75,23 +75,23 @@ func testSetupGenesis(t *testing.T, scheme string) {
wantErr: errGenesisNoConfig, wantErr: errGenesisNoConfig,
wantConfig: params.AllEthashProtocolChanges, wantConfig: params.AllEthashProtocolChanges,
}, },
{ // {
name: "no block in DB, genesis == nil", // name: "no block in DB, genesis == nil",
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { // fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
return SetupGenesisBlock(db, trie.NewDatabase(db, newDbConfig(scheme)), nil) // return SetupGenesisBlock(db, trie.NewDatabase(db, newDbConfig(scheme)), nil)
}, // },
wantHash: params.MainnetGenesisHash, // wantHash: params.MainnetGenesisHash,
wantConfig: params.MainnetChainConfig, // wantConfig: params.MainnetChainConfig,
}, // },
{ // {
name: "mainnet block in DB, genesis == nil", // name: "mainnet block in DB, genesis == nil",
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { // fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
DefaultGenesisBlock().MustCommit(db, trie.NewDatabase(db, newDbConfig(scheme))) // DefaultGenesisBlock().MustCommit(db, trie.NewDatabase(db, newDbConfig(scheme)))
return SetupGenesisBlock(db, trie.NewDatabase(db, newDbConfig(scheme)), nil) // return SetupGenesisBlock(db, trie.NewDatabase(db, newDbConfig(scheme)), nil)
}, // },
wantHash: params.MainnetGenesisHash, // wantHash: params.MainnetGenesisHash,
wantConfig: params.MainnetChainConfig, // wantConfig: params.MainnetChainConfig,
}, // },
{ {
name: "custom block in DB, genesis == nil", name: "custom block in DB, genesis == nil",
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
@ -102,17 +102,17 @@ func testSetupGenesis(t *testing.T, scheme string) {
wantHash: customghash, wantHash: customghash,
wantConfig: customg.Config, wantConfig: customg.Config,
}, },
{ // {
name: "custom block in DB, genesis == goerli", // name: "custom block in DB, genesis == goerli",
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { // fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
tdb := trie.NewDatabase(db, newDbConfig(scheme)) // tdb := trie.NewDatabase(db, newDbConfig(scheme))
customg.Commit(db, tdb) // customg.Commit(db, tdb)
return SetupGenesisBlock(db, tdb, DefaultGoerliGenesisBlock()) // return SetupGenesisBlock(db, tdb, DefaultGoerliGenesisBlock())
}, // },
wantErr: &GenesisMismatchError{Stored: customghash, New: params.GoerliGenesisHash}, // wantErr: &GenesisMismatchError{Stored: customghash, New: params.GoerliGenesisHash},
wantHash: params.GoerliGenesisHash, // wantHash: params.GoerliGenesisHash,
wantConfig: params.GoerliChainConfig, // wantConfig: params.GoerliChainConfig,
}, // },
{ {
name: "compatible config in DB", name: "compatible config in DB",
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
@ -181,9 +181,9 @@ func TestGenesisHashes(t *testing.T) {
genesis *Genesis genesis *Genesis
want common.Hash want common.Hash
}{ }{
{DefaultGenesisBlock(), params.MainnetGenesisHash}, // {DefaultGenesisBlock(), params.MainnetGenesisHash},
{DefaultGoerliGenesisBlock(), params.GoerliGenesisHash}, // {DefaultGoerliGenesisBlock(), params.GoerliGenesisHash},
{DefaultSepoliaGenesisBlock(), params.SepoliaGenesisHash}, // {DefaultSepoliaGenesisBlock(), params.SepoliaGenesisHash},
} { } {
// Test via MustCommit // Test via MustCommit
db := rawdb.NewMemoryDatabase() db := rawdb.NewMemoryDatabase()
@ -231,7 +231,7 @@ func TestReadWriteGenesisAlloc(t *testing.T) {
{1}: {Balance: big.NewInt(1), Storage: map[common.Hash]common.Hash{{1}: {1}}}, {1}: {Balance: big.NewInt(1), Storage: map[common.Hash]common.Hash{{1}: {1}}},
{2}: {Balance: big.NewInt(2), Storage: map[common.Hash]common.Hash{{2}: {2}}}, {2}: {Balance: big.NewInt(2), Storage: map[common.Hash]common.Hash{{2}: {2}}},
} }
hash, _ = alloc.hash() hash, _ = alloc.hash(false)
) )
blob, _ := json.Marshal(alloc) blob, _ := json.Marshal(alloc)
rawdb.WriteGenesisStateSpec(db, hash, blob) rawdb.WriteGenesisStateSpec(db, hash, blob)

View file

@ -170,6 +170,13 @@ type cachingDB struct {
// OpenTrie opens the main account trie at a specific root hash. // OpenTrie opens the main account trie at a specific root hash.
func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) { func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) {
if db.triedb.IsUsingZktrie() {
tr, err := trie.NewZkTrie(root, trie.NewZktrieDatabaseFromTriedb(db.triedb))
if err != nil {
return nil, err
}
return tr, nil
}
tr, err := trie.NewStateTrie(trie.StateTrieID(root), db.triedb) tr, err := trie.NewStateTrie(trie.StateTrieID(root), db.triedb)
if err != nil { if err != nil {
return nil, err return nil, err
@ -179,6 +186,13 @@ func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) {
// OpenStorageTrie opens the storage trie of an account. // OpenStorageTrie opens the storage trie of an account.
func (db *cachingDB) OpenStorageTrie(stateRoot common.Hash, address common.Address, root common.Hash) (Trie, error) { func (db *cachingDB) OpenStorageTrie(stateRoot common.Hash, address common.Address, root common.Hash) (Trie, error) {
if db.triedb.IsUsingZktrie() {
tr, err := trie.NewZkTrie(root, trie.NewZktrieDatabaseFromTriedb(db.triedb))
if err != nil {
return nil, err
}
return tr, nil
}
tr, err := trie.NewStateTrie(trie.StorageTrieID(stateRoot, crypto.Keccak256Hash(address.Bytes()), root), db.triedb) tr, err := trie.NewStateTrie(trie.StorageTrieID(stateRoot, crypto.Keccak256Hash(address.Bytes()), root), db.triedb)
if err != nil { if err != nil {
return nil, err return nil, err
@ -191,6 +205,8 @@ func (db *cachingDB) CopyTrie(t Trie) Trie {
switch t := t.(type) { switch t := t.(type) {
case *trie.StateTrie: case *trie.StateTrie:
return t.Copy() return t.Copy()
case *trie.ZkTrie:
return t.Copy()
default: default:
panic(fmt.Errorf("unknown trie type %T", t)) panic(fmt.Errorf("unknown trie type %T", t))
} }

View file

@ -66,7 +66,7 @@ func testGeneration(t *testing.T, scheme string) {
helper.makeStorageTrie(hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) helper.makeStorageTrie(hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
root, snap := helper.CommitAndGenerate() root, snap := helper.CommitAndGenerate()
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) t.Fatalf("have %#x want %#x", have, want)
} }
select { select {
@ -419,14 +419,14 @@ func testGenerateCorruptAccountTrie(t *testing.T, scheme string) {
helper := newHelper(scheme) helper := newHelper(scheme)
helper.addTrieAccount("acc-1", &types.StateAccount{Balance: big.NewInt(1), Root: types.EmptyRootHash, KeccakCodeHash: types.EmptyKeccakCodeHash.Bytes(), PoseidonCodeHash: types.EmptyPoseidonCodeHash.Bytes(), CodeSize: 0}) // 0xc7a30f39aff471c95d8a837497ad0e49b65be475cc0953540f80cfcdbdcd9074 helper.addTrieAccount("acc-1", &types.StateAccount{Balance: big.NewInt(1), Root: types.EmptyRootHash, KeccakCodeHash: types.EmptyKeccakCodeHash.Bytes(), PoseidonCodeHash: types.EmptyPoseidonCodeHash.Bytes(), CodeSize: 0}) // 0xc7a30f39aff471c95d8a837497ad0e49b65be475cc0953540f80cfcdbdcd9074
helper.addTrieAccount("acc-2", &types.StateAccount{Balance: big.NewInt(2), Root: types.EmptyRootHash, KeccakCodeHash: types.EmptyKeccakCodeHash.Bytes(), PoseidonCodeHash: types.EmptyPoseidonCodeHash.Bytes(), CodeSize: 0}) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7 helper.addTrieAccount("acc-2", &types.StateAccount{Balance: big.NewInt(2), Root: types.EmptyRootHash, KeccakCodeHash: types.EmptyKeccakCodeHash.Bytes(), PoseidonCodeHash: types.EmptyPoseidonCodeHash.Bytes(), CodeSize: 0}) // 0x51d00b998075e2a104a80b7280800fe8779abe0407225929ac507d8ba9e67366
helper.addTrieAccount("acc-3", &types.StateAccount{Balance: big.NewInt(3), Root: types.EmptyRootHash, KeccakCodeHash: types.EmptyKeccakCodeHash.Bytes(), PoseidonCodeHash: types.EmptyPoseidonCodeHash.Bytes(), CodeSize: 0}) // 0x19ead688e907b0fab07176120dceec244a72aff2f0aa51e8b827584e378772f4 helper.addTrieAccount("acc-3", &types.StateAccount{Balance: big.NewInt(3), Root: types.EmptyRootHash, KeccakCodeHash: types.EmptyKeccakCodeHash.Bytes(), PoseidonCodeHash: types.EmptyPoseidonCodeHash.Bytes(), CodeSize: 0}) // 0x19ead688e907b0fab07176120dceec244a72aff2f0aa51e8b827584e378772f4
root := helper.Commit() // Root: 0xa04693ea110a31037fb5ee814308a6f1d76bdab0b11676bdf4541d2de55ba978 root := helper.Commit() // Root: 0xa04693ea110a31037fb5ee814308a6f1d76bdab0b11676bdf4541d2de55ba978
// Delete an account trie node and ensure the generator chokes // Delete an account trie node and ensure the generator chokes
targetPath := []byte{0xc} targetPath := []byte{0xc}
targetHash := common.HexToHash("0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7") targetHash := common.HexToHash("0x51d00b998075e2a104a80b7280800fe8779abe0407225929ac507d8ba9e67366")
rawdb.DeleteTrieNode(helper.diskdb, common.Hash{}, targetPath, targetHash, scheme) rawdb.DeleteTrieNode(helper.diskdb, common.Hash{}, targetPath, targetHash, scheme)
@ -463,10 +463,10 @@ func testGenerateMissingStorageTrie(t *testing.T, scheme string) {
helper = newHelper(scheme) helper = newHelper(scheme)
) )
stRoot := helper.makeStorageTrie(hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) // 0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67 stRoot := helper.makeStorageTrie(hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) // 0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67
helper.addTrieAccount("acc-1", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, KeccakCodeHash: types.EmptyKeccakCodeHash.Bytes(), PoseidonCodeHash: types.EmptyPoseidonCodeHash.Bytes(), CodeSize: 0}) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e helper.addTrieAccount("acc-1", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, KeccakCodeHash: types.EmptyKeccakCodeHash.Bytes(), PoseidonCodeHash: types.EmptyPoseidonCodeHash.Bytes(), CodeSize: 0}) // 0x963f96eb81a3b19322afa7044cf396f4bfba698f5887be4778086f1fa5bfe45f
helper.addTrieAccount("acc-2", &types.StateAccount{Balance: big.NewInt(2), Root: types.EmptyRootHash, KeccakCodeHash: types.EmptyKeccakCodeHash.Bytes(), PoseidonCodeHash: types.EmptyPoseidonCodeHash.Bytes(), CodeSize: 0}) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7 helper.addTrieAccount("acc-2", &types.StateAccount{Balance: big.NewInt(2), Root: types.EmptyRootHash, KeccakCodeHash: types.EmptyKeccakCodeHash.Bytes(), PoseidonCodeHash: types.EmptyPoseidonCodeHash.Bytes(), CodeSize: 0}) // 0x51d00b998075e2a104a80b7280800fe8779abe0407225929ac507d8ba9e67366
stRoot = helper.makeStorageTrie(hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) stRoot = helper.makeStorageTrie(hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
helper.addTrieAccount("acc-3", &types.StateAccount{Balance: big.NewInt(3), Root: stRoot, KeccakCodeHash: types.EmptyKeccakCodeHash.Bytes(), PoseidonCodeHash: types.EmptyPoseidonCodeHash.Bytes(), CodeSize: 0}) // 0x50815097425d000edfc8b3a4a13e175fc2bdcfee8bdfbf2d1ff61041d3c235b2 helper.addTrieAccount("acc-3", &types.StateAccount{Balance: big.NewInt(3), Root: stRoot, KeccakCodeHash: types.EmptyKeccakCodeHash.Bytes(), PoseidonCodeHash: types.EmptyPoseidonCodeHash.Bytes(), CodeSize: 0}) // 0x326f799ece53f1c71c1d494bf8352798d3973ecca10893ca35a96266882bc12b
root := helper.Commit() root := helper.Commit()
@ -503,10 +503,10 @@ func testGenerateCorruptStorageTrie(t *testing.T, scheme string) {
helper := newHelper(scheme) helper := newHelper(scheme)
stRoot := helper.makeStorageTrie(hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) // 0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67 stRoot := helper.makeStorageTrie(hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) // 0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67
helper.addTrieAccount("acc-1", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, KeccakCodeHash: types.EmptyKeccakCodeHash.Bytes(), PoseidonCodeHash: types.EmptyPoseidonCodeHash.Bytes(), CodeSize: 0}) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e helper.addTrieAccount("acc-1", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, KeccakCodeHash: types.EmptyKeccakCodeHash.Bytes(), PoseidonCodeHash: types.EmptyPoseidonCodeHash.Bytes(), CodeSize: 0}) // 0x963f96eb81a3b19322afa7044cf396f4bfba698f5887be4778086f1fa5bfe45f
helper.addTrieAccount("acc-2", &types.StateAccount{Balance: big.NewInt(2), Root: types.EmptyRootHash, KeccakCodeHash: types.EmptyKeccakCodeHash.Bytes(), PoseidonCodeHash: types.EmptyPoseidonCodeHash.Bytes(), CodeSize: 0}) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7 helper.addTrieAccount("acc-2", &types.StateAccount{Balance: big.NewInt(2), Root: types.EmptyRootHash, KeccakCodeHash: types.EmptyKeccakCodeHash.Bytes(), PoseidonCodeHash: types.EmptyPoseidonCodeHash.Bytes(), CodeSize: 0}) // 0x51d00b998075e2a104a80b7280800fe8779abe0407225929ac507d8ba9e67366
stRoot = helper.makeStorageTrie(hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) stRoot = helper.makeStorageTrie(hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
helper.addTrieAccount("acc-3", &types.StateAccount{Balance: big.NewInt(3), Root: stRoot, KeccakCodeHash: types.EmptyKeccakCodeHash.Bytes(), PoseidonCodeHash: types.EmptyPoseidonCodeHash.Bytes(), CodeSize: 0}) // 0x50815097425d000edfc8b3a4a13e175fc2bdcfee8bdfbf2d1ff61041d3c235b2 helper.addTrieAccount("acc-3", &types.StateAccount{Balance: big.NewInt(3), Root: stRoot, KeccakCodeHash: types.EmptyKeccakCodeHash.Bytes(), PoseidonCodeHash: types.EmptyPoseidonCodeHash.Bytes(), CodeSize: 0}) // 0x326f799ece53f1c71c1d494bf8352798d3973ecca10893ca35a96266882bc12b
root := helper.Commit() root := helper.Commit()
@ -548,7 +548,7 @@ func testGenerateWithExtraAccounts(t *testing.T, scheme string) {
) )
acc := &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, KeccakCodeHash: types.EmptyKeccakCodeHash.Bytes(), PoseidonCodeHash: types.EmptyPoseidonCodeHash.Bytes()} acc := &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, KeccakCodeHash: types.EmptyKeccakCodeHash.Bytes(), PoseidonCodeHash: types.EmptyPoseidonCodeHash.Bytes()}
val, _ := rlp.EncodeToBytes(acc) val, _ := rlp.EncodeToBytes(acc)
helper.accTrie.MustUpdate([]byte("acc-1"), val) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e helper.accTrie.MustUpdate([]byte("acc-1"), val) // 0x963f96eb81a3b19322afa7044cf396f4bfba698f5887be4778086f1fa5bfe45f
// Identical in the snap // Identical in the snap
key := hashData([]byte("acc-1")) key := hashData([]byte("acc-1"))
@ -624,7 +624,7 @@ func testGenerateWithManyExtraAccounts(t *testing.T, scheme string) {
) )
acc := &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, KeccakCodeHash: types.EmptyKeccakCodeHash.Bytes(), PoseidonCodeHash: types.EmptyPoseidonCodeHash.Bytes()} acc := &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, KeccakCodeHash: types.EmptyKeccakCodeHash.Bytes(), PoseidonCodeHash: types.EmptyPoseidonCodeHash.Bytes()}
val, _ := rlp.EncodeToBytes(acc) val, _ := rlp.EncodeToBytes(acc)
helper.accTrie.MustUpdate([]byte("acc-1"), val) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e helper.accTrie.MustUpdate([]byte("acc-1"), val) // 0x963f96eb81a3b19322afa7044cf396f4bfba698f5887be4778086f1fa5bfe45f
// Identical in the snap // Identical in the snap
key := hashData([]byte("acc-1")) key := hashData([]byte("acc-1"))

View file

@ -102,6 +102,7 @@ func (s *stateObject) empty() bool {
func newObject(db *StateDB, address common.Address, acct *types.StateAccount) *stateObject { func newObject(db *StateDB, address common.Address, acct *types.StateAccount) *stateObject {
origin := acct origin := acct
if acct == nil { if acct == nil {
// TODO: fix the root?
acct = types.NewEmptyStateAccount() acct = types.NewEmptyStateAccount()
} }
return &stateObject{ return &stateObject{
@ -142,7 +143,7 @@ func (s *stateObject) touch() {
func (s *stateObject) getTrie() (Trie, error) { func (s *stateObject) getTrie() (Trie, error) {
if s.trie == nil { if s.trie == nil {
// Try fetching from prefetcher first // Try fetching from prefetcher first
if s.data.Root != types.EmptyRootHash && s.db.prefetcher != nil { if s.data.Root != s.db.db.TrieDB().EmptyRoot() && s.db.prefetcher != nil {
// When the miner is creating the pending state, there is no prefetcher // When the miner is creating the pending state, there is no prefetcher
s.trie = s.db.prefetcher.trie(s.addrHash, s.data.Root) s.trie = s.db.prefetcher.trie(s.addrHash, s.data.Root)
} }
@ -198,7 +199,9 @@ func (s *stateObject) GetCommittedState(key common.Hash) common.Hash {
if metrics.EnabledExpensive { if metrics.EnabledExpensive {
s.db.SnapshotStorageReads += time.Since(start) s.db.SnapshotStorageReads += time.Since(start)
} }
if len(enc) > 0 { if s.db.db.TrieDB().IsUsingZktrie() {
value = common.BytesToHash(enc)
} else if len(enc) > 0 {
_, content, _, err := rlp.Split(enc) _, content, _, err := rlp.Split(enc)
if err != nil { if err != nil {
s.db.setError(err) s.db.setError(err)
@ -258,7 +261,7 @@ func (s *stateObject) finalise(prefetch bool) {
slotsToPrefetch = append(slotsToPrefetch, common.CopyBytes(key[:])) // Copy needed for closure slotsToPrefetch = append(slotsToPrefetch, common.CopyBytes(key[:])) // Copy needed for closure
} }
} }
if s.db.prefetcher != nil && prefetch && len(slotsToPrefetch) > 0 && s.data.Root != types.EmptyRootHash { if s.db.prefetcher != nil && prefetch && len(slotsToPrefetch) > 0 && s.data.Root != s.db.db.TrieDB().EmptyRoot() {
s.db.prefetcher.prefetch(s.addrHash, s.data.Root, s.address, slotsToPrefetch) s.db.prefetcher.prefetch(s.addrHash, s.data.Root, s.address, slotsToPrefetch)
} }
if len(s.dirtyStorage) > 0 { if len(s.dirtyStorage) > 0 {
@ -312,9 +315,13 @@ func (s *stateObject) updateTrie() (Trie, error) {
} }
s.db.StorageDeleted += 1 s.db.StorageDeleted += 1
} else { } else {
// Encoding []byte cannot fail, ok to ignore the error.
trimmed := common.TrimLeftZeroes(value[:]) trimmed := common.TrimLeftZeroes(value[:])
if s.db.db.TrieDB().IsUsingZktrie() {
encoded = common.CopyBytes(value[:])
} else {
// Encoding []byte cannot fail, ok to ignore the error.
encoded, _ = rlp.EncodeToBytes(trimmed) encoded, _ = rlp.EncodeToBytes(trimmed)
}
if err := tr.UpdateStorage(s.address, key[:], trimmed); err != nil { if err := tr.UpdateStorage(s.address, key[:], trimmed); err != nil {
s.db.setError(err) s.db.setError(err)
return nil, err return nil, err

85
core/state/state_prove.go Normal file
View file

@ -0,0 +1,85 @@
package state
import (
"fmt"
zkt "github.com/scroll-tech/zktrie/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
zktrie "github.com/ethereum/go-ethereum/trie"
"github.com/ethereum/go-ethereum/trie/zkproof"
)
type TrieProve interface {
Prove(key []byte, fromLevel uint, proofDb ethdb.KeyValueWriter) error
}
type ZktrieProofTracer struct {
*zktrie.ProofTracer
}
// MarkDeletion overwrite the underlayer method with secure key
func (t ZktrieProofTracer) MarkDeletion(key common.Hash) {
key_s, _ := zkt.ToSecureKeyBytes(key.Bytes())
t.ProofTracer.MarkDeletion(key_s.Bytes())
}
// Merge overwrite underlayer method with proper argument
func (t ZktrieProofTracer) Merge(another ZktrieProofTracer) {
t.ProofTracer.Merge(another.ProofTracer)
}
func (t ZktrieProofTracer) Available() bool {
return t.ProofTracer != nil
}
// NewProofTracer is not in Db interface and used explictily for reading proof in storage trie (not updated by the dirty value)
func (s *StateDB) NewProofTracer(trieS Trie) ZktrieProofTracer {
if s.IsUsingZktrie() {
zkTrie := trieS.(*zktrie.ZkTrie)
if zkTrie == nil {
panic("unexpected trie type for zktrie")
}
return ZktrieProofTracer{zkTrie.NewProofTracer()}
}
return ZktrieProofTracer{}
}
// GetStorageTrieForProof is not in Db interface and used explictily for reading proof in storage trie (not updated by the dirty value)
func (s *StateDB) GetStorageTrieForProof(addr common.Address) (Trie, error) {
// try the trie in stateObject first, else we would create one
stateObject := s.getStateObject(addr)
if stateObject == nil {
// still return a empty trie
dummy_trie, _ := s.db.OpenStorageTrie(s.originalRoot, addr, common.Hash{})
return dummy_trie, nil
}
trie := stateObject.trie
var err error
if trie == nil {
// use a new, temporary trie
trie, err = s.db.OpenStorageTrie(s.originalRoot, stateObject.address, stateObject.data.Root)
if err != nil {
return nil, fmt.Errorf("can't create storage trie on root %s: %v ", stateObject.data.Root, err)
}
}
return trie, nil
}
// GetSecureTrieProof handle any interface with Prove (should be a Trie in most case) and
// deliver the proof in bytes
func (s *StateDB) GetSecureTrieProof(trieProve TrieProve, key common.Hash) ([][]byte, error) {
var proof zkproof.ProofList
var err error
if s.IsUsingZktrie() {
key_s, _ := zkt.ToSecureKeyBytes(key.Bytes())
err = trieProve.Prove(key_s.Bytes(), 0, &proof)
} else {
err = trieProve.Prove(crypto.Keccak256(key.Bytes()), 0, &proof)
}
return proof, err
}

View file

@ -63,27 +63,33 @@ func TestDump(t *testing.T) {
s.state, _ = New(root, tdb, nil) s.state, _ = New(root, tdb, nil)
got := string(s.state.Dump(nil)) got := string(s.state.Dump(nil))
want := `{ want := `{
"root": "71edff0130dd2385947095001c73d9e28d862fc286fca2b922ca6f6f3cddfdd2", "root": "789955993afb9d2a04b957a91be5d7b139aabb60fb7af63df6405021211c13c4",
"accounts": { "accounts": {
"0x0000000000000000000000000000000000000001": { "0x0000000000000000000000000000000000000001": {
"balance": "22", "balance": "22",
"nonce": 0, "nonce": 0,
"root": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "root": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"codeHash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "keccakCodeHash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
"poseidonCodeHash": "0x2098f5fb9e239eab3ceac3f27b81e481dc3124d55ffed523a839ee8446b64864",
"codeSize": 0,
"key": "0x1468288056310c82aa4c01a7e12a10f8111a0560e72b700555479031b86c357d" "key": "0x1468288056310c82aa4c01a7e12a10f8111a0560e72b700555479031b86c357d"
}, },
"0x0000000000000000000000000000000000000002": { "0x0000000000000000000000000000000000000002": {
"balance": "44", "balance": "44",
"nonce": 0, "nonce": 0,
"root": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "root": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"codeHash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "keccakCodeHash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
"poseidonCodeHash": "0x2098f5fb9e239eab3ceac3f27b81e481dc3124d55ffed523a839ee8446b64864",
"codeSize": 0,
"key": "0xd52688a8f926c816ca1e079067caba944f158e764817b83fc43594370ca9cf62" "key": "0xd52688a8f926c816ca1e079067caba944f158e764817b83fc43594370ca9cf62"
}, },
"0x0000000000000000000000000000000000000102": { "0x0000000000000000000000000000000000000102": {
"balance": "0", "balance": "0",
"nonce": 0, "nonce": 0,
"root": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "root": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"codeHash": "0x87874902497a5bb968da31a2998d8f22e949d1ef6214bcdedd8bae24cca4b9e3", "keccakCodeHash": "0x87874902497a5bb968da31a2998d8f22e949d1ef6214bcdedd8bae24cca4b9e3",
"poseidonCodeHash": "0x1f090de833dd6dee7af5ee49f94fd64d1079aee3df47795eaaf2775d6921458c",
"codeSize": 7,
"code": "0x03030303030303", "code": "0x03030303030303",
"key": "0xa17eacbc25cda025e81db9c5c62868822c73ce097cee2a63e33a2e41268358a1" "key": "0xa17eacbc25cda025e81db9c5c62868822c73ce097cee2a63e33a2e41268358a1"
} }
@ -120,11 +126,11 @@ func TestIterativeDump(t *testing.T) {
s.state.IterativeDump(nil, json.NewEncoder(b)) s.state.IterativeDump(nil, json.NewEncoder(b))
// check that DumpToCollector contains the state objects that are in trie // check that DumpToCollector contains the state objects that are in trie
got := b.String() got := b.String()
want := `{"root":"0xd5710ea8166b7b04bc2bfb129d7db12931cee82f75ca8e2d075b4884322bf3de"} want := `{"root":"0xb52efb616edbf7ae4914e756bd3fe7ff4d06dd914d613123517171d610f33d5c"}
{"balance":"22","nonce":0,"root":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","codeHash":"0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470","address":"0x0000000000000000000000000000000000000001","key":"0x1468288056310c82aa4c01a7e12a10f8111a0560e72b700555479031b86c357d"} {"balance":"22","nonce":0,"root":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","keccakCodeHash":"0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470","poseidonCodeHash":"0x2098f5fb9e239eab3ceac3f27b81e481dc3124d55ffed523a839ee8446b64864","codeSize":0,"address":"0x0000000000000000000000000000000000000001","key":"0x1468288056310c82aa4c01a7e12a10f8111a0560e72b700555479031b86c357d"}
{"balance":"1337","nonce":0,"root":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","codeHash":"0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470","address":"0x0000000000000000000000000000000000000000","key":"0x5380c7b7ae81a58eb98d9c78de4a1fd7fd9535fc953ed2be602daaa41767312a"} {"balance":"1337","nonce":0,"root":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","keccakCodeHash":"0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470","poseidonCodeHash":"0x2098f5fb9e239eab3ceac3f27b81e481dc3124d55ffed523a839ee8446b64864","codeSize":0,"address":"0x0000000000000000000000000000000000000000","key":"0x5380c7b7ae81a58eb98d9c78de4a1fd7fd9535fc953ed2be602daaa41767312a"}
{"balance":"0","nonce":0,"root":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","codeHash":"0x87874902497a5bb968da31a2998d8f22e949d1ef6214bcdedd8bae24cca4b9e3","code":"0x03030303030303","address":"0x0000000000000000000000000000000000000102","key":"0xa17eacbc25cda025e81db9c5c62868822c73ce097cee2a63e33a2e41268358a1"} {"balance":"0","nonce":0,"root":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","keccakCodeHash":"0x87874902497a5bb968da31a2998d8f22e949d1ef6214bcdedd8bae24cca4b9e3","poseidonCodeHash":"0x1f090de833dd6dee7af5ee49f94fd64d1079aee3df47795eaaf2775d6921458c","codeSize":7,"code":"0x03030303030303","address":"0x0000000000000000000000000000000000000102","key":"0xa17eacbc25cda025e81db9c5c62868822c73ce097cee2a63e33a2e41268358a1"}
{"balance":"44","nonce":0,"root":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","codeHash":"0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470","address":"0x0000000000000000000000000000000000000002","key":"0xd52688a8f926c816ca1e079067caba944f158e764817b83fc43594370ca9cf62"} {"balance":"44","nonce":0,"root":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","keccakCodeHash":"0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470","poseidonCodeHash":"0x2098f5fb9e239eab3ceac3f27b81e481dc3124d55ffed523a839ee8446b64864","codeSize":0,"address":"0x0000000000000000000000000000000000000002","key":"0xd52688a8f926c816ca1e079067caba944f158e764817b83fc43594370ca9cf62"}
` `
if got != want { if got != want {
t.Errorf("DumpToCollector mismatch:\ngot: %s\nwant: %s\n", got, want) t.Errorf("DumpToCollector mismatch:\ngot: %s\nwant: %s\n", got, want)
@ -261,6 +267,12 @@ func compareStateObjects(so0, so1 *stateObject, t *testing.T) {
if !bytes.Equal(so0.KeccakCodeHash(), so1.KeccakCodeHash()) { if !bytes.Equal(so0.KeccakCodeHash(), so1.KeccakCodeHash()) {
t.Fatalf("CodeHash mismatch: have %v, want %v", so0.KeccakCodeHash(), so1.KeccakCodeHash()) t.Fatalf("CodeHash 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) { if !bytes.Equal(so0.code, so1.code) {
t.Fatalf("Code mismatch: have %v, want %v", so0.code, so1.code) t.Fatalf("Code mismatch: have %v, want %v", so0.code, so1.code)
} }

View file

@ -206,6 +206,10 @@ func (s *StateDB) Error() error {
return s.dbErr return s.dbErr
} }
func (s *StateDB) IsUsingZktrie() bool {
return s.db.TrieDB().IsUsingZktrie()
}
func (s *StateDB) AddLog(log *types.Log) { func (s *StateDB) AddLog(log *types.Log) {
s.journal.append(addLogChange{txhash: s.thash}) s.journal.append(addLogChange{txhash: s.thash})

View file

@ -0,0 +1,107 @@
// Copyright 2021 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package types
import (
"encoding/binary"
"errors"
"math/big"
"github.com/iden3/go-iden3-crypto/utils"
zkt "github.com/scroll-tech/zktrie/types"
"github.com/ethereum/go-ethereum/common"
)
var (
ErrInvalidLength = errors.New("StateAccount: invalid input length")
)
// 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] StorageRoot
// [96:128] KeccakCodeHash
// [128:160] PoseidonCodehash
// (total 160 bytes)
func (s *StateAccount) MarshalFields() ([]zkt.Byte32, uint32) {
fields := make([]zkt.Byte32, 5)
if s.Balance == nil {
panic("StateAccount balance nil")
}
if !utils.CheckBigIntInField(s.Balance) {
panic("StateAccount balance overflow")
}
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) != 160 {
return nil, ErrInvalidLength
}
acc := new(StateAccount)
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.Root = common.Hash{}
acc.Root.SetBytes(bytes[64:96])
acc.KeccakCodeHash = make([]byte, 32)
copy(acc.KeccakCodeHash, bytes[96:128])
acc.PoseidonCodeHash = make([]byte, 32)
copy(acc.PoseidonCodeHash, bytes[128:160])
return acc, nil
}

View file

@ -0,0 +1,189 @@
package types
import (
"math"
"math/big"
"testing"
"github.com/iden3/go-iden3-crypto/constants"
"github.com/stretchr/testify/assert"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto/codehash"
)
func assertAccountsEqual(t *testing.T, expected *StateAccount, actual *StateAccount) {
assert.Equal(t, expected.Nonce, actual.Nonce)
assert.Zero(t, expected.Balance.Cmp(actual.Balance))
assert.Equal(t, expected.Root, actual.Root)
assert.Equal(t, expected.KeccakCodeHash, actual.KeccakCodeHash)
assert.Equal(t, expected.PoseidonCodeHash, actual.PoseidonCodeHash)
assert.Equal(t, expected.CodeSize, actual.CodeSize)
}
func TestMarshalUnmarshalEmptyAccount(t *testing.T) {
acc := StateAccount{
Nonce: 0,
Balance: big.NewInt(0),
Root: common.Hash{},
KeccakCodeHash: codehash.EmptyKeccakCodeHash.Bytes(),
PoseidonCodeHash: codehash.EmptyPoseidonCodeHash.Bytes(),
CodeSize: 0,
}
// marshal account
bytes, flag := acc.MarshalFields()
assert.Equal(t, 5, len(bytes))
assert.Equal(t, uint32(8), flag)
assert.Equal(t, common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000000"), bytes[0].Bytes())
assert.Equal(t, common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000000"), bytes[1].Bytes())
assert.Equal(t, common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000000"), bytes[2].Bytes())
assert.Equal(t, common.Hex2Bytes("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"), bytes[3].Bytes())
assert.Equal(t, common.Hex2Bytes("2098f5fb9e239eab3ceac3f27b81e481dc3124d55ffed523a839ee8446b64864"), bytes[4].Bytes())
// unmarshal account
flatBytes := []byte("")
for _, item := range bytes {
flatBytes = append(flatBytes, item.Bytes()...)
}
acc2, err := UnmarshalStateAccount(flatBytes)
assert.Nil(t, err)
assertAccountsEqual(t, &acc, acc2)
}
func TestMarshalUnmarshalZeroAccount(t *testing.T) {
acc := StateAccount{
Nonce: 0,
Balance: big.NewInt(0),
Root: common.Hash{},
KeccakCodeHash: make([]byte, 0),
PoseidonCodeHash: make([]byte, 0),
CodeSize: 0,
}
// marshal account
bytes, flag := acc.MarshalFields()
assert.Equal(t, 5, len(bytes))
assert.Equal(t, uint32(8), flag)
assert.Equal(t, common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000000"), bytes[0].Bytes())
assert.Equal(t, common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000000"), bytes[1].Bytes())
assert.Equal(t, common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000000"), bytes[2].Bytes())
assert.Equal(t, common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000000"), bytes[3].Bytes())
assert.Equal(t, common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000000"), bytes[4].Bytes())
}
func TestMarshalUnmarshalNonEmptyAccount(t *testing.T) {
acc := StateAccount{
Nonce: 0x11111111,
Balance: big.NewInt(0x33333333),
Root: common.HexToHash("123456789abcdef123456789abcdef123456789abcdef123456789abcdef1234"),
KeccakCodeHash: common.Hex2Bytes("1111111111111111111111111111111111111111111111111111111111111111"),
PoseidonCodeHash: common.Hex2Bytes("2222222222222222222222222222222222222222222222222222222222222222"),
CodeSize: 0x22222222,
}
// marshal account
bytes, flag := acc.MarshalFields()
assert.Equal(t, 5, len(bytes))
assert.Equal(t, uint32(8), flag)
assert.Equal(t, common.Hex2Bytes("0000000000000000000000000000000000000000222222220000000011111111"), bytes[0].Bytes())
assert.Equal(t, common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000033333333"), bytes[1].Bytes())
assert.Equal(t, common.Hex2Bytes("123456789abcdef123456789abcdef123456789abcdef123456789abcdef1234"), bytes[2].Bytes())
assert.Equal(t, common.Hex2Bytes("1111111111111111111111111111111111111111111111111111111111111111"), bytes[3].Bytes())
assert.Equal(t, common.Hex2Bytes("2222222222222222222222222222222222222222222222222222222222222222"), bytes[4].Bytes())
// unmarshal account
flatBytes := []byte("")
for _, item := range bytes {
flatBytes = append(flatBytes, item.Bytes()...)
}
acc2, err := UnmarshalStateAccount(flatBytes)
assert.Nil(t, err)
assertAccountsEqual(t, &acc, acc2)
}
func TestMarshalUnmarshalAccountWithMaxFields(t *testing.T) {
maxFieldElement := new(big.Int).Sub(constants.Q, big.NewInt(1))
acc := StateAccount{
Nonce: math.MaxUint64,
Balance: maxFieldElement,
Root: common.BigToHash(maxFieldElement),
KeccakCodeHash: common.Hex2Bytes("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
PoseidonCodeHash: maxFieldElement.Bytes(),
CodeSize: math.MaxUint64,
}
// marshal account
bytes, flag := acc.MarshalFields()
assert.Equal(t, 5, len(bytes))
assert.Equal(t, uint32(8), flag)
assert.Equal(t, common.Hex2Bytes("00000000000000000000000000000000ffffffffffffffffffffffffffffffff"), bytes[0].Bytes())
assert.Equal(t, common.Hex2Bytes("30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000"), bytes[1].Bytes())
assert.Equal(t, common.Hex2Bytes("30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000"), bytes[2].Bytes())
assert.Equal(t, common.Hex2Bytes("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), bytes[3].Bytes())
assert.Equal(t, common.Hex2Bytes("30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000"), bytes[4].Bytes())
// unmarshal account
flatBytes := []byte("")
for _, item := range bytes {
flatBytes = append(flatBytes, item.Bytes()...)
}
acc2, err := UnmarshalStateAccount(flatBytes)
assert.Nil(t, err)
assertAccountsEqual(t, &acc, acc2)
}
func TestMarshalPanic(t *testing.T) {
assert.PanicsWithValue(t, "StateAccount balance nil", func() {
acc := StateAccount{}
acc.MarshalFields()
})
assert.PanicsWithValue(t, "StateAccount balance overflow", func() {
acc := StateAccount{Balance: constants.Q}
acc.MarshalFields()
})
assert.PanicsWithValue(t, "StateAccount balance overflow", func() {
balance := new(big.Int)
balance, ok := balance.SetString("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16)
assert.True(t, ok)
acc := StateAccount{Balance: balance}
acc.MarshalFields()
})
assert.PanicsWithValue(t, "StateAccount root overflow", func() {
acc := StateAccount{Balance: big.NewInt(0), Root: common.BigToHash(constants.Q)}
acc.MarshalFields()
})
assert.PanicsWithValue(t, "StateAccount poseidonCodeHash overflow", func() {
acc := StateAccount{Balance: big.NewInt(0), PoseidonCodeHash: constants.Q.Bytes()}
acc.MarshalFields()
})
}

View file

@ -514,7 +514,7 @@ func (s *Ethereum) SyncService() *sync_service.SyncService { return s.syncServic
// network protocols to start. // network protocols to start.
func (s *Ethereum) Protocols() []p2p.Protocol { func (s *Ethereum) Protocols() []p2p.Protocol {
protos := eth.MakeProtocols((*ethHandler)(s.handler), s.networkID, s.ethDialCandidates) protos := eth.MakeProtocols((*ethHandler)(s.handler), s.networkID, s.ethDialCandidates)
if s.config.SnapshotCache > 0 { if !s.blockchain.Config().Scroll.ZktrieEnabled() && s.config.SnapshotCache > 0 {
protos = append(protos, snap.MakeProtocols((*snapHandler)(s.handler), s.snapDialCandidates)...) protos = append(protos, snap.MakeProtocols((*snapHandler)(s.handler), s.snapDialCandidates)...)
} }
return protos return protos
@ -533,12 +533,12 @@ func (s *Ethereum) Start() error {
// Figure out a max peers count based on the server limits // Figure out a max peers count based on the server limits
maxPeers := s.p2pServer.MaxPeers maxPeers := s.p2pServer.MaxPeers
if s.config.LightServ > 0 { // if s.config.LightServ > 0 {
if s.config.LightPeers >= s.p2pServer.MaxPeers { // if s.config.LightPeers >= s.p2pServer.MaxPeers {
return fmt.Errorf("invalid peer config: light peer count (%d) >= total peer count (%d)", s.config.LightPeers, s.p2pServer.MaxPeers) // return fmt.Errorf("invalid peer config: light peer count (%d) >= total peer count (%d)", s.config.LightPeers, s.p2pServer.MaxPeers)
} // }
maxPeers -= s.config.LightPeers // maxPeers -= s.config.LightPeers
} // }
// Start the networking layer and the light server if requested // Start the networking layer and the light server if requested
s.handler.Start(maxPeers) s.handler.Start(maxPeers)
return nil return nil

View file

@ -286,21 +286,21 @@ func TestFilters(t *testing.T) {
}{ }{
{ {
f: sys.NewBlockFilter(chain[2].Hash(), []common.Address{contract}, nil), f: sys.NewBlockFilter(chain[2].Hash(), []common.Address{contract}, nil),
want: `[{"address":"0xfe00000000000000000000000000000000000000","topics":["0x0000000000000000000000000000000000000000000000000000746f70696332","0x0000000000000000000000000000000000000000000000000000746f70696331"],"data":"0x","blockNumber":"0x3","transactionHash":"0xdefe471992a07a02acdfbe33edaae22fbb86d7d3cec3f1b8e4e77702fb3acc1d","transactionIndex":"0x0","blockHash":"0x7a7556792ca7d37882882e2b001fe14833eaf81c2c7f865c9c771ec37a024f6b","logIndex":"0x0","removed":false}]`, want: `[{"address":"0xfe00000000000000000000000000000000000000","topics":["0x0000000000000000000000000000000000000000000000000000746f70696332","0x0000000000000000000000000000000000000000000000000000746f70696331"],"data":"0x","blockNumber":"0x3","transactionHash":"0xdefe471992a07a02acdfbe33edaae22fbb86d7d3cec3f1b8e4e77702fb3acc1d","transactionIndex":"0x0","blockHash":"0xb4871b3f94b8d0375f195bbabc42afe0ee9bb855041f191305241a150177b647","logIndex":"0x0","removed":false}]`,
}, { }, {
f: sys.NewRangeFilter(0, int64(rpc.LatestBlockNumber), []common.Address{contract}, [][]common.Hash{{hash1, hash2, hash3, hash4}}), f: sys.NewRangeFilter(0, int64(rpc.LatestBlockNumber), []common.Address{contract}, [][]common.Hash{{hash1, hash2, hash3, hash4}}),
want: `[{"address":"0xfe00000000000000000000000000000000000000","topics":["0x0000000000000000000000000000000000000000000000000000746f70696331"],"data":"0x","blockNumber":"0x2","transactionHash":"0xa8028c655b6423204c8edfbc339f57b042d6bec2b6a61145d76b7c08b4cccd42","transactionIndex":"0x0","blockHash":"0x24417bb49ce44cfad65da68f33b510bf2a129c0d89ccf06acb6958b8585ccf34","logIndex":"0x0","removed":false},{"address":"0xfe00000000000000000000000000000000000000","topics":["0x0000000000000000000000000000000000000000000000000000746f70696332","0x0000000000000000000000000000000000000000000000000000746f70696331"],"data":"0x","blockNumber":"0x3","transactionHash":"0xdefe471992a07a02acdfbe33edaae22fbb86d7d3cec3f1b8e4e77702fb3acc1d","transactionIndex":"0x0","blockHash":"0x7a7556792ca7d37882882e2b001fe14833eaf81c2c7f865c9c771ec37a024f6b","logIndex":"0x0","removed":false},{"address":"0xfe00000000000000000000000000000000000000","topics":["0x0000000000000000000000000000000000000000000000000000746f70696334"],"data":"0x","blockNumber":"0x3e8","transactionHash":"0x9a87842100a638dfa5da8842b4beda691d2fd77b0c84b57f24ecfa9fb208f747","transactionIndex":"0x0","blockHash":"0xb360bad5265261c075ece02d3bf0e39498a6a76310482cdfd90588748e6c5ee0","logIndex":"0x0","removed":false}]`, want: `[{"address":"0xfe00000000000000000000000000000000000000","topics":["0x0000000000000000000000000000000000000000000000000000746f70696331"],"data":"0x","blockNumber":"0x2","transactionHash":"0xa8028c655b6423204c8edfbc339f57b042d6bec2b6a61145d76b7c08b4cccd42","transactionIndex":"0x0","blockHash":"0x1e7d940a070e5e44f2c3824edec50b7733656a525c8fee7a25f653019bc7517a","logIndex":"0x0","removed":false},{"address":"0xfe00000000000000000000000000000000000000","topics":["0x0000000000000000000000000000000000000000000000000000746f70696332","0x0000000000000000000000000000000000000000000000000000746f70696331"],"data":"0x","blockNumber":"0x3","transactionHash":"0xdefe471992a07a02acdfbe33edaae22fbb86d7d3cec3f1b8e4e77702fb3acc1d","transactionIndex":"0x0","blockHash":"0xb4871b3f94b8d0375f195bbabc42afe0ee9bb855041f191305241a150177b647","logIndex":"0x0","removed":false},{"address":"0xfe00000000000000000000000000000000000000","topics":["0x0000000000000000000000000000000000000000000000000000746f70696334"],"data":"0x","blockNumber":"0x3e8","transactionHash":"0x9a87842100a638dfa5da8842b4beda691d2fd77b0c84b57f24ecfa9fb208f747","transactionIndex":"0x0","blockHash":"0x12d5def71baa80ab362473517837a854b814e4c5205a28e9139cd7feb5602a4c","logIndex":"0x0","removed":false}]`,
}, { }, {
f: sys.NewRangeFilter(900, 999, []common.Address{contract}, [][]common.Hash{{hash3}}), f: sys.NewRangeFilter(900, 999, []common.Address{contract}, [][]common.Hash{{hash3}}),
}, { }, {
f: sys.NewRangeFilter(990, int64(rpc.LatestBlockNumber), []common.Address{contract2}, [][]common.Hash{{hash3}}), f: sys.NewRangeFilter(990, int64(rpc.LatestBlockNumber), []common.Address{contract2}, [][]common.Hash{{hash3}}),
want: `[{"address":"0xff00000000000000000000000000000000000000","topics":["0x0000000000000000000000000000000000000000000000000000746f70696333"],"data":"0x","blockNumber":"0x3e7","transactionHash":"0x53e3675800c6908424b61b35a44e51ca4c73ca603e58a65b32c67968b4f42200","transactionIndex":"0x0","blockHash":"0x2e4620a2b426b0612ec6cad9603f466723edaed87f98c9137405dd4f7a2409ff","logIndex":"0x0","removed":false}]`, want: `[{"address":"0xff00000000000000000000000000000000000000","topics":["0x0000000000000000000000000000000000000000000000000000746f70696333"],"data":"0x","blockNumber":"0x3e7","transactionHash":"0x53e3675800c6908424b61b35a44e51ca4c73ca603e58a65b32c67968b4f42200","transactionIndex":"0x0","blockHash":"0xdcd5f41895e0992f1e5eb5fab7e78c0bc2a99efb667b2145be2e75a07a2d8cee","logIndex":"0x0","removed":false}]`,
}, { }, {
f: sys.NewRangeFilter(1, 10, []common.Address{contract}, [][]common.Hash{{hash2}, {hash1}}), f: sys.NewRangeFilter(1, 10, []common.Address{contract}, [][]common.Hash{{hash2}, {hash1}}),
want: `[{"address":"0xfe00000000000000000000000000000000000000","topics":["0x0000000000000000000000000000000000000000000000000000746f70696332","0x0000000000000000000000000000000000000000000000000000746f70696331"],"data":"0x","blockNumber":"0x3","transactionHash":"0xdefe471992a07a02acdfbe33edaae22fbb86d7d3cec3f1b8e4e77702fb3acc1d","transactionIndex":"0x0","blockHash":"0x7a7556792ca7d37882882e2b001fe14833eaf81c2c7f865c9c771ec37a024f6b","logIndex":"0x0","removed":false}]`, want: `[{"address":"0xfe00000000000000000000000000000000000000","topics":["0x0000000000000000000000000000000000000000000000000000746f70696332","0x0000000000000000000000000000000000000000000000000000746f70696331"],"data":"0x","blockNumber":"0x3","transactionHash":"0xdefe471992a07a02acdfbe33edaae22fbb86d7d3cec3f1b8e4e77702fb3acc1d","transactionIndex":"0x0","blockHash":"0xb4871b3f94b8d0375f195bbabc42afe0ee9bb855041f191305241a150177b647","logIndex":"0x0","removed":false}]`,
}, { }, {
f: sys.NewRangeFilter(1, 10, nil, [][]common.Hash{{hash1, hash2}}), f: sys.NewRangeFilter(1, 10, nil, [][]common.Hash{{hash1, hash2}}),
want: `[{"address":"0xfe00000000000000000000000000000000000000","topics":["0x0000000000000000000000000000000000000000000000000000746f70696331"],"data":"0x","blockNumber":"0x2","transactionHash":"0xa8028c655b6423204c8edfbc339f57b042d6bec2b6a61145d76b7c08b4cccd42","transactionIndex":"0x0","blockHash":"0x24417bb49ce44cfad65da68f33b510bf2a129c0d89ccf06acb6958b8585ccf34","logIndex":"0x0","removed":false},{"address":"0xff00000000000000000000000000000000000000","topics":["0x0000000000000000000000000000000000000000000000000000746f70696331"],"data":"0x","blockNumber":"0x2","transactionHash":"0xdba3e2ea9a7d690b722d70ee605fd67ba4c00d1d3aecd5cf187a7b92ad8eb3df","transactionIndex":"0x1","blockHash":"0x24417bb49ce44cfad65da68f33b510bf2a129c0d89ccf06acb6958b8585ccf34","logIndex":"0x1","removed":false},{"address":"0xfe00000000000000000000000000000000000000","topics":["0x0000000000000000000000000000000000000000000000000000746f70696332","0x0000000000000000000000000000000000000000000000000000746f70696331"],"data":"0x","blockNumber":"0x3","transactionHash":"0xdefe471992a07a02acdfbe33edaae22fbb86d7d3cec3f1b8e4e77702fb3acc1d","transactionIndex":"0x0","blockHash":"0x7a7556792ca7d37882882e2b001fe14833eaf81c2c7f865c9c771ec37a024f6b","logIndex":"0x0","removed":false}]`, want: `[{"address":"0xfe00000000000000000000000000000000000000","topics":["0x0000000000000000000000000000000000000000000000000000746f70696331"],"data":"0x","blockNumber":"0x2","transactionHash":"0xa8028c655b6423204c8edfbc339f57b042d6bec2b6a61145d76b7c08b4cccd42","transactionIndex":"0x0","blockHash":"0x1e7d940a070e5e44f2c3824edec50b7733656a525c8fee7a25f653019bc7517a","logIndex":"0x0","removed":false},{"address":"0xff00000000000000000000000000000000000000","topics":["0x0000000000000000000000000000000000000000000000000000746f70696331"],"data":"0x","blockNumber":"0x2","transactionHash":"0xdba3e2ea9a7d690b722d70ee605fd67ba4c00d1d3aecd5cf187a7b92ad8eb3df","transactionIndex":"0x1","blockHash":"0x1e7d940a070e5e44f2c3824edec50b7733656a525c8fee7a25f653019bc7517a","logIndex":"0x1","removed":false},{"address":"0xfe00000000000000000000000000000000000000","topics":["0x0000000000000000000000000000000000000000000000000000746f70696332","0x0000000000000000000000000000000000000000000000000000746f70696331"],"data":"0x","blockNumber":"0x3","transactionHash":"0xdefe471992a07a02acdfbe33edaae22fbb86d7d3cec3f1b8e4e77702fb3acc1d","transactionIndex":"0x0","blockHash":"0xb4871b3f94b8d0375f195bbabc42afe0ee9bb855041f191305241a150177b647","logIndex":"0x0","removed":false}]`,
}, { }, {
f: sys.NewRangeFilter(0, int64(rpc.LatestBlockNumber), nil, [][]common.Hash{{common.BytesToHash([]byte("fail"))}}), f: sys.NewRangeFilter(0, int64(rpc.LatestBlockNumber), nil, [][]common.Hash{{common.BytesToHash([]byte("fail"))}}),
}, { }, {
@ -309,13 +309,13 @@ func TestFilters(t *testing.T) {
f: sys.NewRangeFilter(0, int64(rpc.LatestBlockNumber), nil, [][]common.Hash{{common.BytesToHash([]byte("fail"))}, {hash1}}), f: sys.NewRangeFilter(0, int64(rpc.LatestBlockNumber), nil, [][]common.Hash{{common.BytesToHash([]byte("fail"))}, {hash1}}),
}, { }, {
f: sys.NewRangeFilter(int64(rpc.LatestBlockNumber), int64(rpc.LatestBlockNumber), nil, nil), f: sys.NewRangeFilter(int64(rpc.LatestBlockNumber), int64(rpc.LatestBlockNumber), nil, nil),
want: `[{"address":"0xfe00000000000000000000000000000000000000","topics":["0x0000000000000000000000000000000000000000000000000000746f70696334"],"data":"0x","blockNumber":"0x3e8","transactionHash":"0x9a87842100a638dfa5da8842b4beda691d2fd77b0c84b57f24ecfa9fb208f747","transactionIndex":"0x0","blockHash":"0xb360bad5265261c075ece02d3bf0e39498a6a76310482cdfd90588748e6c5ee0","logIndex":"0x0","removed":false}]`, want: `[{"address":"0xfe00000000000000000000000000000000000000","topics":["0x0000000000000000000000000000000000000000000000000000746f70696334"],"data":"0x","blockNumber":"0x3e8","transactionHash":"0x9a87842100a638dfa5da8842b4beda691d2fd77b0c84b57f24ecfa9fb208f747","transactionIndex":"0x0","blockHash":"0x12d5def71baa80ab362473517837a854b814e4c5205a28e9139cd7feb5602a4c","logIndex":"0x0","removed":false}]`,
}, { }, {
f: sys.NewRangeFilter(int64(rpc.FinalizedBlockNumber), int64(rpc.LatestBlockNumber), nil, nil), f: sys.NewRangeFilter(int64(rpc.FinalizedBlockNumber), int64(rpc.LatestBlockNumber), nil, nil),
want: `[{"address":"0xff00000000000000000000000000000000000000","topics":["0x0000000000000000000000000000000000000000000000000000746f70696333"],"data":"0x","blockNumber":"0x3e7","transactionHash":"0x53e3675800c6908424b61b35a44e51ca4c73ca603e58a65b32c67968b4f42200","transactionIndex":"0x0","blockHash":"0x2e4620a2b426b0612ec6cad9603f466723edaed87f98c9137405dd4f7a2409ff","logIndex":"0x0","removed":false},{"address":"0xfe00000000000000000000000000000000000000","topics":["0x0000000000000000000000000000000000000000000000000000746f70696334"],"data":"0x","blockNumber":"0x3e8","transactionHash":"0x9a87842100a638dfa5da8842b4beda691d2fd77b0c84b57f24ecfa9fb208f747","transactionIndex":"0x0","blockHash":"0xb360bad5265261c075ece02d3bf0e39498a6a76310482cdfd90588748e6c5ee0","logIndex":"0x0","removed":false}]`, want: `[{"address":"0xff00000000000000000000000000000000000000","topics":["0x0000000000000000000000000000000000000000000000000000746f70696333"],"data":"0x","blockNumber":"0x3e7","transactionHash":"0x53e3675800c6908424b61b35a44e51ca4c73ca603e58a65b32c67968b4f42200","transactionIndex":"0x0","blockHash":"0xdcd5f41895e0992f1e5eb5fab7e78c0bc2a99efb667b2145be2e75a07a2d8cee","logIndex":"0x0","removed":false},{"address":"0xfe00000000000000000000000000000000000000","topics":["0x0000000000000000000000000000000000000000000000000000746f70696334"],"data":"0x","blockNumber":"0x3e8","transactionHash":"0x9a87842100a638dfa5da8842b4beda691d2fd77b0c84b57f24ecfa9fb208f747","transactionIndex":"0x0","blockHash":"0x12d5def71baa80ab362473517837a854b814e4c5205a28e9139cd7feb5602a4c","logIndex":"0x0","removed":false}]`,
}, { }, {
f: sys.NewRangeFilter(int64(rpc.FinalizedBlockNumber), int64(rpc.FinalizedBlockNumber), nil, nil), f: sys.NewRangeFilter(int64(rpc.FinalizedBlockNumber), int64(rpc.FinalizedBlockNumber), nil, nil),
want: `[{"address":"0xff00000000000000000000000000000000000000","topics":["0x0000000000000000000000000000000000000000000000000000746f70696333"],"data":"0x","blockNumber":"0x3e7","transactionHash":"0x53e3675800c6908424b61b35a44e51ca4c73ca603e58a65b32c67968b4f42200","transactionIndex":"0x0","blockHash":"0x2e4620a2b426b0612ec6cad9603f466723edaed87f98c9137405dd4f7a2409ff","logIndex":"0x0","removed":false}]`, want: `[{"address":"0xff00000000000000000000000000000000000000","topics":["0x0000000000000000000000000000000000000000000000000000746f70696333"],"data":"0x","blockNumber":"0x3e7","transactionHash":"0x53e3675800c6908424b61b35a44e51ca4c73ca603e58a65b32c67968b4f42200","transactionIndex":"0x0","blockHash":"0xdcd5f41895e0992f1e5eb5fab7e78c0bc2a99efb667b2145be2e75a07a2d8cee","logIndex":"0x0","removed":false}]`,
}, { }, {
f: sys.NewRangeFilter(int64(rpc.LatestBlockNumber), int64(rpc.FinalizedBlockNumber), nil, nil), f: sys.NewRangeFilter(int64(rpc.LatestBlockNumber), int64(rpc.FinalizedBlockNumber), nil, nil),
}, { }, {
@ -329,10 +329,10 @@ func TestFilters(t *testing.T) {
err: "safe header not found", err: "safe header not found",
}, { }, {
f: sys.NewRangeFilter(int64(rpc.PendingBlockNumber), int64(rpc.PendingBlockNumber), nil, nil), f: sys.NewRangeFilter(int64(rpc.PendingBlockNumber), int64(rpc.PendingBlockNumber), nil, nil),
want: `[{"address":"0xfe00000000000000000000000000000000000000","topics":["0x0000000000000000000000000000000000000000000000000000746f70696335"],"data":"0x","blockNumber":"0x3e9","transactionHash":"0x4110587c1b8d86edc85dce929a34127f1cb8809515a9f177c91c866de3eb0638","transactionIndex":"0x0","blockHash":"0xc7245899e5817f16fa99cf5ad2d9c1e4b98443a565a673ec9c764640443ef037","logIndex":"0x0","removed":false}]`, want: `[{"address":"0xfe00000000000000000000000000000000000000","topics":["0x0000000000000000000000000000000000000000000000000000746f70696335"],"data":"0x","blockNumber":"0x3e9","transactionHash":"0x4110587c1b8d86edc85dce929a34127f1cb8809515a9f177c91c866de3eb0638","transactionIndex":"0x0","blockHash":"0xfaf12ee5c179618e694f8d3f45e0d962e1e64a45a57627792a22379a49270c08","logIndex":"0x0","removed":false}]`,
}, { }, {
f: sys.NewRangeFilter(int64(rpc.LatestBlockNumber), int64(rpc.PendingBlockNumber), nil, nil), f: sys.NewRangeFilter(int64(rpc.LatestBlockNumber), int64(rpc.PendingBlockNumber), nil, nil),
want: `[{"address":"0xfe00000000000000000000000000000000000000","topics":["0x0000000000000000000000000000000000000000000000000000746f70696334"],"data":"0x","blockNumber":"0x3e8","transactionHash":"0x9a87842100a638dfa5da8842b4beda691d2fd77b0c84b57f24ecfa9fb208f747","transactionIndex":"0x0","blockHash":"0xb360bad5265261c075ece02d3bf0e39498a6a76310482cdfd90588748e6c5ee0","logIndex":"0x0","removed":false},{"address":"0xfe00000000000000000000000000000000000000","topics":["0x0000000000000000000000000000000000000000000000000000746f70696335"],"data":"0x","blockNumber":"0x3e9","transactionHash":"0x4110587c1b8d86edc85dce929a34127f1cb8809515a9f177c91c866de3eb0638","transactionIndex":"0x0","blockHash":"0xc7245899e5817f16fa99cf5ad2d9c1e4b98443a565a673ec9c764640443ef037","logIndex":"0x0","removed":false}]`, want: `[{"address":"0xfe00000000000000000000000000000000000000","topics":["0x0000000000000000000000000000000000000000000000000000746f70696334"],"data":"0x","blockNumber":"0x3e8","transactionHash":"0x9a87842100a638dfa5da8842b4beda691d2fd77b0c84b57f24ecfa9fb208f747","transactionIndex":"0x0","blockHash":"0x12d5def71baa80ab362473517837a854b814e4c5205a28e9139cd7feb5602a4c","logIndex":"0x0","removed":false},{"address":"0xfe00000000000000000000000000000000000000","topics":["0x0000000000000000000000000000000000000000000000000000746f70696335"],"data":"0x","blockNumber":"0x3e9","transactionHash":"0x4110587c1b8d86edc85dce929a34127f1cb8809515a9f177c91c866de3eb0638","transactionIndex":"0x0","blockHash":"0xfaf12ee5c179618e694f8d3f45e0d962e1e64a45a57627792a22379a49270c08","logIndex":"0x0","removed":false}]`,
}, { }, {
f: sys.NewRangeFilter(int64(rpc.PendingBlockNumber), int64(rpc.LatestBlockNumber), nil, nil), f: sys.NewRangeFilter(int64(rpc.PendingBlockNumber), int64(rpc.LatestBlockNumber), nil, nil),
err: "invalid block range", err: "invalid block range",

3
go.mod
View file

@ -42,7 +42,7 @@ require (
github.com/holiman/bloomfilter/v2 v2.0.3 github.com/holiman/bloomfilter/v2 v2.0.3
github.com/holiman/uint256 v1.2.3 github.com/holiman/uint256 v1.2.3
github.com/huin/goupnp v1.3.0 github.com/huin/goupnp v1.3.0
github.com/iden3/go-iden3-crypto v0.0.15 github.com/iden3/go-iden3-crypto v0.0.12
github.com/influxdata/influxdb-client-go/v2 v2.4.0 github.com/influxdata/influxdb-client-go/v2 v2.4.0
github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c
github.com/jackpal/go-nat-pmp v1.0.2 github.com/jackpal/go-nat-pmp v1.0.2
@ -57,6 +57,7 @@ require (
github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7
github.com/protolambda/bls12-381-util v0.0.0-20220416220906-d8552aa452c7 github.com/protolambda/bls12-381-util v0.0.0-20220416220906-d8552aa452c7
github.com/rs/cors v1.7.0 github.com/rs/cors v1.7.0
github.com/scroll-tech/zktrie v0.6.0
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible
github.com/status-im/keycard-go v0.2.0 github.com/status-im/keycard-go v0.2.0
github.com/stretchr/testify v1.8.4 github.com/stretchr/testify v1.8.4

10
go.sum
View file

@ -154,6 +154,7 @@ github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dchest/blake512 v1.0.0/go.mod h1:FV1x7xPPLWukZlpDpWQ88rF/SFwZ5qbskrzhLMB92JI=
github.com/deckarep/golang-set/v2 v2.1.0 h1:g47V4Or+DUdzbs8FxCCmgb6VYd+ptPAngjM6dtGktsI= github.com/deckarep/golang-set/v2 v2.1.0 h1:g47V4Or+DUdzbs8FxCCmgb6VYd+ptPAngjM6dtGktsI=
github.com/deckarep/golang-set/v2 v2.1.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= github.com/deckarep/golang-set/v2 v2.1.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4=
github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0=
@ -351,8 +352,8 @@ github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFck
github.com/hydrogen18/memlistener v0.0.0-20141126152155-54553eb933fb/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE= github.com/hydrogen18/memlistener v0.0.0-20141126152155-54553eb933fb/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w=
github.com/iden3/go-iden3-crypto v0.0.15 h1:4MJYlrot1l31Fzlo2sF56u7EVFeHHJkxGXXZCtESgK4= github.com/iden3/go-iden3-crypto v0.0.12 h1:dXZF+R9iI07DK49LHX/EKC3jTa0O2z+TUyvxjGK7V38=
github.com/iden3/go-iden3-crypto v0.0.15/go.mod h1:dLpM4vEPJ3nDHzhWFXDjzkn1qHoBeOT/3UEhXsEsP3E= github.com/iden3/go-iden3-crypto v0.0.12/go.mod h1:swXIv0HFbJKobbQBtsB50G7IHr6PbTowutSew/iBEoo=
github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/influxdata/influxdb-client-go/v2 v2.4.0 h1:HGBfZYStlx3Kqvsv1h2pJixbCl/jhnFtxpKFAv9Tu5k= github.com/influxdata/influxdb-client-go/v2 v2.4.0 h1:HGBfZYStlx3Kqvsv1h2pJixbCl/jhnFtxpKFAv9Tu5k=
@ -542,6 +543,8 @@ github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw= github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw=
github.com/scroll-tech/zktrie v0.6.0 h1:xLrMAO31Yo2BiPg1jtYKzcjpEFnXy8acbB7iIsyshPs=
github.com/scroll-tech/zktrie v0.6.0/go.mod h1:XvNo7vAk8yxNyTjBDj5WIiFzYW4bx/gJ78+NK6Zn6Uk=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU=
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
@ -621,6 +624,7 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@ -696,6 +700,7 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
@ -774,6 +779,7 @@ golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211020174200-9d6173849985/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211020174200-9d6173849985/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=

View file

@ -4,17 +4,17 @@
"extraData": "0x", "extraData": "0x",
"gasLimit": "0x47e7c4", "gasLimit": "0x47e7c4",
"gasUsed": "0x5208", "gasUsed": "0x5208",
"hash": "0x0da274b315de8e4d5bf8717218ec43540464ef36378cb896469bb731e1d3f3cb", "hash": "0xcc3b85e906fca96a8337bd17a80a0ae26519c77b2a1e47c59911aebc02a801db",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"miner": "0x0000000000000000000000000000000000000000", "miner": "0x0000000000000000000000000000000000000000",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"nonce": "0x0000000000000000", "nonce": "0x0000000000000000",
"number": "0x1", "number": "0x1",
"parentHash": "0xbdc7d83b8f876938810462fe8d053263a482e44201e3883d4ae204ff4de7eff5", "parentHash": "0x6df968f862b75ade64e8dbdd7b28f035580feef62939fb9cbc7cc24e821246c5",
"receiptsRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2", "receiptsRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2",
"sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"size": "0x26a", "size": "0x26a",
"stateRoot": "0x92c5c55a698963f5b06e3aee415630f5c48b0760e537af94917ce9c4f42a2e22", "stateRoot": "0x1cdafb4045e1cf2b93b5eea1b2425998a9be80c4719265dba102c50bbcb6ece4",
"timestamp": "0xa", "timestamp": "0xa",
"totalDifficulty": "0x1", "totalDifficulty": "0x1",
"transactions": [ "transactions": [

View file

@ -4,7 +4,7 @@
"extraData": "0x", "extraData": "0x",
"gasLimit": "0x47e7c4", "gasLimit": "0x47e7c4",
"gasUsed": "0x0", "gasUsed": "0x0",
"hash": "0xbdc7d83b8f876938810462fe8d053263a482e44201e3883d4ae204ff4de7eff5", "hash": "0x6df968f862b75ade64e8dbdd7b28f035580feef62939fb9cbc7cc24e821246c5",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"miner": "0x0000000000000000000000000000000000000000", "miner": "0x0000000000000000000000000000000000000000",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
@ -14,7 +14,7 @@
"receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"size": "0x200", "size": "0x200",
"stateRoot": "0xfe168c5e9584a85927212e5bea5304bb7d0d8a893453b4b2c52176a72f585ae2", "stateRoot": "0x346d06cdc42cc55d09a235e919de127dde75ba911f8b5d31130935e462e296f0",
"timestamp": "0x0", "timestamp": "0x0",
"totalDifficulty": "0x1", "totalDifficulty": "0x1",
"transactions": [], "transactions": [],

View file

@ -4,22 +4,22 @@
"extraData": "0x", "extraData": "0x",
"gasLimit": "0x47e7c4", "gasLimit": "0x47e7c4",
"gasUsed": "0x5208", "gasUsed": "0x5208",
"hash": "0xda97ed946e0d502fb898b0ac881bd44da3c7fee5eaf184431e1ec3d361dad17e", "hash": "0x8497ace989616d5495ab931f644ea6990dddf7148999bde6bb2ab4b4c7240320",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"miner": "0x0000000000000000000000000000000000000000", "miner": "0x0000000000000000000000000000000000000000",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"nonce": "0x0000000000000000", "nonce": "0x0000000000000000",
"number": "0x9", "number": "0x9",
"parentHash": "0x5abd19c39d9f1c6e52998e135ea14e1fbc5db3fa2a108f4538e238ca5c2e68d7", "parentHash": "0x092f6de1438bfcdd6718afa64cf12a13b658cb8a332b730855e3da2885aee687",
"receiptsRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2", "receiptsRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2",
"sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"size": "0x26a", "size": "0x26a",
"stateRoot": "0xbd4aa2c2873df709151075250a8c01c9a14d2b0e2f715dbdd16e0ef8030c2cf0", "stateRoot": "0x1abc7ad1941fa76fd04eaed1a0658384df02b47feb0561890645296e6579bec8",
"timestamp": "0x5a", "timestamp": "0x5a",
"totalDifficulty": "0x1", "totalDifficulty": "0x1",
"transactions": [ "transactions": [
{ {
"blockHash": "0xda97ed946e0d502fb898b0ac881bd44da3c7fee5eaf184431e1ec3d361dad17e", "blockHash": "0x8497ace989616d5495ab931f644ea6990dddf7148999bde6bb2ab4b4c7240320",
"blockNumber": "0x9", "blockNumber": "0x9",
"from": "0x703c4b2bd70c169f5717101caee543299fc946c7", "from": "0x703c4b2bd70c169f5717101caee543299fc946c7",
"gas": "0x5208", "gas": "0x5208",
@ -33,7 +33,8 @@
"type": "0x0", "type": "0x0",
"v": "0x1b", "v": "0x1b",
"r": "0xc6028b8e983d62fa8542f8a7633fb23cc941be2c897134352d95a7d9b19feafd", "r": "0xc6028b8e983d62fa8542f8a7633fb23cc941be2c897134352d95a7d9b19feafd",
"s": "0xeb6adcaaae3bed489c6cce4435f9db05d23a52820c78bd350e31eec65ed809d" "s": "0xeb6adcaaae3bed489c6cce4435f9db05d23a52820c78bd350e31eec65ed809d",
"sender": "0x0000000000000000000000000000000000000000"
} }
], ],
"transactionsRoot": "0x0767ed8359337dc6a8fdc77fe52db611bed1be87aac73c4556b1bf1dd3d190a5", "transactionsRoot": "0x0767ed8359337dc6a8fdc77fe52db611bed1be87aac73c4556b1bf1dd3d190a5",

View file

@ -4,17 +4,17 @@
"extraData": "0x", "extraData": "0x",
"gasLimit": "0x47e7c4", "gasLimit": "0x47e7c4",
"gasUsed": "0x5208", "gasUsed": "0x5208",
"hash": "0x97f540a3577c0f645c5dada5da86f38350e8f847e71f21124f917835003e2607", "hash": "0x58e8791382f392175cea88e173190ea86e36367acf0f95eb56d2ceb1f650b030",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"miner": "0x0000000000000000000000000000000000000000", "miner": "0x0000000000000000000000000000000000000000",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"nonce": "0x0000000000000000", "nonce": "0x0000000000000000",
"number": "0xa", "number": "0xa",
"parentHash": "0xda97ed946e0d502fb898b0ac881bd44da3c7fee5eaf184431e1ec3d361dad17e", "parentHash": "0x8497ace989616d5495ab931f644ea6990dddf7148999bde6bb2ab4b4c7240320",
"receiptsRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2", "receiptsRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2",
"sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"size": "0x26a", "size": "0x26a",
"stateRoot": "0xbb62872e4023fa8a8b17b9cc37031f4817d9595779748d01cba408b495707a91", "stateRoot": "0xe7adf5abb2eb6302c2af9b8bd1c309b1d28eda30d2b7ba01b151e48b88bd2163",
"timestamp": "0x64", "timestamp": "0x64",
"totalDifficulty": "0x1", "totalDifficulty": "0x1",
"transactions": [ "transactions": [

View file

@ -4,7 +4,7 @@
"extraData": "0x", "extraData": "0x",
"gasLimit": "0x47e7c4", "gasLimit": "0x47e7c4",
"gasUsed": "0x0", "gasUsed": "0x0",
"hash": "0xbdc7d83b8f876938810462fe8d053263a482e44201e3883d4ae204ff4de7eff5", "hash": "0x6df968f862b75ade64e8dbdd7b28f035580feef62939fb9cbc7cc24e821246c5",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"miner": "0x0000000000000000000000000000000000000000", "miner": "0x0000000000000000000000000000000000000000",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
@ -14,7 +14,7 @@
"receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"size": "0x200", "size": "0x200",
"stateRoot": "0xfe168c5e9584a85927212e5bea5304bb7d0d8a893453b4b2c52176a72f585ae2", "stateRoot": "0x346d06cdc42cc55d09a235e919de127dde75ba911f8b5d31130935e462e296f0",
"timestamp": "0x0", "timestamp": "0x0",
"totalDifficulty": "0x1", "totalDifficulty": "0x1",
"transactions": [], "transactions": [],

View file

@ -4,17 +4,17 @@
"extraData": "0x", "extraData": "0x",
"gasLimit": "0x47e7c4", "gasLimit": "0x47e7c4",
"gasUsed": "0x5208", "gasUsed": "0x5208",
"hash": "0x0da274b315de8e4d5bf8717218ec43540464ef36378cb896469bb731e1d3f3cb", "hash": "0xcc3b85e906fca96a8337bd17a80a0ae26519c77b2a1e47c59911aebc02a801db",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"miner": "0x0000000000000000000000000000000000000000", "miner": "0x0000000000000000000000000000000000000000",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"nonce": "0x0000000000000000", "nonce": "0x0000000000000000",
"number": "0x1", "number": "0x1",
"parentHash": "0xbdc7d83b8f876938810462fe8d053263a482e44201e3883d4ae204ff4de7eff5", "parentHash": "0x6df968f862b75ade64e8dbdd7b28f035580feef62939fb9cbc7cc24e821246c5",
"receiptsRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2", "receiptsRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2",
"sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"size": "0x26a", "size": "0x26a",
"stateRoot": "0x92c5c55a698963f5b06e3aee415630f5c48b0760e537af94917ce9c4f42a2e22", "stateRoot": "0x1cdafb4045e1cf2b93b5eea1b2425998a9be80c4719265dba102c50bbcb6ece4",
"timestamp": "0xa", "timestamp": "0xa",
"totalDifficulty": "0x1", "totalDifficulty": "0x1",
"transactions": [ "transactions": [

View file

@ -4,22 +4,22 @@
"extraData": "0x", "extraData": "0x",
"gasLimit": "0x47e7c4", "gasLimit": "0x47e7c4",
"gasUsed": "0x5208", "gasUsed": "0x5208",
"hash": "0xda97ed946e0d502fb898b0ac881bd44da3c7fee5eaf184431e1ec3d361dad17e", "hash": "0x8497ace989616d5495ab931f644ea6990dddf7148999bde6bb2ab4b4c7240320",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"miner": "0x0000000000000000000000000000000000000000", "miner": "0x0000000000000000000000000000000000000000",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"nonce": "0x0000000000000000", "nonce": "0x0000000000000000",
"number": "0x9", "number": "0x9",
"parentHash": "0x5abd19c39d9f1c6e52998e135ea14e1fbc5db3fa2a108f4538e238ca5c2e68d7", "parentHash": "0x092f6de1438bfcdd6718afa64cf12a13b658cb8a332b730855e3da2885aee687",
"receiptsRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2", "receiptsRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2",
"sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"size": "0x26a", "size": "0x26a",
"stateRoot": "0xbd4aa2c2873df709151075250a8c01c9a14d2b0e2f715dbdd16e0ef8030c2cf0", "stateRoot": "0x1abc7ad1941fa76fd04eaed1a0658384df02b47feb0561890645296e6579bec8",
"timestamp": "0x5a", "timestamp": "0x5a",
"totalDifficulty": "0x1", "totalDifficulty": "0x1",
"transactions": [ "transactions": [
{ {
"blockHash": "0xda97ed946e0d502fb898b0ac881bd44da3c7fee5eaf184431e1ec3d361dad17e", "blockHash": "0x8497ace989616d5495ab931f644ea6990dddf7148999bde6bb2ab4b4c7240320",
"blockNumber": "0x9", "blockNumber": "0x9",
"from": "0x703c4b2bd70c169f5717101caee543299fc946c7", "from": "0x703c4b2bd70c169f5717101caee543299fc946c7",
"gas": "0x5208", "gas": "0x5208",
@ -33,7 +33,8 @@
"type": "0x0", "type": "0x0",
"v": "0x1b", "v": "0x1b",
"r": "0xc6028b8e983d62fa8542f8a7633fb23cc941be2c897134352d95a7d9b19feafd", "r": "0xc6028b8e983d62fa8542f8a7633fb23cc941be2c897134352d95a7d9b19feafd",
"s": "0xeb6adcaaae3bed489c6cce4435f9db05d23a52820c78bd350e31eec65ed809d" "s": "0xeb6adcaaae3bed489c6cce4435f9db05d23a52820c78bd350e31eec65ed809d",
"sender": "0x0000000000000000000000000000000000000000"
} }
], ],
"transactionsRoot": "0x0767ed8359337dc6a8fdc77fe52db611bed1be87aac73c4556b1bf1dd3d190a5", "transactionsRoot": "0x0767ed8359337dc6a8fdc77fe52db611bed1be87aac73c4556b1bf1dd3d190a5",

View file

@ -4,17 +4,17 @@
"extraData": "0x", "extraData": "0x",
"gasLimit": "0x47e7c4", "gasLimit": "0x47e7c4",
"gasUsed": "0x5208", "gasUsed": "0x5208",
"hash": "0x97f540a3577c0f645c5dada5da86f38350e8f847e71f21124f917835003e2607", "hash": "0x58e8791382f392175cea88e173190ea86e36367acf0f95eb56d2ceb1f650b030",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"miner": "0x0000000000000000000000000000000000000000", "miner": "0x0000000000000000000000000000000000000000",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"nonce": "0x0000000000000000", "nonce": "0x0000000000000000",
"number": "0xa", "number": "0xa",
"parentHash": "0xda97ed946e0d502fb898b0ac881bd44da3c7fee5eaf184431e1ec3d361dad17e", "parentHash": "0x8497ace989616d5495ab931f644ea6990dddf7148999bde6bb2ab4b4c7240320",
"receiptsRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2", "receiptsRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2",
"sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"size": "0x26a", "size": "0x26a",
"stateRoot": "0xbb62872e4023fa8a8b17b9cc37031f4817d9595779748d01cba408b495707a91", "stateRoot": "0xe7adf5abb2eb6302c2af9b8bd1c309b1d28eda30d2b7ba01b151e48b88bd2163",
"timestamp": "0x64", "timestamp": "0x64",
"totalDifficulty": "0x1", "totalDifficulty": "0x1",
"transactions": [ "transactions": [

View file

@ -33,7 +33,8 @@
"chainId": "0x7fffffffffffffee", "chainId": "0x7fffffffffffffee",
"v": "0x0", "v": "0x0",
"r": "0x0", "r": "0x0",
"s": "0x0" "s": "0x0",
"sender": "0x0000000000000000000000000000000000000000"
} }
], ],
"transactionsRoot": "0x98d9f6dd0aa479c0fb448f2627e9f1964aca699fccab8f6e95861547a4699e37", "transactionsRoot": "0x98d9f6dd0aa479c0fb448f2627e9f1964aca699fccab8f6e95861547a4699e37",

View file

@ -2,13 +2,14 @@
{ {
"blobGasPrice": "0x1", "blobGasPrice": "0x1",
"blobGasUsed": "0x20000", "blobGasUsed": "0x20000",
"blockHash": "0xe724dfd4349861f4dceef2bc4df086d0a3d88858214f6bee9fcf1bebd1edc2a6", "blockHash": "0xb39a867bef2962b3e7af21d9a8a8c018c1de5c27be56341261857e24b96b263e",
"blockNumber": "0x6", "blockNumber": "0x6",
"contractAddress": null, "contractAddress": null,
"cumulativeGasUsed": "0x5208", "cumulativeGasUsed": "0x5208",
"effectiveGasPrice": "0x1b09d63b", "effectiveGasPrice": "0x1b09d63b",
"from": "0x703c4b2bd70c169f5717101caee543299fc946c7", "from": "0x703c4b2bd70c169f5717101caee543299fc946c7",
"gasUsed": "0x5208", "gasUsed": "0x5208",
"l1Fee": "0x0",
"logs": [], "logs": [],
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"status": "0x1", "status": "0x1",

View file

@ -1,12 +1,13 @@
[ [
{ {
"blockHash": "0x1e7dcf3abe8bf05d32367a5dc387caa32578b15871bf8b3cbeedf2d8d530f844", "blockHash": "0x7afe7ea18e15ea1bf0b10ae924e42a8e01023c4b1f3c8058c45723a1e56b8868",
"blockNumber": "0x2", "blockNumber": "0x2",
"contractAddress": "0xae9bea628c4ce503dcfd7e305cab4e29e7476592", "contractAddress": "0xae9bea628c4ce503dcfd7e305cab4e29e7476592",
"cumulativeGasUsed": "0xcf50", "cumulativeGasUsed": "0xcf50",
"effectiveGasPrice": "0x2db16291", "effectiveGasPrice": "0x2db16291",
"from": "0x703c4b2bd70c169f5717101caee543299fc946c7", "from": "0x703c4b2bd70c169f5717101caee543299fc946c7",
"gasUsed": "0xcf50", "gasUsed": "0xcf50",
"l1Fee": "0x0",
"logs": [], "logs": [],
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"status": "0x1", "status": "0x1",

View file

@ -1,12 +1,13 @@
[ [
{ {
"blockHash": "0xffa737e6ce9a9162ffd411dd06169114b3ed5ee9fc1474a2625c92548e4455e0", "blockHash": "0xb2d0c9e52757eee01da7c6a6da6de23a4548c036c97f4f113c5e05d9daf17e1a",
"blockNumber": "0x4", "blockNumber": "0x4",
"contractAddress": null, "contractAddress": null,
"cumulativeGasUsed": "0x538d", "cumulativeGasUsed": "0x538d",
"effectiveGasPrice": "0x2325c42f", "effectiveGasPrice": "0x2325c42f",
"from": "0x703c4b2bd70c169f5717101caee543299fc946c7", "from": "0x703c4b2bd70c169f5717101caee543299fc946c7",
"gasUsed": "0x538d", "gasUsed": "0x538d",
"l1Fee": "0x0",
"logs": [], "logs": [],
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"status": "0x0", "status": "0x0",

View file

@ -1,12 +1,13 @@
[ [
{ {
"blockHash": "0x173dcd9d22ce71929cd17e84ea88702a0f84d6244c6898d2a4f48722e494fe9c", "blockHash": "0xd62e01634cdf11c2b2a854453deccbc7b5b4f6df1c717b932ade30f47db68512",
"blockNumber": "0x3", "blockNumber": "0x3",
"contractAddress": null, "contractAddress": null,
"cumulativeGasUsed": "0x5e28", "cumulativeGasUsed": "0x5e28",
"effectiveGasPrice": "0x281c2585", "effectiveGasPrice": "0x281c2585",
"from": "0x703c4b2bd70c169f5717101caee543299fc946c7", "from": "0x703c4b2bd70c169f5717101caee543299fc946c7",
"gasUsed": "0x5e28", "gasUsed": "0x5e28",
"l1Fee": "0x0",
"logs": [ "logs": [
{ {
"address": "0x0000000000000000000000000000000000031ec7", "address": "0x0000000000000000000000000000000000031ec7",
@ -19,7 +20,7 @@
"blockNumber": "0x3", "blockNumber": "0x3",
"transactionHash": "0xeaf3921cbf03ba45bad4e6ab807b196ce3b2a0b5bacc355b6272fa96b11b4287", "transactionHash": "0xeaf3921cbf03ba45bad4e6ab807b196ce3b2a0b5bacc355b6272fa96b11b4287",
"transactionIndex": "0x0", "transactionIndex": "0x0",
"blockHash": "0x173dcd9d22ce71929cd17e84ea88702a0f84d6244c6898d2a4f48722e494fe9c", "blockHash": "0xd62e01634cdf11c2b2a854453deccbc7b5b4f6df1c717b932ade30f47db68512",
"logIndex": "0x0", "logIndex": "0x0",
"removed": false "removed": false
} }

View file

@ -1,12 +1,13 @@
[ [
{ {
"blockHash": "0xa8a067b3cb3b9ddc6cfb8317bfd08b266fcf9994fc870c1f7ed394acecfadf39", "blockHash": "0x34044cfcfe129574966dc82cee6ec504c869d50ec2bd4a16eb330b04a277bcab",
"blockNumber": "0x1", "blockNumber": "0x1",
"contractAddress": null, "contractAddress": null,
"cumulativeGasUsed": "0x5208", "cumulativeGasUsed": "0x5208",
"effectiveGasPrice": "0x342770c0", "effectiveGasPrice": "0x342770c0",
"from": "0x703c4b2bd70c169f5717101caee543299fc946c7", "from": "0x703c4b2bd70c169f5717101caee543299fc946c7",
"gasUsed": "0x5208", "gasUsed": "0x5208",
"l1Fee": "0x0",
"logs": [], "logs": [],
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"status": "0x1", "status": "0x1",

View file

@ -2,13 +2,14 @@
{ {
"blobGasPrice": "0x1", "blobGasPrice": "0x1",
"blobGasUsed": "0x20000", "blobGasUsed": "0x20000",
"blockHash": "0xe724dfd4349861f4dceef2bc4df086d0a3d88858214f6bee9fcf1bebd1edc2a6", "blockHash": "0xb39a867bef2962b3e7af21d9a8a8c018c1de5c27be56341261857e24b96b263e",
"blockNumber": "0x6", "blockNumber": "0x6",
"contractAddress": null, "contractAddress": null,
"cumulativeGasUsed": "0x5208", "cumulativeGasUsed": "0x5208",
"effectiveGasPrice": "0x1b09d63b", "effectiveGasPrice": "0x1b09d63b",
"from": "0x703c4b2bd70c169f5717101caee543299fc946c7", "from": "0x703c4b2bd70c169f5717101caee543299fc946c7",
"gasUsed": "0x5208", "gasUsed": "0x5208",
"l1Fee": "0x0",
"logs": [], "logs": [],
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"status": "0x1", "status": "0x1",

View file

@ -4,7 +4,7 @@
"extraData": "0x", "extraData": "0x",
"gasLimit": "0x47e7c4", "gasLimit": "0x47e7c4",
"gasUsed": "0x0", "gasUsed": "0x0",
"hash": "0xbdc7d83b8f876938810462fe8d053263a482e44201e3883d4ae204ff4de7eff5", "hash": "0x6df968f862b75ade64e8dbdd7b28f035580feef62939fb9cbc7cc24e821246c5",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"miner": "0x0000000000000000000000000000000000000000", "miner": "0x0000000000000000000000000000000000000000",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
@ -13,7 +13,7 @@
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"stateRoot": "0xfe168c5e9584a85927212e5bea5304bb7d0d8a893453b4b2c52176a72f585ae2", "stateRoot": "0x346d06cdc42cc55d09a235e919de127dde75ba911f8b5d31130935e462e296f0",
"timestamp": "0x0", "timestamp": "0x0",
"totalDifficulty": "0x1", "totalDifficulty": "0x1",
"transactionsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421" "transactionsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"

View file

@ -4,16 +4,16 @@
"extraData": "0x", "extraData": "0x",
"gasLimit": "0x47e7c4", "gasLimit": "0x47e7c4",
"gasUsed": "0x5208", "gasUsed": "0x5208",
"hash": "0x0da274b315de8e4d5bf8717218ec43540464ef36378cb896469bb731e1d3f3cb", "hash": "0xcc3b85e906fca96a8337bd17a80a0ae26519c77b2a1e47c59911aebc02a801db",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"miner": "0x0000000000000000000000000000000000000000", "miner": "0x0000000000000000000000000000000000000000",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"nonce": "0x0000000000000000", "nonce": "0x0000000000000000",
"number": "0x1", "number": "0x1",
"parentHash": "0xbdc7d83b8f876938810462fe8d053263a482e44201e3883d4ae204ff4de7eff5", "parentHash": "0x6df968f862b75ade64e8dbdd7b28f035580feef62939fb9cbc7cc24e821246c5",
"receiptsRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2", "receiptsRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2",
"sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"stateRoot": "0x92c5c55a698963f5b06e3aee415630f5c48b0760e537af94917ce9c4f42a2e22", "stateRoot": "0x1cdafb4045e1cf2b93b5eea1b2425998a9be80c4719265dba102c50bbcb6ece4",
"timestamp": "0xa", "timestamp": "0xa",
"totalDifficulty": "0x1", "totalDifficulty": "0x1",
"transactionsRoot": "0xca0ebcce920d2cdfbf9e1dbe90ed3441a1a576f344bd80e60508da814916f4e7" "transactionsRoot": "0xca0ebcce920d2cdfbf9e1dbe90ed3441a1a576f344bd80e60508da814916f4e7"

View file

@ -4,16 +4,16 @@
"extraData": "0x", "extraData": "0x",
"gasLimit": "0x47e7c4", "gasLimit": "0x47e7c4",
"gasUsed": "0x5208", "gasUsed": "0x5208",
"hash": "0xda97ed946e0d502fb898b0ac881bd44da3c7fee5eaf184431e1ec3d361dad17e", "hash": "0x8497ace989616d5495ab931f644ea6990dddf7148999bde6bb2ab4b4c7240320",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"miner": "0x0000000000000000000000000000000000000000", "miner": "0x0000000000000000000000000000000000000000",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"nonce": "0x0000000000000000", "nonce": "0x0000000000000000",
"number": "0x9", "number": "0x9",
"parentHash": "0x5abd19c39d9f1c6e52998e135ea14e1fbc5db3fa2a108f4538e238ca5c2e68d7", "parentHash": "0x092f6de1438bfcdd6718afa64cf12a13b658cb8a332b730855e3da2885aee687",
"receiptsRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2", "receiptsRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2",
"sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"stateRoot": "0xbd4aa2c2873df709151075250a8c01c9a14d2b0e2f715dbdd16e0ef8030c2cf0", "stateRoot": "0x1abc7ad1941fa76fd04eaed1a0658384df02b47feb0561890645296e6579bec8",
"timestamp": "0x5a", "timestamp": "0x5a",
"totalDifficulty": "0x1", "totalDifficulty": "0x1",
"transactionsRoot": "0x0767ed8359337dc6a8fdc77fe52db611bed1be87aac73c4556b1bf1dd3d190a5" "transactionsRoot": "0x0767ed8359337dc6a8fdc77fe52db611bed1be87aac73c4556b1bf1dd3d190a5"

View file

@ -4,16 +4,16 @@
"extraData": "0x", "extraData": "0x",
"gasLimit": "0x47e7c4", "gasLimit": "0x47e7c4",
"gasUsed": "0x5208", "gasUsed": "0x5208",
"hash": "0x97f540a3577c0f645c5dada5da86f38350e8f847e71f21124f917835003e2607", "hash": "0x58e8791382f392175cea88e173190ea86e36367acf0f95eb56d2ceb1f650b030",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"miner": "0x0000000000000000000000000000000000000000", "miner": "0x0000000000000000000000000000000000000000",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"nonce": "0x0000000000000000", "nonce": "0x0000000000000000",
"number": "0xa", "number": "0xa",
"parentHash": "0xda97ed946e0d502fb898b0ac881bd44da3c7fee5eaf184431e1ec3d361dad17e", "parentHash": "0x8497ace989616d5495ab931f644ea6990dddf7148999bde6bb2ab4b4c7240320",
"receiptsRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2", "receiptsRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2",
"sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"stateRoot": "0xbb62872e4023fa8a8b17b9cc37031f4817d9595779748d01cba408b495707a91", "stateRoot": "0xe7adf5abb2eb6302c2af9b8bd1c309b1d28eda30d2b7ba01b151e48b88bd2163",
"timestamp": "0x64", "timestamp": "0x64",
"totalDifficulty": "0x1", "totalDifficulty": "0x1",
"transactionsRoot": "0xb0893d21a4a44dc26a962a6e91abae66df87fb61ac9c60e936aee89c76331445" "transactionsRoot": "0xb0893d21a4a44dc26a962a6e91abae66df87fb61ac9c60e936aee89c76331445"

View file

@ -4,7 +4,7 @@
"extraData": "0x", "extraData": "0x",
"gasLimit": "0x47e7c4", "gasLimit": "0x47e7c4",
"gasUsed": "0x0", "gasUsed": "0x0",
"hash": "0xbdc7d83b8f876938810462fe8d053263a482e44201e3883d4ae204ff4de7eff5", "hash": "0x6df968f862b75ade64e8dbdd7b28f035580feef62939fb9cbc7cc24e821246c5",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"miner": "0x0000000000000000000000000000000000000000", "miner": "0x0000000000000000000000000000000000000000",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
@ -13,7 +13,7 @@
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"stateRoot": "0xfe168c5e9584a85927212e5bea5304bb7d0d8a893453b4b2c52176a72f585ae2", "stateRoot": "0x346d06cdc42cc55d09a235e919de127dde75ba911f8b5d31130935e462e296f0",
"timestamp": "0x0", "timestamp": "0x0",
"totalDifficulty": "0x1", "totalDifficulty": "0x1",
"transactionsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421" "transactionsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"

View file

@ -4,16 +4,16 @@
"extraData": "0x", "extraData": "0x",
"gasLimit": "0x47e7c4", "gasLimit": "0x47e7c4",
"gasUsed": "0x5208", "gasUsed": "0x5208",
"hash": "0x0da274b315de8e4d5bf8717218ec43540464ef36378cb896469bb731e1d3f3cb", "hash": "0xcc3b85e906fca96a8337bd17a80a0ae26519c77b2a1e47c59911aebc02a801db",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"miner": "0x0000000000000000000000000000000000000000", "miner": "0x0000000000000000000000000000000000000000",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"nonce": "0x0000000000000000", "nonce": "0x0000000000000000",
"number": "0x1", "number": "0x1",
"parentHash": "0xbdc7d83b8f876938810462fe8d053263a482e44201e3883d4ae204ff4de7eff5", "parentHash": "0x6df968f862b75ade64e8dbdd7b28f035580feef62939fb9cbc7cc24e821246c5",
"receiptsRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2", "receiptsRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2",
"sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"stateRoot": "0x92c5c55a698963f5b06e3aee415630f5c48b0760e537af94917ce9c4f42a2e22", "stateRoot": "0x1cdafb4045e1cf2b93b5eea1b2425998a9be80c4719265dba102c50bbcb6ece4",
"timestamp": "0xa", "timestamp": "0xa",
"totalDifficulty": "0x1", "totalDifficulty": "0x1",
"transactionsRoot": "0xca0ebcce920d2cdfbf9e1dbe90ed3441a1a576f344bd80e60508da814916f4e7" "transactionsRoot": "0xca0ebcce920d2cdfbf9e1dbe90ed3441a1a576f344bd80e60508da814916f4e7"

View file

@ -4,16 +4,16 @@
"extraData": "0x", "extraData": "0x",
"gasLimit": "0x47e7c4", "gasLimit": "0x47e7c4",
"gasUsed": "0x5208", "gasUsed": "0x5208",
"hash": "0xda97ed946e0d502fb898b0ac881bd44da3c7fee5eaf184431e1ec3d361dad17e", "hash": "0x8497ace989616d5495ab931f644ea6990dddf7148999bde6bb2ab4b4c7240320",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"miner": "0x0000000000000000000000000000000000000000", "miner": "0x0000000000000000000000000000000000000000",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"nonce": "0x0000000000000000", "nonce": "0x0000000000000000",
"number": "0x9", "number": "0x9",
"parentHash": "0x5abd19c39d9f1c6e52998e135ea14e1fbc5db3fa2a108f4538e238ca5c2e68d7", "parentHash": "0x092f6de1438bfcdd6718afa64cf12a13b658cb8a332b730855e3da2885aee687",
"receiptsRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2", "receiptsRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2",
"sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"stateRoot": "0xbd4aa2c2873df709151075250a8c01c9a14d2b0e2f715dbdd16e0ef8030c2cf0", "stateRoot": "0x1abc7ad1941fa76fd04eaed1a0658384df02b47feb0561890645296e6579bec8",
"timestamp": "0x5a", "timestamp": "0x5a",
"totalDifficulty": "0x1", "totalDifficulty": "0x1",
"transactionsRoot": "0x0767ed8359337dc6a8fdc77fe52db611bed1be87aac73c4556b1bf1dd3d190a5" "transactionsRoot": "0x0767ed8359337dc6a8fdc77fe52db611bed1be87aac73c4556b1bf1dd3d190a5"

View file

@ -4,16 +4,16 @@
"extraData": "0x", "extraData": "0x",
"gasLimit": "0x47e7c4", "gasLimit": "0x47e7c4",
"gasUsed": "0x5208", "gasUsed": "0x5208",
"hash": "0x97f540a3577c0f645c5dada5da86f38350e8f847e71f21124f917835003e2607", "hash": "0x58e8791382f392175cea88e173190ea86e36367acf0f95eb56d2ceb1f650b030",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"miner": "0x0000000000000000000000000000000000000000", "miner": "0x0000000000000000000000000000000000000000",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"nonce": "0x0000000000000000", "nonce": "0x0000000000000000",
"number": "0xa", "number": "0xa",
"parentHash": "0xda97ed946e0d502fb898b0ac881bd44da3c7fee5eaf184431e1ec3d361dad17e", "parentHash": "0x8497ace989616d5495ab931f644ea6990dddf7148999bde6bb2ab4b4c7240320",
"receiptsRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2", "receiptsRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2",
"sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"stateRoot": "0xbb62872e4023fa8a8b17b9cc37031f4817d9595779748d01cba408b495707a91", "stateRoot": "0xe7adf5abb2eb6302c2af9b8bd1c309b1d28eda30d2b7ba01b151e48b88bd2163",
"timestamp": "0x64", "timestamp": "0x64",
"totalDifficulty": "0x1", "totalDifficulty": "0x1",
"transactionsRoot": "0xb0893d21a4a44dc26a962a6e91abae66df87fb61ac9c60e936aee89c76331445" "transactionsRoot": "0xb0893d21a4a44dc26a962a6e91abae66df87fb61ac9c60e936aee89c76331445"

View file

@ -1,13 +1,14 @@
{ {
"blobGasPrice": "0x1", "blobGasPrice": "0x1",
"blobGasUsed": "0x20000", "blobGasUsed": "0x20000",
"blockHash": "0xe724dfd4349861f4dceef2bc4df086d0a3d88858214f6bee9fcf1bebd1edc2a6", "blockHash": "0xb39a867bef2962b3e7af21d9a8a8c018c1de5c27be56341261857e24b96b263e",
"blockNumber": "0x6", "blockNumber": "0x6",
"contractAddress": null, "contractAddress": null,
"cumulativeGasUsed": "0x5208", "cumulativeGasUsed": "0x5208",
"effectiveGasPrice": "0x1b09d63b", "effectiveGasPrice": "0x1b09d63b",
"from": "0x703c4b2bd70c169f5717101caee543299fc946c7", "from": "0x703c4b2bd70c169f5717101caee543299fc946c7",
"gasUsed": "0x5208", "gasUsed": "0x5208",
"l1Fee": "0x0",
"logs": [], "logs": [],
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"status": "0x1", "status": "0x1",

View file

@ -1,11 +1,12 @@
{ {
"blockHash": "0x1e7dcf3abe8bf05d32367a5dc387caa32578b15871bf8b3cbeedf2d8d530f844", "blockHash": "0x7afe7ea18e15ea1bf0b10ae924e42a8e01023c4b1f3c8058c45723a1e56b8868",
"blockNumber": "0x2", "blockNumber": "0x2",
"contractAddress": "0xae9bea628c4ce503dcfd7e305cab4e29e7476592", "contractAddress": "0xae9bea628c4ce503dcfd7e305cab4e29e7476592",
"cumulativeGasUsed": "0xcf50", "cumulativeGasUsed": "0xcf50",
"effectiveGasPrice": "0x2db16291", "effectiveGasPrice": "0x2db16291",
"from": "0x703c4b2bd70c169f5717101caee543299fc946c7", "from": "0x703c4b2bd70c169f5717101caee543299fc946c7",
"gasUsed": "0xcf50", "gasUsed": "0xcf50",
"l1Fee": "0x0",
"logs": [], "logs": [],
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"status": "0x1", "status": "0x1",

View file

@ -1,11 +1,12 @@
{ {
"blockHash": "0x3fadc5bc916018a326732be829a2565b3acb960a8406f0f151a5e1fa971ea7dd", "blockHash": "0xe1081b33b1e59d80de12700f8c123589b06d5629762a27d31919315e25265c9c",
"blockNumber": "0x5", "blockNumber": "0x5",
"contractAddress": "0xfdaa97661a584d977b4d3abb5370766ff5b86a18", "contractAddress": "0xfdaa97661a584d977b4d3abb5370766ff5b86a18",
"cumulativeGasUsed": "0xe01c", "cumulativeGasUsed": "0xe01c",
"effectiveGasPrice": "0x1ecb3fb4", "effectiveGasPrice": "0x1ecb3fb4",
"from": "0x703c4b2bd70c169f5717101caee543299fc946c7", "from": "0x703c4b2bd70c169f5717101caee543299fc946c7",
"gasUsed": "0xe01c", "gasUsed": "0xe01c",
"l1Fee": "0x0",
"logs": [], "logs": [],
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"status": "0x1", "status": "0x1",

View file

@ -1,11 +1,12 @@
{ {
"blockHash": "0xffa737e6ce9a9162ffd411dd06169114b3ed5ee9fc1474a2625c92548e4455e0", "blockHash": "0xb2d0c9e52757eee01da7c6a6da6de23a4548c036c97f4f113c5e05d9daf17e1a",
"blockNumber": "0x4", "blockNumber": "0x4",
"contractAddress": null, "contractAddress": null,
"cumulativeGasUsed": "0x538d", "cumulativeGasUsed": "0x538d",
"effectiveGasPrice": "0x2325c42f", "effectiveGasPrice": "0x2325c42f",
"from": "0x703c4b2bd70c169f5717101caee543299fc946c7", "from": "0x703c4b2bd70c169f5717101caee543299fc946c7",
"gasUsed": "0x538d", "gasUsed": "0x538d",
"l1Fee": "0x0",
"logs": [], "logs": [],
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"status": "0x0", "status": "0x0",

View file

@ -1,11 +1,12 @@
{ {
"blockHash": "0xa8a067b3cb3b9ddc6cfb8317bfd08b266fcf9994fc870c1f7ed394acecfadf39", "blockHash": "0x34044cfcfe129574966dc82cee6ec504c869d50ec2bd4a16eb330b04a277bcab",
"blockNumber": "0x1", "blockNumber": "0x1",
"contractAddress": null, "contractAddress": null,
"cumulativeGasUsed": "0x5208", "cumulativeGasUsed": "0x5208",
"effectiveGasPrice": "0x342770c0", "effectiveGasPrice": "0x342770c0",
"from": "0x703c4b2bd70c169f5717101caee543299fc946c7", "from": "0x703c4b2bd70c169f5717101caee543299fc946c7",
"gasUsed": "0x5208", "gasUsed": "0x5208",
"l1Fee": "0x0",
"logs": [], "logs": [],
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"status": "0x1", "status": "0x1",

View file

@ -1,11 +1,12 @@
{ {
"blockHash": "0x173dcd9d22ce71929cd17e84ea88702a0f84d6244c6898d2a4f48722e494fe9c", "blockHash": "0xd62e01634cdf11c2b2a854453deccbc7b5b4f6df1c717b932ade30f47db68512",
"blockNumber": "0x3", "blockNumber": "0x3",
"contractAddress": null, "contractAddress": null,
"cumulativeGasUsed": "0x5e28", "cumulativeGasUsed": "0x5e28",
"effectiveGasPrice": "0x281c2585", "effectiveGasPrice": "0x281c2585",
"from": "0x703c4b2bd70c169f5717101caee543299fc946c7", "from": "0x703c4b2bd70c169f5717101caee543299fc946c7",
"gasUsed": "0x5e28", "gasUsed": "0x5e28",
"l1Fee": "0x0",
"logs": [ "logs": [
{ {
"address": "0x0000000000000000000000000000000000031ec7", "address": "0x0000000000000000000000000000000000031ec7",
@ -18,7 +19,7 @@
"blockNumber": "0x3", "blockNumber": "0x3",
"transactionHash": "0xeaf3921cbf03ba45bad4e6ab807b196ce3b2a0b5bacc355b6272fa96b11b4287", "transactionHash": "0xeaf3921cbf03ba45bad4e6ab807b196ce3b2a0b5bacc355b6272fa96b11b4287",
"transactionIndex": "0x0", "transactionIndex": "0x0",
"blockHash": "0x173dcd9d22ce71929cd17e84ea88702a0f84d6244c6898d2a4f48722e494fe9c", "blockHash": "0xd62e01634cdf11c2b2a854453deccbc7b5b4f6df1c717b932ade30f47db68512",
"logIndex": "0x0", "logIndex": "0x0",
"removed": false "removed": false
} }

View file

@ -18,6 +18,7 @@ package les
import ( import (
"crypto/ecdsa" "crypto/ecdsa"
"errors"
"time" "time"
"github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/common/mclock"
@ -82,6 +83,11 @@ func NewLesServer(node *node.Node, e ethBackend, config *ethconfig.Config) (*Les
if err != nil { if err != nil {
return nil, err return nil, err
} }
// Currently disable for zktrie
if e.BlockChain().Config().Scroll.ZktrieEnabled() {
return nil, errors.New("light server not work with zktrie storage")
}
// Calculate the number of threads used to service the light client // Calculate the number of threads used to service the light client
// requests based on the user-specified value. // requests based on the user-specified value.
threads := config.LightServ * 4 / 100 threads := config.LightServ * 4 / 100

View file

@ -339,6 +339,9 @@ type ChainConfig struct {
} }
type ScrollConfig struct { type ScrollConfig struct {
// Use zktrie [optional]
UseZktrie bool `json:"useZktrie,omitempty"`
// Maximum number of transactions per block [optional] // Maximum number of transactions per block [optional]
MaxTxPerBlock *int `json:"maxTxPerBlock,omitempty"` MaxTxPerBlock *int `json:"maxTxPerBlock,omitempty"`
@ -373,6 +376,10 @@ func (s ScrollConfig) FeeVaultEnabled() bool {
return s.FeeVaultAddress != nil return s.FeeVaultAddress != nil
} }
func (s ScrollConfig) ZktrieEnabled() bool {
return s.UseZktrie
}
func (s ScrollConfig) ShouldIncludeL1Messages() bool { func (s ScrollConfig) ShouldIncludeL1Messages() bool {
return s.L1Config != nil && s.L1Config.NumL1MessagesPerBlock > 0 return s.L1Config != nil && s.L1Config.NumL1MessagesPerBlock > 0
} }

View file

@ -18,6 +18,7 @@ package trie
import ( import (
"errors" "errors"
"sync"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
@ -33,6 +34,9 @@ type Config struct {
Preimages bool // Flag whether the preimage of node key is recorded Preimages bool // Flag whether the preimage of node key is recorded
HashDB *hashdb.Config // Configs for hash-based scheme HashDB *hashdb.Config // Configs for hash-based scheme
PathDB *pathdb.Config // Configs for experimental path-based scheme PathDB *pathdb.Config // Configs for experimental path-based scheme
// zktrie related stuff
IsUsingZktrie bool
} }
// HashDefaults represents a config for using hash-based scheme with // HashDefaults represents a config for using hash-based scheme with
@ -42,6 +46,19 @@ var HashDefaults = &Config{
HashDB: hashdb.Defaults, HashDB: hashdb.Defaults,
} }
// HashDefaultsWithZktrie represents a config based on HashDefaults but with zktrie enabled.
var HashDefaultsWithZktrie = &Config{
Preimages: false,
HashDB: hashdb.Defaults,
IsUsingZktrie: true,
}
// HashDefaultsWithPreimages represents a config based on HashDefaults but with Preimages enabled.
var HashDefaultsWithPreimages = &Config{
Preimages: true,
HashDB: hashdb.Defaults,
}
// backend defines the methods needed to access/update trie nodes in different // backend defines the methods needed to access/update trie nodes in different
// state scheme. // state scheme.
type backend interface { type backend interface {
@ -73,6 +90,9 @@ type backend interface {
// Close closes the trie database backend and releases all held resources. // Close closes the trie database backend and releases all held resources.
Close() error Close() error
// database supplementary methods, to get the underlying fields
GetLock() *sync.RWMutex
} }
// Database is the wrapper of the underlying backend which is shared by different // Database is the wrapper of the underlying backend which is shared by different
@ -83,6 +103,10 @@ type Database struct {
diskdb ethdb.Database // Persistent database to store the snapshot diskdb ethdb.Database // Persistent database to store the snapshot
preimages *preimageStore // The store for caching preimages preimages *preimageStore // The store for caching preimages
backend backend // The backend for managing trie nodes backend backend // The backend for managing trie nodes
// zktrie related stuff
// TODO: It's a quick&dirty implementation. FIXME later.
rawDirties KvMap
} }
// NewDatabase initializes the trie database with default settings, note // NewDatabase initializes the trie database with default settings, note
@ -100,6 +124,8 @@ func NewDatabase(diskdb ethdb.Database, config *Config) *Database {
config: config, config: config,
diskdb: diskdb, diskdb: diskdb,
preimages: preimages, preimages: preimages,
// scroll-related
rawDirties: make(KvMap),
} }
if config.HashDB != nil && config.PathDB != nil { if config.HashDB != nil && config.PathDB != nil {
log.Crit("Both 'hash' and 'path' mode are configured") log.Crit("Both 'hash' and 'path' mode are configured")
@ -112,6 +138,19 @@ func NewDatabase(diskdb ethdb.Database, config *Config) *Database {
return db return db
} }
func (db *Database) IsUsingZktrie() bool {
// compatible logic for light mode
if db == nil || db.config == nil {
return false
}
return db.config.IsUsingZktrie
}
func (db *Database) SetIsUsingZktrie(isUsingZktrie bool) {
// config must not be nil
db.config.IsUsingZktrie = isUsingZktrie
}
// Reader returns a reader for accessing all trie nodes with provided state root. // Reader returns a reader for accessing all trie nodes with provided state root.
// An error will be returned if the requested state is not available. // An error will be returned if the requested state is not available.
func (db *Database) Reader(blockRoot common.Hash) (Reader, error) { func (db *Database) Reader(blockRoot common.Hash) (Reader, error) {
@ -142,6 +181,25 @@ func (db *Database) Update(root common.Hash, parent common.Hash, block uint64, n
// to disk. As a side effect, all pre-images accumulated up to this point are // to disk. As a side effect, all pre-images accumulated up to this point are
// also written. // also written.
func (db *Database) Commit(root common.Hash, report bool) error { func (db *Database) Commit(root common.Hash, report bool) error {
batch := db.diskdb.NewBatch()
db.GetLock().Lock()
for _, v := range db.rawDirties {
batch.Put(v.K, v.V)
}
for k := range db.rawDirties {
delete(db.rawDirties, k)
}
db.GetLock().Unlock()
if err := batch.Write(); err != nil {
return err
}
batch.Reset()
if (root == common.Hash{}) {
return nil
}
if db.preimages != nil { if db.preimages != nil {
db.preimages.commit(true) db.preimages.commit(true)
} }

View file

@ -0,0 +1,32 @@
package trie
import (
"sync"
"github.com/VictoriaMetrics/fastcache"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/trie/triedb/hashdb"
)
func (db *Database) GetLock() *sync.RWMutex {
return db.backend.GetLock()
}
func (db *Database) GetCleans() *fastcache.Cache {
hdb, ok := db.backend.(*hashdb.Database)
if !ok {
panic("only hashdb supported")
}
return hdb.GetCleans()
}
// EmptyRoot indicate what root is for an empty trie, it depends on its underlying implement (zktrie or common trie)
func (db *Database) EmptyRoot() common.Hash {
if db.IsUsingZktrie() {
return common.Hash{}
} else {
return types.EmptyRootHash
}
}

47
trie/database_types.go Normal file
View file

@ -0,0 +1,47 @@
package trie
import (
"bytes"
"crypto/sha256"
"errors"
)
// ErrNotFound is used by the implementations of the interface db.Storage for
// when a key is not found in the storage
var ErrNotFound = errors.New("key not found")
// KV contains a key (K) and a value (V)
type KV struct {
K []byte
V []byte
}
// KvMap is a key-value map between a sha256 byte array hash, and a KV struct
type KvMap map[[sha256.Size]byte]KV
// Get retreives the value respective to a key from the KvMap
func (m KvMap) Get(k []byte) ([]byte, bool) {
v, ok := m[sha256.Sum256(k)]
return v.V, ok
}
// Put stores a key and a value in the KvMap
func (m KvMap) Put(k, v []byte) {
m[sha256.Sum256(k)] = KV{k, v}
}
// Concat concatenates arrays of bytes
func Concat(vs ...[]byte) []byte {
var b bytes.Buffer
for _, v := range vs {
b.Write(v)
}
return b.Bytes()
}
// Clone clones a byte array into a new byte array
func Clone(b0 []byte) []byte {
b1 := make([]byte, len(b0))
copy(b1, b0)
return b1
}

View file

@ -115,6 +115,11 @@ func (t *StateTrie) Prove(key []byte, proofDb ethdb.KeyValueWriter) error {
// key in a trie with the given root hash. VerifyProof returns an error if the // key in a trie with the given root hash. VerifyProof returns an error if the
// proof contains invalid trie nodes or the wrong value. // proof contains invalid trie nodes or the wrong value.
func VerifyProof(rootHash common.Hash, key []byte, proofDb ethdb.KeyValueReader) (value []byte, err error) { func VerifyProof(rootHash common.Hash, key []byte, proofDb ethdb.KeyValueReader) (value []byte, err error) {
// test the type of proof (for trie or SMT)
if buf, _ := proofDb.Get(magicHash); buf != nil {
return VerifyProofSMT(rootHash, key, proofDb)
}
key = keybytesToHex(key) key = keybytesToHex(key)
wantHash := rootHash wantHash := rootHash
for i := 0; ; i++ { for i := 0; ; i++ {

View file

@ -708,15 +708,15 @@ func TestTinyTrie(t *testing.T) {
_, accounts := makeAccounts(5) _, accounts := makeAccounts(5)
trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase(), nil)) trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase(), nil))
trie.MustUpdate(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000001337"), accounts[3]) trie.MustUpdate(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) t.Errorf("1: got %x, exp %x", root, exp)
} }
trie.MustUpdate(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000001338"), accounts[4]) trie.MustUpdate(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) t.Errorf("2: got %x, exp %x", root, exp)
} }
trie.MustUpdate(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000001339"), accounts[4]) trie.MustUpdate(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) t.Errorf("3: got %x, exp %x", root, exp)
} }
checktr := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase(), nil)) checktr := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase(), nil))
@ -740,7 +740,7 @@ func TestCommitAfterHash(t *testing.T) {
trie.Hash() trie.Hash()
trie.Commit(false) trie.Commit(false)
root := trie.Hash() root := trie.Hash()
exp := common.HexToHash("72f9d3f3fe1e1dd7b8936442e7642aef76371472d94319900790053c493f3fe6") exp := common.HexToHash("f0c0681648c93b347479cd58c61995557f01294425bd031ce1943c2799bbd4ec")
if exp != root { if exp != root {
t.Errorf("got %x, exp %x", root, exp) t.Errorf("got %x, exp %x", root, exp)
} }
@ -847,9 +847,9 @@ func TestCommitSequence(t *testing.T) {
count int count int
expWriteSeqHash []byte expWriteSeqHash []byte
}{ }{
{20, common.FromHex("873c78df73d60e59d4a2bcf3716e8bfe14554549fea2fc147cb54129382a8066")}, {20, common.FromHex("7b908cce3bc16abb3eac5dff6c136856526f15225f74ce860a2bec47912a5492")},
{200, common.FromHex("ba03d891bb15408c940eea5ee3d54d419595102648d02774a0268d892add9c8e")}, {200, common.FromHex("55791f6ec2f83fee512a2d3d4b505784fdefaea89974e10440d01d62a18a298a")},
{2000, common.FromHex("f7a184f20df01c94f09537401d11e68d97ad0c00115233107f51b9c287ce60c7")}, {2000, common.FromHex("ccb464abf67804538908c62431b3a6788e8dc6dee62aff9bfe6b10136acfceac")},
} { } {
addresses, accounts := makeAccounts(tc.count) addresses, accounts := makeAccounts(tc.count)
// This spongeDb is used to check the sequence of disk-db-writes // This spongeDb is used to check the sequence of disk-db-writes

View file

@ -36,10 +36,10 @@ import (
) )
var ( var (
memcacheCleanHitMeter = metrics.NewRegisteredMeter("hashdb/memcache/clean/hit", nil) MemcacheCleanHitMeter = metrics.NewRegisteredMeter("hashdb/memcache/clean/hit", nil)
memcacheCleanMissMeter = metrics.NewRegisteredMeter("hashdb/memcache/clean/miss", nil) MemcacheCleanMissMeter = metrics.NewRegisteredMeter("hashdb/memcache/clean/miss", nil)
memcacheCleanReadMeter = metrics.NewRegisteredMeter("hashdb/memcache/clean/read", nil) MemcacheCleanReadMeter = metrics.NewRegisteredMeter("hashdb/memcache/clean/read", nil)
memcacheCleanWriteMeter = metrics.NewRegisteredMeter("hashdb/memcache/clean/write", nil) MemcacheCleanWriteMeter = metrics.NewRegisteredMeter("hashdb/memcache/clean/write", nil)
memcacheDirtyHitMeter = metrics.NewRegisteredMeter("hashdb/memcache/dirty/hit", nil) memcacheDirtyHitMeter = metrics.NewRegisteredMeter("hashdb/memcache/dirty/hit", nil)
memcacheDirtyMissMeter = metrics.NewRegisteredMeter("hashdb/memcache/dirty/miss", nil) memcacheDirtyMissMeter = metrics.NewRegisteredMeter("hashdb/memcache/dirty/miss", nil)
@ -193,8 +193,8 @@ func (db *Database) Node(hash common.Hash) ([]byte, error) {
// Retrieve the node from the clean cache if available // Retrieve the node from the clean cache if available
if db.cleans != nil { if db.cleans != nil {
if enc := db.cleans.Get(nil, hash[:]); enc != nil { if enc := db.cleans.Get(nil, hash[:]); enc != nil {
memcacheCleanHitMeter.Mark(1) MemcacheCleanHitMeter.Mark(1)
memcacheCleanReadMeter.Mark(int64(len(enc))) MemcacheCleanReadMeter.Mark(int64(len(enc)))
return enc, nil return enc, nil
} }
} }
@ -215,8 +215,8 @@ func (db *Database) Node(hash common.Hash) ([]byte, error) {
if len(enc) != 0 { if len(enc) != 0 {
if db.cleans != nil { if db.cleans != nil {
db.cleans.Set(hash[:], enc) db.cleans.Set(hash[:], enc)
memcacheCleanMissMeter.Mark(1) MemcacheCleanMissMeter.Mark(1)
memcacheCleanWriteMeter.Mark(int64(len(enc))) MemcacheCleanWriteMeter.Mark(int64(len(enc)))
} }
return enc, nil return enc, nil
} }
@ -554,7 +554,7 @@ func (c *cleaner) Put(key []byte, rlp []byte) error {
// Move the flushed node into the clean cache to prevent insta-reloads // Move the flushed node into the clean cache to prevent insta-reloads
if c.db.cleans != nil { if c.db.cleans != nil {
c.db.cleans.Set(hash[:], rlp) c.db.cleans.Set(hash[:], rlp)
memcacheCleanWriteMeter.Mark(int64(len(rlp))) MemcacheCleanWriteMeter.Mark(int64(len(rlp)))
} }
return nil return nil
} }

View file

@ -0,0 +1,15 @@
package hashdb
import (
"sync"
"github.com/VictoriaMetrics/fastcache"
)
func (db *Database) GetLock() *sync.RWMutex {
return &db.lock
}
func (db *Database) GetCleans() *fastcache.Cache {
return db.cleans
}

View file

@ -0,0 +1,9 @@
package pathdb
import (
"sync"
)
func (db *Database) GetLock() *sync.RWMutex {
return &db.lock
}

287
trie/zk_trie.go Normal file
View file

@ -0,0 +1,287 @@
// Copyright 2015 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package trie
import (
"fmt"
zktrie "github.com/scroll-tech/zktrie/trie"
zkt "github.com/scroll-tech/zktrie/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto/poseidon"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie/trienode"
)
var magicHash []byte = []byte("THIS IS THE MAGIC INDEX FOR ZKTRIE")
// wrap zktrie for trie interface
type ZkTrie struct {
*zktrie.ZkTrie
db *ZktrieDatabase
}
func init() {
zkt.InitHashScheme(poseidon.HashFixedWithDomain)
}
func sanityCheckByte32Key(b []byte) {
if len(b) != 32 && len(b) != 20 {
panic(fmt.Errorf("do not support length except for 120bit and 256bit now. data: %v len: %v", b, len(b)))
}
}
// NewZkTrie creates a trie
// NewZkTrie bypasses all the buffer mechanism in *Database, it directly uses the
// underlying diskdb
func NewZkTrie(root common.Hash, db *ZktrieDatabase) (*ZkTrie, error) {
tr, err := zktrie.NewZkTrie(*zkt.NewByte32FromBytes(root.Bytes()), db)
if err != nil {
return nil, err
}
return &ZkTrie{tr, db}, nil
}
// Get returns the value for key stored in the trie.
// The value bytes must not be modified by the caller.
func (t *ZkTrie) Get(key []byte) []byte {
sanityCheckByte32Key(key)
res, err := t.TryGet(key)
if err != nil {
log.Error(fmt.Sprintf("Unhandled trie error: %v", err))
}
return res
}
func (t *ZkTrie) GetAccount(address common.Address) (*types.StateAccount, error) {
key := address.Bytes()
sanityCheckByte32Key(key)
res, err := t.TryGet(key)
if res == nil || err != nil {
return nil, err
}
return types.UnmarshalStateAccount(res)
}
func (t *ZkTrie) GetStorage(_ common.Address, key []byte) ([]byte, error) {
sanityCheckByte32Key(key)
enc, err := t.TryGet(key)
if err != nil || len(enc) == 0 {
return nil, err
}
_, content, _, err := rlp.Split(enc)
return content, err
}
func (t *ZkTrie) UpdateAccount(address common.Address, acc *types.StateAccount) error {
return t.TryUpdateAccount(address.Bytes(), acc)
}
// TryUpdateAccount will abstract the write of an account to the
// secure trie.
func (t *ZkTrie) TryUpdateAccount(key []byte, acc *types.StateAccount) error {
sanityCheckByte32Key(key)
value, flag := acc.MarshalFields()
return t.ZkTrie.TryUpdate(key, flag, value)
}
// Update associates key with value in the trie. Subsequent calls to
// Get will return value. If value has length zero, any existing value
// is deleted from the trie and calls to Get will return nil.
//
// The value bytes must not be modified by the caller while they are
// stored in the trie.
func (t *ZkTrie) Update(key, value []byte) {
if err := t.TryUpdate(key, value); err != nil {
log.Error(fmt.Sprintf("Unhandled trie error: %v", err))
}
}
// NOTE: value is restricted to length of bytes32.
// we override the underlying zktrie's TryUpdate method
func (t *ZkTrie) TryUpdate(key, value []byte) error {
sanityCheckByte32Key(key)
return t.ZkTrie.TryUpdate(key, 1, []zkt.Byte32{*zkt.NewByte32FromBytes(value)})
}
func (t *ZkTrie) UpdateContractCode(_ common.Address, _ common.Hash, _ []byte) error {
return nil
}
func (t *ZkTrie) UpdateStorage(_ common.Address, key, value []byte) error {
v, _ := rlp.EncodeToBytes(value)
return t.TryUpdate(key, v)
}
// Delete removes any existing value for key from the trie.
func (t *ZkTrie) Delete(key []byte) {
sanityCheckByte32Key(key)
if err := t.TryDelete(key); err != nil {
log.Error(fmt.Sprintf("Unhandled trie error: %v", err))
}
}
func (t *ZkTrie) DeleteAccount(address common.Address) error {
key := address.Bytes()
sanityCheckByte32Key(key)
return t.TryDelete(key)
}
func (t *ZkTrie) DeleteStorage(_ common.Address, key []byte) error {
sanityCheckByte32Key(key)
return t.TryDelete(key)
}
// GetKey returns the preimage of a hashed key that was
// previously used to store a value.
func (t *ZkTrie) GetKey(kHashBytes []byte) []byte {
// TODO: use a kv cache in memory
k, err := zkt.NewBigIntFromHashBytes(kHashBytes)
if err != nil {
log.Error(fmt.Sprintf("Unhandled trie error: %v", err))
}
if t.db.db.preimages != nil {
return t.db.db.preimages.preimage(common.BytesToHash(k.Bytes()))
}
return nil
}
// Commit writes all nodes and the secure hash pre-images to the trie's database.
// Nodes are stored with their sha3 hash as the key.
//
// Committing flushes nodes from memory. Subsequent Get calls will load nodes
// from the database.
//
// func (t *ZkTrie) Commit(LeafCallback) (common.Hash, int, error) {
// // in current implmentation, every update of trie already writes into database
// // so Commmit does nothing
// return t.Hash(), 0, nil
// }
func (t *ZkTrie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error) {
// in current implmentation, every update of trie already writes into database
// so Commmit does nothing
return t.Hash(), nil, nil
}
// Hash returns the root hash of SecureBinaryTrie. It does not write to the
// database and can be used even if the trie doesn't have one.
func (t *ZkTrie) Hash() common.Hash {
var hash common.Hash
hash.SetBytes(t.ZkTrie.Hash())
return hash
}
// Copy returns a copy of SecureBinaryTrie.
func (t *ZkTrie) Copy() *ZkTrie {
return &ZkTrie{t.ZkTrie.Copy(), t.db}
}
// NodeIterator returns an iterator that returns nodes of the underlying trie. Iteration
// starts at the key after the given start key.
func (t *ZkTrie) NodeIterator(start []byte) (NodeIterator, error) {
/// FIXME
panic("not implemented")
}
// hashKey returns the hash of key as an ephemeral buffer.
// The caller must not hold onto the return value because it will become
// invalid on the next call to hashKey or secKey.
/*func (t *ZkTrie) hashKey(key []byte) []byte {
if len(key) != 32 {
panic("non byte32 input to hashKey")
}
low16 := new(big.Int).SetBytes(key[:16])
high16 := new(big.Int).SetBytes(key[16:])
hash, err := poseidon.Hash([]*big.Int{low16, high16})
if err != nil {
panic(err)
}
return hash.Bytes()
}
*/
// Prove constructs a merkle proof for key. The result contains all encoded nodes
// on the path to the value at key. The value itself is also included in the last
// node and can be retrieved by verifying the proof.
//
// If the trie does not contain a value for key, the returned proof contains all
// nodes of the longest existing prefix of the key (at least the root node), ending
// with the node that proves the absence of the key.
// func (t *ZkTrie) Prove(key []byte, fromLevel uint, proofDb ethdb.KeyValueWriter) error {
func (t *ZkTrie) Prove(key []byte, proofDb ethdb.KeyValueWriter) error {
fromLevel := uint(0)
err := t.ZkTrie.Prove(key, fromLevel, func(n *zktrie.Node) error {
nodeHash, err := n.NodeHash()
if err != nil {
return err
}
if n.Type == zktrie.NodeTypeLeaf_New {
preImage := t.GetKey(n.NodeKey.Bytes())
if len(preImage) > 0 {
n.KeyPreimage = &zkt.Byte32{}
copy(n.KeyPreimage[:], preImage)
//return fmt.Errorf("key preimage not found for [%x] ref %x", n.NodeKey.Bytes(), k.Bytes())
}
}
return proofDb.Put(nodeHash[:], n.Value())
})
if err != nil {
return err
}
// we put this special kv pair in db so we can distinguish the type and
// make suitable Proof
return proofDb.Put(magicHash, zktrie.ProofMagicBytes())
}
// VerifyProof checks merkle proofs. The given proof must contain the value for
// key in a trie with the given root hash. VerifyProof returns an error if the
// proof contains invalid trie nodes or the wrong value.
func VerifyProofSMT(rootHash common.Hash, key []byte, proofDb ethdb.KeyValueReader) (value []byte, err error) {
h := zkt.NewHashFromBytes(rootHash.Bytes())
k, err := zkt.ToSecureKey(key)
if err != nil {
return nil, err
}
proof, n, err := zktrie.BuildZkTrieProof(h, k, len(key)*8, func(key *zkt.Hash) (*zktrie.Node, error) {
buf, _ := proofDb.Get(key[:])
if buf == nil {
return nil, zktrie.ErrKeyNotFound
}
n, err := zktrie.NewNodeFromBytes(buf)
return n, err
})
if err != nil {
// do not contain the key
return nil, err
} else if !proof.Existence {
return nil, nil
}
if zktrie.VerifyProofZkTrie(h, proof, n) {
return n.Data(), nil
} else {
return nil, fmt.Errorf("bad proof node %v", proof)
}
}

172
trie/zk_trie_database.go Normal file
View file

@ -0,0 +1,172 @@
package trie
import (
"math/big"
"github.com/syndtr/goleveldb/leveldb"
zktrie "github.com/scroll-tech/zktrie/trie"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/trie/triedb/hashdb"
)
// ZktrieDatabase Database adaptor implements zktrie.ZktrieDatbase
// It also reverses the bit order of the key being persisted.
// This ensures that the adjacent leaf in zktrie maintains minimal
// distance when persisted with dictionary order in LevelDB.
// Consequently, this optimizes the snapshot operation, allowing it
// to iterate through adjacent leaves at a reduced cost.
type ZktrieDatabase struct {
db *Database
prefix []byte
}
func NewZktrieDatabase(diskdb ethdb.Database) *ZktrieDatabase {
db := NewDatabase(diskdb, nil)
db.config.IsUsingZktrie = true
return &ZktrieDatabase{db: db, prefix: []byte{}}
}
// adhoc wrapper...
func NewZktrieDatabaseFromTriedb(db *Database) *ZktrieDatabase {
db.config.IsUsingZktrie = true
return &ZktrieDatabase{db: db, prefix: []byte{}}
}
// Put saves a key:value into the Storage
func (l *ZktrieDatabase) Put(k, v []byte) error {
k = bitReverse(k)
l.db.GetLock().Lock()
l.db.rawDirties.Put(Concat(l.prefix, k[:]), v)
l.db.GetLock().Unlock()
return nil
}
// Get retrieves a value from a key in the Storage
func (l *ZktrieDatabase) Get(key []byte) ([]byte, error) {
key = bitReverse(key)
concatKey := Concat(l.prefix, key[:])
l.db.GetLock().RLock()
value, ok := l.db.rawDirties.Get(concatKey)
l.db.GetLock().RUnlock()
if ok {
return value, nil
}
if l.db.GetCleans() != nil {
if enc := l.db.GetCleans().Get(nil, concatKey); enc != nil {
hashdb.MemcacheCleanHitMeter.Mark(1)
hashdb.MemcacheCleanReadMeter.Mark(int64(len(enc)))
return enc, nil
}
}
v, err := l.db.diskdb.Get(concatKey)
if err == leveldb.ErrNotFound {
return nil, zktrie.ErrKeyNotFound
}
if l.db.GetCleans() != nil {
l.db.GetCleans().Set(concatKey[:], v)
hashdb.MemcacheCleanMissMeter.Mark(1)
hashdb.MemcacheCleanWriteMeter.Mark(int64(len(v)))
}
return v, err
}
func (l *ZktrieDatabase) UpdatePreimage(preimage []byte, hashField *big.Int) {
db := l.db
if db.preimages != nil { // Ugly direct check but avoids the below write lock
// we must copy the input key
db.preimages.insertPreimage(map[common.Hash][]byte{common.BytesToHash(hashField.Bytes()): common.CopyBytes(preimage)})
}
}
// Iterate implements the method Iterate of the interface Storage
func (l *ZktrieDatabase) Iterate(f func([]byte, []byte) (bool, error)) error {
iter := l.db.diskdb.NewIterator(l.prefix, nil)
defer iter.Release()
for iter.Next() {
localKey := bitReverse(iter.Key()[len(l.prefix):])
if cont, err := f(localKey, iter.Value()); err != nil {
return err
} else if !cont {
break
}
}
iter.Release()
return iter.Error()
}
// Close implements the method Close of the interface Storage
func (l *ZktrieDatabase) Close() {
// FIXME: is this correct?
if err := l.db.diskdb.Close(); err != nil {
panic(err)
}
}
// List implements the method List of the interface Storage
func (l *ZktrieDatabase) List(limit int) ([]KV, error) {
ret := []KV{}
err := l.Iterate(func(key []byte, value []byte) (bool, error) {
ret = append(ret, KV{K: Clone(key), V: Clone(value)})
if len(ret) == limit {
return false, nil
}
return true, nil
})
return ret, err
}
func bitReverseForNibble(b byte) byte {
switch b {
case 0:
return 0
case 1:
return 8
case 2:
return 4
case 3:
return 12
case 4:
return 2
case 5:
return 10
case 6:
return 6
case 7:
return 14
case 8:
return 1
case 9:
return 9
case 10:
return 5
case 11:
return 13
case 12:
return 3
case 13:
return 11
case 14:
return 7
case 15:
return 15
default:
panic("unexpected input")
}
}
func bitReverse(inp []byte) (out []byte) {
l := len(inp)
out = make([]byte, l)
for i, b := range inp {
out[l-i-1] = bitReverseForNibble(b&15)<<4 + bitReverseForNibble(b>>4)
}
return
}

View file

@ -0,0 +1,63 @@
package trie
import (
"bytes"
"testing"
"github.com/ethereum/go-ethereum/common"
)
// grep from `feat/snap`
func reverseBitInPlace(b []byte) {
var v [8]uint8
for i := 0; i < len(b); i++ {
for j := 0; j < 8; j++ {
v[j] = (b[i] >> j) & 1
}
var tmp uint8 = 0
for j := 0; j < 8; j++ {
tmp |= v[8-j-1] << j
}
b[i] = tmp
}
}
func reverseBytesInPlace(b []byte) {
for i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 {
b[i], b[j] = b[j], b[i]
}
}
func TestBitReverse(t *testing.T) {
for _, testBytes := range [][]byte{
common.FromHex("7b908cce3bc16abb3eac5dff6c136856526f15225f74ce860a2bec47912a5492"),
common.FromHex("fac65cd2ad5e301083d0310dd701b5faaff1364cbe01cdbfaf4ec3609bb4149e"),
common.FromHex("55791f6ec2f83fee512a2d3d4b505784fdefaea89974e10440d01d62a18a298a"),
common.FromHex("5ab775b64d86a8058bb71c3c765d0f2158c14bbeb9cb32a65eda793a7e95e30f"),
common.FromHex("ccb464abf67804538908c62431b3a6788e8dc6dee62aff9bfe6b10136acfceac"),
common.FromHex("b908adff17a5aa9d6787324c39014a74b04cef7fba6a92aeb730f48da1ca665d"),
} {
b1 := bitReverse(testBytes)
reverseBitInPlace(testBytes)
reverseBytesInPlace(testBytes)
if !bytes.Equal(b1, testBytes) {
t.Errorf("unexpected bit reversed %x vs %x", b1, testBytes)
}
}
}
func TestBitDoubleReverse(t *testing.T) {
for _, testBytes := range [][]byte{
common.FromHex("7b908cce3bc16abb3eac5dff6c136856526f15225f74ce860a2bec47912a5492"),
common.FromHex("fac65cd2ad5e301083d0310dd701b5faaff1364cbe01cdbfaf4ec3609bb4149e"),
common.FromHex("55791f6ec2f83fee512a2d3d4b505784fdefaea89974e10440d01d62a18a298a"),
common.FromHex("5ab775b64d86a8058bb71c3c765d0f2158c14bbeb9cb32a65eda793a7e95e30f"),
common.FromHex("ccb464abf67804538908c62431b3a6788e8dc6dee62aff9bfe6b10136acfceac"),
common.FromHex("b908adff17a5aa9d6787324c39014a74b04cef7fba6a92aeb730f48da1ca665d"),
} {
b := bitReverse(bitReverse(testBytes))
if !bytes.Equal(b, testBytes) {
t.Errorf("unexpected double bit reversed %x vs %x", b, testBytes)
}
}
}

289
trie/zk_trie_impl_test.go Normal file
View file

@ -0,0 +1,289 @@
package trie
import (
"math/big"
"testing"
"github.com/iden3/go-iden3-crypto/constants"
cryptoUtils "github.com/iden3/go-iden3-crypto/utils"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
zktrie "github.com/scroll-tech/zktrie/trie"
zkt "github.com/scroll-tech/zktrie/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
)
// we do not need zktrie impl anymore, only made a wrapper for adapting testing
type zkTrieImplTestWrapper struct {
*zktrie.ZkTrieImpl
}
func newZkTrieImpl(storage *ZktrieDatabase, maxLevels int) (*zkTrieImplTestWrapper, error) {
return newZkTrieImplWithRoot(storage, &zkt.HashZero, maxLevels)
}
// NewZkTrieImplWithRoot loads a new ZkTrieImpl. If in the storage already exists one
// will open that one, if not, will create a new one.
func newZkTrieImplWithRoot(storage *ZktrieDatabase, root *zkt.Hash, maxLevels int) (*zkTrieImplTestWrapper, error) {
impl, err := zktrie.NewZkTrieImplWithRoot(storage, root, maxLevels)
if err != nil {
return nil, err
}
return &zkTrieImplTestWrapper{impl}, nil
}
// AddWord
// Deprecated: Add a Bytes32 kv to ZkTrieImpl, only for testing
func (mt *zkTrieImplTestWrapper) AddWord(kPreimage, vPreimage *zkt.Byte32) error {
k, err := kPreimage.Hash()
if err != nil {
return err
}
if v, _ := mt.TryGet(k.Bytes()); v != nil {
return zktrie.ErrEntryIndexAlreadyExists
}
return mt.ZkTrieImpl.TryUpdate(zkt.NewHashFromBigInt(k), 1, []zkt.Byte32{*vPreimage})
}
// GetLeafNodeByWord
// Deprecated: Get a Bytes32 kv to ZkTrieImpl, only for testing
func (mt *zkTrieImplTestWrapper) GetLeafNodeByWord(kPreimage *zkt.Byte32) (*zktrie.Node, error) {
k, err := kPreimage.Hash()
if err != nil {
return nil, err
}
return mt.ZkTrieImpl.GetLeafNode(zkt.NewHashFromBigInt(k))
}
// Deprecated: only for testing
func (mt *zkTrieImplTestWrapper) UpdateWord(kPreimage, vPreimage *zkt.Byte32) error {
k, err := kPreimage.Hash()
if err != nil {
return err
}
return mt.ZkTrieImpl.TryUpdate(zkt.NewHashFromBigInt(k), 1, []zkt.Byte32{*vPreimage})
}
// Deprecated: only for testing
func (mt *zkTrieImplTestWrapper) DeleteWord(kPreimage *zkt.Byte32) error {
k, err := kPreimage.Hash()
if err != nil {
return err
}
return mt.ZkTrieImpl.TryDelete(zkt.NewHashFromBigInt(k))
}
func (mt *zkTrieImplTestWrapper) TryGet(key []byte) ([]byte, error) {
return mt.ZkTrieImpl.TryGet(zkt.NewHashFromBytes(key))
}
func (mt *zkTrieImplTestWrapper) TryDelete(key []byte) error {
return mt.ZkTrieImpl.TryDelete(zkt.NewHashFromBytes(key))
}
// TryUpdateAccount will abstract the write of an account to the trie
func (mt *zkTrieImplTestWrapper) TryUpdateAccount(key []byte, acc *types.StateAccount) error {
value, flag := acc.MarshalFields()
return mt.ZkTrieImpl.TryUpdate(zkt.NewHashFromBytes(key), flag, value)
}
// NewHashFromHex returns a *Hash representation of the given hex string
func NewHashFromHex(h string) (*zkt.Hash, error) {
return zkt.NewHashFromCheckedBytes(common.FromHex(h))
}
type Fatalable interface {
Fatal(args ...interface{})
}
func newTestingMerkle(f Fatalable, numLevels int) *zkTrieImplTestWrapper {
mt, err := newZkTrieImpl(NewZktrieDatabase(rawdb.NewMemoryDatabase()), numLevels)
if err != nil {
f.Fatal(err)
return nil
}
return mt
}
func TestHashParsers(t *testing.T) {
h0 := zkt.NewHashFromBigInt(big.NewInt(0))
assert.Equal(t, "0", h0.String())
h1 := zkt.NewHashFromBigInt(big.NewInt(1))
assert.Equal(t, "1", h1.String())
h10 := zkt.NewHashFromBigInt(big.NewInt(10))
assert.Equal(t, "10", h10.String())
h7l := zkt.NewHashFromBigInt(big.NewInt(1234567))
assert.Equal(t, "1234567", h7l.String())
h8l := zkt.NewHashFromBigInt(big.NewInt(12345678))
assert.Equal(t, "12345678...", h8l.String())
b, ok := new(big.Int).SetString("4932297968297298434239270129193057052722409868268166443802652458940273154854", 10) //nolint:lll
assert.True(t, ok)
h := zkt.NewHashFromBigInt(b)
assert.Equal(t, "4932297968297298434239270129193057052722409868268166443802652458940273154854", h.BigInt().String()) //nolint:lll
assert.Equal(t, "49322979...", h.String())
assert.Equal(t, "0ae794eb9c3d8bbb9002e993fc2ed301dcbd2af5508ed072c375e861f1aa5b26", h.Hex())
b1, err := zkt.NewBigIntFromHashBytes(b.Bytes())
assert.Nil(t, err)
assert.Equal(t, new(big.Int).SetBytes(b.Bytes()).String(), b1.String())
b2, err := zkt.NewHashFromCheckedBytes(b.Bytes())
assert.Nil(t, err)
assert.Equal(t, b.String(), b2.BigInt().String())
h2, err := NewHashFromHex(h.Hex())
assert.Nil(t, err)
assert.Equal(t, h, h2)
_, err = NewHashFromHex("0x12")
assert.NotNil(t, err)
// check limits
a := new(big.Int).Sub(constants.Q, big.NewInt(1))
testHashParsers(t, a)
a = big.NewInt(int64(1))
testHashParsers(t, a)
}
func testHashParsers(t *testing.T, a *big.Int) {
require.True(t, cryptoUtils.CheckBigIntInField(a))
h := zkt.NewHashFromBigInt(a)
assert.Equal(t, a, h.BigInt())
hFromBytes, err := zkt.NewHashFromCheckedBytes(h.Bytes())
assert.Nil(t, err)
assert.Equal(t, h, hFromBytes)
assert.Equal(t, a, hFromBytes.BigInt())
assert.Equal(t, a.String(), hFromBytes.BigInt().String())
hFromHex, err := NewHashFromHex(h.Hex())
assert.Nil(t, err)
assert.Equal(t, h, hFromHex)
aBIFromHBytes, err := zkt.NewBigIntFromHashBytes(h.Bytes())
assert.Nil(t, err)
assert.Equal(t, a, aBIFromHBytes)
assert.Equal(t, new(big.Int).SetBytes(a.Bytes()).String(), aBIFromHBytes.String())
}
func TestMerkleTree_AddUpdateGetWord(t *testing.T) {
mt := newTestingMerkle(t, 10)
err := mt.AddWord(&zkt.Byte32{1}, &zkt.Byte32{2})
assert.Nil(t, err)
err = mt.AddWord(&zkt.Byte32{3}, &zkt.Byte32{4})
assert.Nil(t, err)
err = mt.AddWord(&zkt.Byte32{5}, &zkt.Byte32{6})
assert.Nil(t, err)
err = mt.AddWord(&zkt.Byte32{5}, &zkt.Byte32{7})
assert.Equal(t, zktrie.ErrEntryIndexAlreadyExists, err)
node, err := mt.GetLeafNodeByWord(&zkt.Byte32{1})
assert.Nil(t, err)
assert.Equal(t, len(node.ValuePreimage), 1)
assert.Equal(t, (&zkt.Byte32{2})[:], node.ValuePreimage[0][:])
node, err = mt.GetLeafNodeByWord(&zkt.Byte32{3})
assert.Nil(t, err)
assert.Equal(t, len(node.ValuePreimage), 1)
assert.Equal(t, (&zkt.Byte32{4})[:], node.ValuePreimage[0][:])
node, err = mt.GetLeafNodeByWord(&zkt.Byte32{5})
assert.Nil(t, err)
assert.Equal(t, len(node.ValuePreimage), 1)
assert.Equal(t, (&zkt.Byte32{6})[:], node.ValuePreimage[0][:])
err = mt.UpdateWord(&zkt.Byte32{1}, &zkt.Byte32{7})
assert.Nil(t, err)
err = mt.UpdateWord(&zkt.Byte32{3}, &zkt.Byte32{8})
assert.Nil(t, err)
err = mt.UpdateWord(&zkt.Byte32{5}, &zkt.Byte32{9})
assert.Nil(t, err)
node, err = mt.GetLeafNodeByWord(&zkt.Byte32{1})
assert.Nil(t, err)
assert.Equal(t, len(node.ValuePreimage), 1)
assert.Equal(t, (&zkt.Byte32{7})[:], node.ValuePreimage[0][:])
node, err = mt.GetLeafNodeByWord(&zkt.Byte32{3})
assert.Nil(t, err)
assert.Equal(t, len(node.ValuePreimage), 1)
assert.Equal(t, (&zkt.Byte32{8})[:], node.ValuePreimage[0][:])
node, err = mt.GetLeafNodeByWord(&zkt.Byte32{5})
assert.Nil(t, err)
assert.Equal(t, len(node.ValuePreimage), 1)
assert.Equal(t, (&zkt.Byte32{9})[:], node.ValuePreimage[0][:])
_, err = mt.GetLeafNodeByWord(&zkt.Byte32{100})
assert.Equal(t, zktrie.ErrKeyNotFound, err)
}
func TestMerkleTree_UpdateAccount(t *testing.T) {
mt := newTestingMerkle(t, 10)
acc1 := &types.StateAccount{
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"),
KeccakCodeHash: common.HexToHash("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470").Bytes(),
PoseidonCodeHash: common.HexToHash("05d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470").Bytes(),
CodeSize: 5,
}
err = mt.TryUpdateAccount(common.HexToAddress("0x4cb1aB63aF5D8931Ce09673EbD8ae2ce16fD6571").Bytes(), acc2)
assert.Nil(t, err)
bt, err := mt.TryGet(common.HexToAddress("0x05fDbDfaE180345C6Cff5316c286727CF1a43327").Bytes())
assert.Nil(t, err)
acc, err := types.UnmarshalStateAccount(bt)
assert.Nil(t, err)
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.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)
acc, err = types.UnmarshalStateAccount(bt)
assert.Nil(t, err)
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.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)
assert.Nil(t, bt)
err = mt.TryDelete(common.HexToHash("0x05fDbDfaE180345C6Cff5316c286727CF1a43327").Bytes())
assert.Nil(t, err)
bt, err = mt.TryGet(common.HexToAddress("0x05fDbDfaE180345C6Cff5316c286727CF1a43327").Bytes())
assert.Nil(t, err)
assert.Nil(t, bt)
err = mt.TryDelete(common.HexToAddress("0x4cb1aB63aF5D8931Ce09673EbD8ae2ce16fD6571").Bytes())
assert.Nil(t, err)
bt, err = mt.TryGet(common.HexToAddress("0x4cb1aB63aF5D8931Ce09673EbD8ae2ce16fD6571").Bytes())
assert.Nil(t, err)
assert.Nil(t, bt)
}

284
trie/zk_trie_proof_test.go Normal file
View file

@ -0,0 +1,284 @@
// Copyright 2015 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package trie
import (
"bytes"
mrand "math/rand"
"testing"
"time"
"github.com/stretchr/testify/assert"
zkt "github.com/scroll-tech/zktrie/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb/memorydb"
)
func init() {
mrand.Seed(time.Now().Unix())
}
// makeProvers creates Merkle trie provers based on different implementations to
// test all variations.
func makeSMTProvers(mt *ZkTrie) []func(key []byte) *memorydb.Database {
var provers []func(key []byte) *memorydb.Database
// Create a direct trie based Merkle prover
provers = append(provers, func(key []byte) *memorydb.Database {
word := zkt.NewByte32FromBytesPaddingZero(key)
k, err := word.Hash()
if err != nil {
panic(err)
}
proofDB := memorydb.New()
err = mt.Prove(common.BytesToHash(k.Bytes()).Bytes(), proofDB)
if err != nil {
panic(err)
}
return proofDB
})
return provers
}
func verifyValue(proveVal []byte, vPreimage []byte) bool {
return bytes.Equal(proveVal, vPreimage)
}
func TestSMTOneElementProof(t *testing.T) {
tr, _ := NewZkTrie(common.Hash{}, NewZktrieDatabase(rawdb.NewMemoryDatabase()))
mt := &zkTrieImplTestWrapper{tr.Tree()}
err := mt.UpdateWord(
zkt.NewByte32FromBytesPaddingZero(bytes.Repeat([]byte("k"), 32)),
zkt.NewByte32FromBytesPaddingZero(bytes.Repeat([]byte("v"), 32)),
)
assert.Nil(t, err)
for i, prover := range makeSMTProvers(tr) {
keyBytes := bytes.Repeat([]byte("k"), 32)
proof := prover(keyBytes)
if proof == nil {
t.Fatalf("prover %d: nil proof", i)
}
if proof.Len() != 2 {
t.Errorf("prover %d: proof should have 1+1 element (including the magic kv)", i)
}
val, err := VerifyProof(common.BytesToHash(mt.Root().Bytes()), keyBytes, proof)
if err != nil {
t.Fatalf("prover %d: failed to verify proof: %v\nraw proof: %x", i, err, proof)
}
if !verifyValue(val, bytes.Repeat([]byte("v"), 32)) {
t.Fatalf("prover %d: verified value mismatch: want 'v' get %x", i, val)
}
}
}
func TestSMTProof(t *testing.T) {
mt, vals := randomZktrie(t, 500)
root := mt.Tree().Root()
for i, prover := range makeSMTProvers(mt) {
for _, kv := range vals {
proof := prover(kv.k)
if proof == nil {
t.Fatalf("prover %d: missing key %x while constructing proof", i, kv.k)
}
val, err := VerifyProof(common.BytesToHash(root.Bytes()), kv.k, proof)
if err != nil {
t.Fatalf("prover %d: failed to verify proof for key %x: %v\nraw proof: %x\n", i, kv.k, err, proof)
}
if !verifyValue(val, zkt.NewByte32FromBytesPaddingZero(kv.v)[:]) {
t.Fatalf("prover %d: verified value mismatch for key %x, want %x, get %x", i, kv.k, kv.v, val)
}
}
}
}
func TestSMTBadProof(t *testing.T) {
mt, vals := randomZktrie(t, 500)
root := mt.Tree().Root()
for i, prover := range makeSMTProvers(mt) {
for _, kv := range vals {
proof := prover(kv.k)
if proof == nil {
t.Fatalf("prover %d: nil proof", i)
}
it := proof.NewIterator(nil, nil)
for i, d := 0, mrand.Intn(proof.Len()); i <= d; i++ {
it.Next()
}
key := it.Key()
val, _ := proof.Get(key)
proof.Delete(key)
it.Release()
mutateByte(val)
proof.Put(crypto.Keccak256(val), val)
if _, err := VerifyProof(common.BytesToHash(root.Bytes()), kv.k, proof); err == nil {
t.Fatalf("prover %d: expected proof to fail for key %x", i, kv.k)
}
}
}
}
// Tests that missing keys can also be proven. The test explicitly uses a single
// entry trie and checks for missing keys both before and after the single entry.
func TestSMTMissingKeyProof(t *testing.T) {
tr, _ := NewZkTrie(common.Hash{}, NewZktrieDatabase(rawdb.NewMemoryDatabase()))
mt := &zkTrieImplTestWrapper{tr.Tree()}
err := mt.UpdateWord(
zkt.NewByte32FromBytesPaddingZero(bytes.Repeat([]byte("k"), 32)),
zkt.NewByte32FromBytesPaddingZero(bytes.Repeat([]byte("v"), 32)),
)
assert.Nil(t, err)
prover := makeSMTProvers(tr)[0]
for i, key := range []string{"a", "j", "l", "z"} {
keyBytes := bytes.Repeat([]byte(key), 32)
proof := prover(keyBytes)
if proof.Len() != 2 {
t.Errorf("test %d: proof should have 2 element (with magic kv)", i)
}
val, err := VerifyProof(common.BytesToHash(mt.Root().Bytes()), keyBytes, proof)
if err != nil {
t.Fatalf("test %d: failed to verify proof: %v\nraw proof: %x", i, err, proof)
}
if val != nil {
t.Fatalf("test %d: verified value mismatch: have %x, want nil", i, val)
}
}
}
func randomZktrie(t *testing.T, n int) (*ZkTrie, map[string]*kv) {
tr, err := NewZkTrie(common.Hash{}, NewZktrieDatabase(rawdb.NewMemoryDatabase()))
if err != nil {
panic(err)
}
mt := &zkTrieImplTestWrapper{tr.Tree()}
vals := make(map[string]*kv)
for i := byte(0); i < 100; i++ {
value := &kv{common.LeftPadBytes([]byte{i}, 32), bytes.Repeat([]byte{i}, 32), false}
value2 := &kv{common.LeftPadBytes([]byte{i + 10}, 32), bytes.Repeat([]byte{i}, 32), false}
err = mt.UpdateWord(zkt.NewByte32FromBytesPaddingZero(value.k), zkt.NewByte32FromBytesPaddingZero(value.v))
assert.Nil(t, err)
err = mt.UpdateWord(zkt.NewByte32FromBytesPaddingZero(value2.k), zkt.NewByte32FromBytesPaddingZero(value2.v))
assert.Nil(t, err)
vals[string(value.k)] = value
vals[string(value2.k)] = value2
}
for i := 0; i < n; i++ {
value := &kv{randBytes(32), randBytes(20), false}
err = mt.UpdateWord(zkt.NewByte32FromBytesPaddingZero(value.k), zkt.NewByte32FromBytesPaddingZero(value.v))
assert.Nil(t, err)
vals[string(value.k)] = value
}
return tr, vals
}
// Tests that new "proof trace" feature
func TestProofWithDeletion(t *testing.T) {
tr, _ := NewZkTrie(common.Hash{}, NewZktrieDatabase(rawdb.NewMemoryDatabase()))
mt := &zkTrieImplTestWrapper{tr.Tree()}
key1 := bytes.Repeat([]byte("l"), 32)
key2 := bytes.Repeat([]byte("m"), 32)
err := mt.UpdateWord(
zkt.NewByte32FromBytesPaddingZero(key1),
zkt.NewByte32FromBytesPaddingZero(bytes.Repeat([]byte("v"), 32)),
)
assert.NoError(t, err)
err = mt.UpdateWord(
zkt.NewByte32FromBytesPaddingZero(key2),
zkt.NewByte32FromBytesPaddingZero(bytes.Repeat([]byte("n"), 32)),
)
assert.NoError(t, err)
proof := memorydb.New()
s_key1, err := zkt.ToSecureKeyBytes(key1)
assert.NoError(t, err)
proofTracer := tr.NewProofTracer()
err = proofTracer.Prove(s_key1.Bytes(), 0, proof)
assert.NoError(t, err)
nd, err := tr.TryGet(key2)
assert.NoError(t, err)
s_key2, err := zkt.ToSecureKeyBytes(bytes.Repeat([]byte("x"), 32))
assert.NoError(t, err)
err = proofTracer.Prove(s_key2.Bytes(), 0, proof)
assert.NoError(t, err)
//assert.Equal(t, len(sibling1), len(delTracer.GetProofs()))
siblings, err := proofTracer.GetDeletionProofs()
assert.NoError(t, err)
assert.Equal(t, 0, len(siblings))
proofTracer.MarkDeletion(s_key1.Bytes())
siblings, err = proofTracer.GetDeletionProofs()
assert.NoError(t, err)
assert.Equal(t, 1, len(siblings))
l := len(siblings[0])
// a hacking to grep the value part directly from the encoded leaf node,
// notice the sibling of key `k*32`` is just the leaf of key `m*32`
assert.Equal(t, siblings[0][l-33:l-1], nd)
// Marking a key that is currently not hit (but terminated by an empty node)
// also causes it to be added to the deletion proof
proofTracer.MarkDeletion(s_key2.Bytes())
siblings, err = proofTracer.GetDeletionProofs()
assert.NoError(t, err)
assert.Equal(t, 2, len(siblings))
key3 := bytes.Repeat([]byte("x"), 32)
err = mt.UpdateWord(
zkt.NewByte32FromBytesPaddingZero(key3),
zkt.NewByte32FromBytesPaddingZero(bytes.Repeat([]byte("z"), 32)),
)
assert.NoError(t, err)
proofTracer = tr.NewProofTracer()
err = proofTracer.Prove(s_key1.Bytes(), 0, proof)
assert.NoError(t, err)
err = proofTracer.Prove(s_key2.Bytes(), 0, proof)
assert.NoError(t, err)
proofTracer.MarkDeletion(s_key1.Bytes())
siblings, err = proofTracer.GetDeletionProofs()
assert.NoError(t, err)
assert.Equal(t, 1, len(siblings))
proofTracer.MarkDeletion(s_key2.Bytes())
siblings, err = proofTracer.GetDeletionProofs()
assert.NoError(t, err)
assert.Equal(t, 2, len(siblings))
// one of the siblings is just leaf for key2, while
// another one must be a middle node
match1 := bytes.Equal(siblings[0][l-33:l-1], nd)
match2 := bytes.Equal(siblings[1][l-33:l-1], nd)
assert.True(t, match1 || match2)
assert.False(t, match1 && match2)
}

270
trie/zk_trie_test.go Normal file
View file

@ -0,0 +1,270 @@
// Copyright 2015 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package trie
import (
"bytes"
"encoding/binary"
"io/ioutil"
"os"
"runtime"
"sync"
"testing"
"github.com/stretchr/testify/assert"
zkt "github.com/scroll-tech/zktrie/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/trie/triedb/hashdb"
)
func newEmptyZkTrie() *ZkTrie {
trie, _ := NewZkTrie(
common.Hash{},
&ZktrieDatabase{
db: NewDatabase(rawdb.NewMemoryDatabase(),
&Config{Preimages: true}),
prefix: []byte{},
},
)
return trie
}
// makeTestSecureTrie creates a large enough secure trie for testing.
func makeTestZkTrie() (*ZktrieDatabase, *ZkTrie, map[string][]byte) {
// Create an empty trie
triedb := NewZktrieDatabase(rawdb.NewMemoryDatabase())
trie, _ := NewZkTrie(common.Hash{}, triedb)
// Fill it with some arbitrary data
content := make(map[string][]byte)
for i := byte(0); i < 255; i++ {
// Map the same data under multiple keys
key, val := common.LeftPadBytes([]byte{1, i}, 32), bytes.Repeat([]byte{i}, 32)
content[string(key)] = val
trie.Update(key, val)
key, val = common.LeftPadBytes([]byte{2, i}, 32), bytes.Repeat([]byte{i}, 32)
content[string(key)] = val
trie.Update(key, val)
// Add some other data to inflate the trie
for j := byte(3); j < 13; j++ {
key, val = common.LeftPadBytes([]byte{j, i}, 32), bytes.Repeat([]byte{j, i}, 16)
content[string(key)] = val
trie.Update(key, val)
}
}
trie.Commit(false)
// Return the generated trie
return triedb, trie, content
}
func TestZktrieDelete(t *testing.T) {
t.Skip("var-len kv not supported")
trie := newEmptyZkTrie()
vals := []struct{ k, v string }{
{"do", "verb"},
{"ether", "wookiedoo"},
{"horse", "stallion"},
{"shaman", "horse"},
{"doge", "coin"},
{"ether", ""},
{"dog", "puppy"},
{"shaman", ""},
}
for _, val := range vals {
if val.v != "" {
trie.Update([]byte(val.k), []byte(val.v))
} else {
trie.Delete([]byte(val.k))
}
}
hash := trie.Hash()
exp := common.HexToHash("29b235a58c3c25ab83010c327d5932bcf05324b7d6b1185e650798034783ca9d")
if hash != exp {
t.Errorf("expected %x got %x", exp, hash)
}
}
func TestZktrieGetKey(t *testing.T) {
trie := newEmptyZkTrie()
key := []byte("0a1b2c3d4e5f6g7h8i9j0a1b2c3d4e5f")
value := []byte("9j8i7h6g5f4e3d2c1b0a9j8i7h6g5f4e")
trie.Update(key, value)
kPreimage := zkt.NewByte32FromBytesPaddingZero(key)
kHash, err := kPreimage.Hash()
assert.Nil(t, err)
if !bytes.Equal(trie.Get(key), value) {
t.Errorf("Get did not return bar")
}
if k := trie.GetKey(kHash.Bytes()); !bytes.Equal(k, key) {
t.Errorf("GetKey returned %q, want %q", k, key)
}
}
func TestZkTrieConcurrency(t *testing.T) {
// Create an initial trie and copy if for concurrent access
_, trie, _ := makeTestZkTrie()
threads := runtime.NumCPU()
tries := make([]*ZkTrie, threads)
for i := 0; i < threads; i++ {
cpy := *trie
tries[i] = &cpy
}
// Start a batch of goroutines interactng with the trie
pend := new(sync.WaitGroup)
pend.Add(threads)
for i := 0; i < threads; i++ {
go func(index int) {
defer pend.Done()
for j := byte(0); j < 255; j++ {
// Map the same data under multiple keys
key, val := common.LeftPadBytes([]byte{byte(index), 1, j}, 32), bytes.Repeat([]byte{j}, 32)
tries[index].Update(key, val)
key, val = common.LeftPadBytes([]byte{byte(index), 2, j}, 32), bytes.Repeat([]byte{j}, 32)
tries[index].Update(key, val)
// Add some other data to inflate the trie
for k := byte(3); k < 13; k++ {
key, val = common.LeftPadBytes([]byte{byte(index), k, j}, 32), bytes.Repeat([]byte{k, j}, 16)
tries[index].Update(key, val)
}
}
tries[index].Commit(false)
}(i)
}
// Wait for all threads to finish
pend.Wait()
}
func tempDBZK(b *testing.B) (string, *Database) {
dir, err := ioutil.TempDir("", "zktrie-bench")
assert.NoError(b, err)
diskdb, err := rawdb.NewLevelDBDatabase(dir, 256, 0, "", false)
assert.NoError(b, err)
config := &Config{
Preimages: true,
HashDB: &hashdb.Config{CleanCacheSize: 256},
IsUsingZktrie: true,
}
return dir, NewDatabase(diskdb, config)
}
const benchElemCountZk = 10000
func BenchmarkZkTrieGet(b *testing.B) {
dir, tmpdb := tempDBZK(b)
zkTrie, _ := NewZkTrie(common.Hash{}, NewZktrieDatabaseFromTriedb(tmpdb))
defer func() {
ldb := zkTrie.db.db.diskdb
ldb.Close()
os.RemoveAll(dir)
}()
k := make([]byte, 32)
for i := 0; i < benchElemCountZk; i++ {
binary.LittleEndian.PutUint64(k, uint64(i))
err := zkTrie.TryUpdate(k, k)
assert.NoError(b, err)
}
zkTrie.db.db.Commit(common.Hash{}, true)
b.ResetTimer()
for i := 0; i < b.N; i++ {
binary.LittleEndian.PutUint64(k, uint64(i))
_, err := zkTrie.TryGet(k)
assert.NoError(b, err)
}
b.StopTimer()
}
func BenchmarkZkTrieUpdate(b *testing.B) {
dir, tmpdb := tempDBZK(b)
zkTrie, _ := NewZkTrie(common.Hash{}, NewZktrieDatabaseFromTriedb(tmpdb))
defer func() {
ldb := zkTrie.db.db.diskdb
ldb.Close()
os.RemoveAll(dir)
}()
k := make([]byte, 32)
v := make([]byte, 32)
b.ReportAllocs()
for i := 0; i < benchElemCountZk; i++ {
binary.LittleEndian.PutUint64(k, uint64(i))
err := zkTrie.TryUpdate(k, k)
assert.NoError(b, err)
}
binary.LittleEndian.PutUint64(k, benchElemCountZk/2)
//zkTrie.Commit(false)
zkTrie.db.db.Commit(common.Hash{}, true)
b.ResetTimer()
for i := 0; i < b.N; i++ {
binary.LittleEndian.PutUint64(k, uint64(i))
binary.LittleEndian.PutUint64(v, 0xffffffff+uint64(i))
err := zkTrie.TryUpdate(k, v)
assert.NoError(b, err)
}
b.StopTimer()
}
func TestZkTrieDelete(t *testing.T) {
key := make([]byte, 32)
value := make([]byte, 32)
trie1 := newEmptyZkTrie()
var count int = 6
var hashes []common.Hash
hashes = append(hashes, trie1.Hash())
for i := 0; i < count; i++ {
binary.LittleEndian.PutUint64(key, uint64(i))
binary.LittleEndian.PutUint64(value, uint64(i))
err := trie1.TryUpdate(key, value)
assert.NoError(t, err)
hashes = append(hashes, trie1.Hash())
}
// binary.LittleEndian.PutUint64(key, uint64(0xffffff))
// err := trie1.TryDelete(key)
// assert.Equal(t, err, zktrie.ErrKeyNotFound)
trie1.Commit(false)
for i := count - 1; i >= 0; i-- {
binary.LittleEndian.PutUint64(key, uint64(i))
v, err := trie1.TryGet(key)
assert.NoError(t, err)
assert.NotEmpty(t, v)
err = trie1.TryDelete(key)
assert.NoError(t, err)
hash := trie1.Hash()
assert.Equal(t, hashes[i].Hex(), hash.Hex())
}
}

349
trie/zkproof/orderer.go Normal file
View file

@ -0,0 +1,349 @@
package zkproof
import (
"math/big"
"sort"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
)
type opIterator interface {
next() *types.AccountWrapper
}
type opOrderer interface {
readonly(bool)
absorb(*types.AccountWrapper)
absorbStorage(*types.AccountWrapper, *types.StorageWrapper)
end_absorb() opIterator
}
type iterateOp []*types.AccountWrapper
func (ops *iterateOp) next() *types.AccountWrapper {
sl := *ops
if len(sl) == 0 {
return nil
}
*ops = sl[1:]
return sl[0]
}
type simpleOrderer struct {
readOnly int
savedOp []*types.AccountWrapper
}
func (od *simpleOrderer) SavedOp() []*types.AccountWrapper { return od.savedOp }
func (od *simpleOrderer) readonly(mode bool) {
if mode {
od.readOnly += 1
} else if od.readOnly == 0 {
panic("unexpected readonly mode stack pop")
} else {
od.readOnly -= 1
}
}
func (od *simpleOrderer) absorb(st *types.AccountWrapper) {
if od.readOnly > 0 {
return
}
od.savedOp = append(od.savedOp, st)
}
func (od *simpleOrderer) absorbStorage(st *types.AccountWrapper, _ *types.StorageWrapper) {
od.absorb(st)
}
func (od *simpleOrderer) end_absorb() opIterator {
ret := iterateOp(od.savedOp)
return &ret
}
type multiOpIterator []opIterator
func (opss *multiOpIterator) next() *types.AccountWrapper {
sl := *opss
if len(sl) == 0 {
return nil
}
op := sl[0].next()
for op == nil {
sl = sl[1:]
*opss = sl
if len(sl) == 0 {
return nil
}
op = sl[0].next()
}
return op
}
type rwTblOrderer struct {
readOnly int
readOnlySnapshot struct {
accounts map[string]*types.AccountWrapper
storages map[string]map[string]*types.StorageWrapper
}
initedData map[common.Address]*types.AccountWrapper
// help to track all accounts being touched, and provide the
// completed account status for storage updating
traced map[string]*types.AccountWrapper
opAccNonce map[string]*types.AccountWrapper
opAccBalance map[string]*types.AccountWrapper
opAccCodeHash map[string]*types.AccountWrapper
opStorage map[string]map[string]*types.StorageWrapper
}
func NewSimpleOrderer() *simpleOrderer { return &simpleOrderer{} }
func NewRWTblOrderer(inited map[common.Address]*types.StateAccount) *rwTblOrderer {
initedAcc := make(map[common.Address]*types.AccountWrapper)
for addr, data := range inited {
if data == nil {
initedAcc[addr] = &types.AccountWrapper{
Address: addr,
Balance: (*hexutil.Big)(big.NewInt(0)),
}
} else {
bl := data.Balance
if bl == nil {
bl = big.NewInt(0)
}
initedAcc[addr] = &types.AccountWrapper{
Address: addr,
Nonce: data.Nonce,
Balance: (*hexutil.Big)(bl),
KeccakCodeHash: common.BytesToHash(data.KeccakCodeHash),
PoseidonCodeHash: common.BytesToHash(data.PoseidonCodeHash),
CodeSize: data.CodeSize,
}
}
}
return &rwTblOrderer{
initedData: initedAcc,
traced: make(map[string]*types.AccountWrapper),
opAccNonce: make(map[string]*types.AccountWrapper),
opAccBalance: make(map[string]*types.AccountWrapper),
opAccCodeHash: make(map[string]*types.AccountWrapper),
opStorage: make(map[string]map[string]*types.StorageWrapper),
}
}
func (od *rwTblOrderer) readonly(mode bool) {
if mode {
if od.readOnly == 0 {
od.readOnlySnapshot.accounts = make(map[string]*types.AccountWrapper)
od.readOnlySnapshot.storages = make(map[string]map[string]*types.StorageWrapper)
}
od.readOnly += 1
} else if od.readOnly == 0 {
panic("unexpected readonly mode stack pop")
} else {
od.readOnly -= 1
if od.readOnly == 0 {
for addrS, st := range od.readOnlySnapshot.accounts {
od.absorb(st)
if m, existed := od.readOnlySnapshot.storages[addrS]; existed {
for _, stg := range m {
st.Storage = stg
od.absorbStorage(st, nil)
}
}
}
}
}
}
func (od *rwTblOrderer) absorbStorage(st *types.AccountWrapper, before *types.StorageWrapper) {
if st.Storage == nil {
panic("do not call absorbStorage ")
}
od.absorb(st)
addrStr := st.Address.String()
if stg := st.Storage; stg != nil {
m, existed := od.opStorage[addrStr]
if !existed {
m = make(map[string]*types.StorageWrapper)
od.opStorage[addrStr] = m
}
// key must be unified into 32 bytes
keyBytes := hexutil.MustDecode(stg.Key)
keyStr := common.BytesToHash(keyBytes).String()
// trace every "touched" status for readOnly
if od.readOnly > 0 {
m, existed := od.readOnlySnapshot.storages[addrStr]
if !existed {
m = make(map[string]*types.StorageWrapper)
od.readOnlySnapshot.storages[addrStr] = m
}
if _, hashTraced := m[keyStr]; !hashTraced {
if before != nil {
m[keyStr] = before
} else {
m[keyStr] = stg
}
}
}
m[keyStr] = stg
}
}
func (od *rwTblOrderer) absorb(st *types.AccountWrapper) {
initedRef, existed := od.initedData[st.Address]
if !existed {
panic("encounter unprepared status")
}
addrStr := st.Address.String()
// trace every "touched" status for readOnly
if od.readOnly > 0 {
snapShot, existed := od.traced[addrStr]
if !existed {
snapShot = initedRef
}
if _, hasTraced := od.readOnlySnapshot.accounts[addrStr]; !hasTraced {
od.readOnlySnapshot.accounts[addrStr] = copyAccountState(snapShot)
}
}
if isDeletedAccount(st) {
// for account delete, made a safer data for status
st = &types.AccountWrapper{
Address: st.Address,
Balance: (*hexutil.Big)(big.NewInt(0)),
}
}
od.traced[addrStr] = st
// notice there would be at least one entry for all 3 fields when accessing an address
// this may caused extract "read" op in mpt circuit which has no corresponding one in rwtable
// we can avoid it unless obtaining more tips from the understanding of opcode
// but it would be ok if we have adopted the new lookup way (root_prev, root_cur) under discussion:
// https://github.com/privacy-scaling-explorations/zkevm-specs/issues/217
if traced, existed := od.opAccNonce[addrStr]; !existed {
traced = copyAccountState(st)
traced.Balance = initedRef.Balance
traced.KeccakCodeHash = initedRef.KeccakCodeHash
traced.PoseidonCodeHash = initedRef.PoseidonCodeHash
traced.CodeSize = initedRef.CodeSize
traced.Storage = nil
od.opAccNonce[addrStr] = traced
} else {
traced.Nonce = st.Nonce
}
if traced, existed := od.opAccBalance[addrStr]; !existed {
traced = copyAccountState(st)
traced.KeccakCodeHash = initedRef.KeccakCodeHash
traced.PoseidonCodeHash = initedRef.PoseidonCodeHash
traced.CodeSize = initedRef.CodeSize
traced.Storage = nil
od.opAccBalance[addrStr] = traced
} else {
traced.Nonce = st.Nonce
traced.Balance = st.Balance
}
if traced, existed := od.opAccCodeHash[addrStr]; !existed {
traced = copyAccountState(st)
traced.Storage = nil
od.opAccCodeHash[addrStr] = traced
} else {
traced.Nonce = st.Nonce
traced.Balance = st.Balance
traced.KeccakCodeHash = st.KeccakCodeHash
traced.PoseidonCodeHash = st.PoseidonCodeHash
traced.CodeSize = st.CodeSize
}
}
func (od *rwTblOrderer) end_absorb() opIterator {
// now sort every map by address / key
// inited has collected all address, just sort address once
sortedAddrs := make([]string, 0, len(od.traced))
for addrs := range od.traced {
sortedAddrs = append(sortedAddrs, addrs)
}
sort.Strings(sortedAddrs)
var iterNonce []*types.AccountWrapper
var iterBalance []*types.AccountWrapper
var iterCodeHash []*types.AccountWrapper
var iterStorage []*types.AccountWrapper
for _, addrStr := range sortedAddrs {
if v, existed := od.opAccNonce[addrStr]; existed {
iterNonce = append(iterNonce, v)
}
if v, existed := od.opAccBalance[addrStr]; existed {
iterBalance = append(iterBalance, v)
}
if v, existed := od.opAccCodeHash[addrStr]; existed {
iterCodeHash = append(iterCodeHash, v)
}
if stgM, existed := od.opStorage[addrStr]; existed {
tracedStatus := od.traced[addrStr]
if tracedStatus == nil {
panic("missed traced status found in storage slot")
}
sortedKeys := make([]string, 0, len(stgM))
for key := range stgM {
sortedKeys = append(sortedKeys, key)
}
sort.Strings(sortedKeys)
for _, key := range sortedKeys {
st := copyAccountState(tracedStatus)
st.Storage = stgM[key]
iterStorage = append(iterStorage, st)
}
}
}
var finalRet []opIterator
for _, arr := range [][]*types.AccountWrapper{iterNonce, iterBalance, iterCodeHash, iterStorage} {
wrappedIter := iterateOp(arr)
finalRet = append(finalRet, &wrappedIter)
}
wrappedRet := multiOpIterator(finalRet)
return &wrappedRet
}

59
trie/zkproof/types.go Normal file
View file

@ -0,0 +1,59 @@
package zkproof
import (
"github.com/ethereum/go-ethereum/common/hexutil"
)
type MPTWitnessType int
const (
MPTWitnessNothing MPTWitnessType = iota
MPTWitnessNatural
MPTWitnessRWTbl
)
// SMTPathNode represent a node in the SMT Path, all hash is saved by the present of
// zktype.Hash
type SMTPathNode struct {
Value hexutil.Bytes `json:"value"`
Sibling hexutil.Bytes `json:"sibling"`
}
// SMTPath is the whole path of SMT
type SMTPath struct {
KeyPathPart *hexutil.Big `json:"pathPart"` //the path part in key
Root hexutil.Bytes `json:"root"`
Path []SMTPathNode `json:"path,omitempty"` //path start from top
Leaf *SMTPathNode `json:"leaf,omitempty"` //would be omitted for empty leaf, the sibling indicate key
}
// 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)
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
type StateStorage struct {
Key hexutil.Bytes `json:"key"` //notice this is the preimage of storage key
Value hexutil.Bytes `json:"value"`
}
// StorageTrace record the updating on state trie and (if changed) account trie
// represent by the [before, after] updating of SMTPath amont tries and Account
type StorageTrace struct {
// which log the trace is responded for, -1 indicate not caused
// by opcode (like gasRefund, coinbase, setNonce, etc)
Address hexutil.Bytes `json:"address"`
AccountKey hexutil.Bytes `json:"accountKey"`
AccountPath [2]*SMTPath `json:"accountPath"`
AccountUpdate [2]*StateAccount `json:"accountUpdate"`
StateKey hexutil.Bytes `json:"stateKey,omitempty"`
CommonStateRoot hexutil.Bytes `json:"commonStateRoot,omitempty"` //CommonStateRoot is used if there is no update on state storage
StatePath [2]*SMTPath `json:"statePath,omitempty"`
StateUpdate [2]*StateStorage `json:"stateUpdate,omitempty"`
}

826
trie/zkproof/writer.go Normal file
View file

@ -0,0 +1,826 @@
package zkproof
import (
"bytes"
"encoding/json"
"fmt"
"math/big"
zktrie "github.com/scroll-tech/zktrie/trie"
zkt "github.com/scroll-tech/zktrie/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/trie"
)
type ProofList [][]byte
func (n *ProofList) Put(key []byte, value []byte) error {
*n = append(*n, value)
return nil
}
func (n *ProofList) Delete(key []byte) error {
panic("not supported")
}
func addressToKey(addr common.Address) *zkt.Hash {
var preImage zkt.Byte32
copy(preImage[:], addr.Bytes())
h, err := preImage.Hash()
if err != nil {
log.Error("hash failure", "preImage", hexutil.Encode(preImage[:]))
return nil
}
return zkt.NewHashFromBigInt(h)
}
// resume the proof bytes into db and return the leaf node
func resumeProofs(proof []hexutil.Bytes, db ethdb.Database) *zktrie.Node {
for _, buf := range proof {
n, err := zktrie.DecodeSMTProof(buf)
if err != nil {
log.Warn("decode proof string fail", "error", err)
} else if n != nil {
hash, err := n.NodeHash()
if err != nil {
log.Warn("node has no valid node hash", "error", err)
} else {
//notice: must consistent with trie/merkletree.go
bt := hash[:]
db.Put(bt, buf)
if n.Type == zktrie.NodeTypeLeaf_New || n.Type == zktrie.NodeTypeEmpty_New {
return n
}
}
}
}
return nil
}
// we have a trick here which suppose the proof array include all middle nodes along the
// whole path in sequence, from root to leaf
func decodeProofForMPTPath(proof ProofList, path *SMTPath) {
var lastNode *zktrie.Node
keyPath := big.NewInt(0)
path.KeyPathPart = (*hexutil.Big)(keyPath)
keyCounter := big.NewInt(1)
for _, buf := range proof {
n, err := zktrie.DecodeSMTProof(buf)
if err != nil {
log.Warn("decode proof string fail", "error", err)
} else if n != nil {
hash, err := n.NodeHash()
if err != nil {
log.Warn("node has no valid node hash", "error", err)
return
}
if lastNode == nil {
// notice: use little-endian represent inside Hash ([:] or Byte32())
path.Root = hash[:]
} else {
if bytes.Equal(hash[:], lastNode.ChildL[:]) {
path.Path = append(path.Path, SMTPathNode{
Value: hash[:],
Sibling: lastNode.ChildR[:],
})
} else if bytes.Equal(hash[:], lastNode.ChildR[:]) {
path.Path = append(path.Path, SMTPathNode{
Value: hash[:],
Sibling: lastNode.ChildL[:],
})
keyPath.Add(keyPath, keyCounter)
} else {
panic("Unexpected proof form")
}
keyCounter.Mul(keyCounter, big.NewInt(2))
}
switch n.Type {
case zktrie.NodeTypeBranch_0, zktrie.NodeTypeBranch_1, zktrie.NodeTypeBranch_2, zktrie.NodeTypeBranch_3:
lastNode = n
case zktrie.NodeTypeLeaf_New:
vhash, _ := n.ValueHash()
path.Leaf = &SMTPathNode{
//here we just return the inner represent of hash (little endian, reversed byte order to common hash)
Value: vhash[:],
Sibling: n.NodeKey[:],
}
//sanity check
keyPart := keyPath.Bytes()
for i, b := range keyPart {
ri := len(keyPart) - i
cb := path.Leaf.Sibling[ri-1] //notice the output is little-endian
if b&cb != b {
panic(fmt.Errorf("path key not match: part is %x but key is %x", keyPart, []byte(path.Leaf.Sibling[:])))
}
}
return
case zktrie.NodeTypeEmpty_New:
return
default:
panic(fmt.Errorf("unknown node type %d", n.Type))
}
}
}
panic("Unexpected finished here")
}
type zktrieProofWriter struct {
db *trie.ZktrieDatabase
tracingZktrie *trie.ZkTrie
tracingStorageTries map[common.Address]*trie.ZkTrie
tracingAccounts map[common.Address]*types.StateAccount
}
func (wr *zktrieProofWriter) TracingAccounts() map[common.Address]*types.StateAccount {
return wr.tracingAccounts
}
func NewZkTrieProofWriter(storage *types.StorageTrace) (*zktrieProofWriter, error) {
underlayerDb := rawdb.NewMemoryDatabase()
zkDb := trie.NewZktrieDatabase(underlayerDb)
accounts := make(map[common.Address]*types.StateAccount)
// resuming proof bytes to underlayerDb
for addrs, proof := range storage.Proofs {
if n := resumeProofs(proof, underlayerDb); n != nil {
addr := common.HexToAddress(addrs)
if n.Type == zktrie.NodeTypeEmpty_New {
accounts[addr] = nil
} else if acc, err := types.UnmarshalStateAccount(n.Data()); err == nil {
if bytes.Equal(n.NodeKey[:], addressToKey(addr)[:]) {
accounts[addr] = acc
} else {
// should still mark the address as being trace (data not existed yet)
accounts[addr] = nil
}
} else {
return nil, fmt.Errorf("decode account bytes fail: %s, raw data [%x]", err, n.Data())
}
} else {
return nil, fmt.Errorf("can not resume proof for address %s", addrs)
}
}
storages := make(map[common.Address]*trie.ZkTrie)
for addrs, stgLists := range storage.StorageProofs {
addr := common.HexToAddress(addrs)
accState, existed := accounts[addr]
if !existed {
// trace is malformed but currently we just warn about that
log.Warn("no account state found for this addr, mal records", "address", addrs)
continue
} else if accState == nil {
// create an empty zktrie for uninit address
storages[addr], _ = trie.NewZkTrie(common.Hash{}, zkDb)
continue
}
for keys, proof := range stgLists {
if n := resumeProofs(proof, underlayerDb); n != nil {
var err error
storages[addr], err = trie.NewZkTrie(accState.Root, zkDb)
if err != nil {
return nil, fmt.Errorf("zktrie create failure for storage in addr <%s>: %s, (root %s)", addrs, err, accState.Root)
}
} else {
return nil, fmt.Errorf("can not resume proof for storage %s@%s", keys, addrs)
}
}
}
for _, delProof := range storage.DeletionProofs {
n, err := zktrie.DecodeSMTProof(delProof)
if err != nil {
log.Warn("decode delproof string fail", "error", err, "node", delProof)
} else if n != nil {
hash, err := n.NodeHash()
if err != nil {
log.Warn("node has no valid node hash", "error", err)
} else {
//notice: must consistent with trie/merkletree.go
bt := hash[:]
underlayerDb.Put(bt, delProof)
}
}
}
zktrie, err := trie.NewZkTrie(
storage.RootBefore,
trie.NewZktrieDatabase(underlayerDb),
)
if err != nil {
return nil, fmt.Errorf("zktrie create failure: %s", err)
}
// sanity check
if !bytes.Equal(zktrie.Hash().Bytes(), storage.RootBefore.Bytes()) {
return nil, fmt.Errorf("unmatch init trie hash: expected %x but has %x", storage.RootBefore.Bytes(), zktrie.Hash().Bytes())
}
return &zktrieProofWriter{
db: zkDb,
tracingZktrie: zktrie,
tracingAccounts: accounts,
tracingStorageTries: storages,
}, nil
}
const (
posSSTOREBefore = 0
posCREATE = 0
posCREATEAfter = 1
posCALL = 2
posSTATICCALL = 0
// posSELFDESTRUCT = 2
)
func getAccountState(l *types.StructLogRes, pos int) *types.AccountWrapper {
if exData := l.ExtraData; exData == nil {
return nil
} else if len(exData.StateList) < pos {
return nil
} else {
return exData.StateList[pos]
}
}
func copyAccountState(st *types.AccountWrapper) *types.AccountWrapper {
var stg *types.StorageWrapper
if st.Storage != nil {
stg = &types.StorageWrapper{
Key: st.Storage.Key,
Value: st.Storage.Value,
}
}
return &types.AccountWrapper{
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.KeccakCodeHash.Bytes(), common.Hash{}.Bytes())
}
func getAccountDataFromLogState(state *types.AccountWrapper) *types.StateAccount {
if isDeletedAccount(state) {
return nil
}
return &types.StateAccount{
Nonce: state.Nonce,
Balance: (*big.Int)(state.Balance),
KeccakCodeHash: state.KeccakCodeHash.Bytes(),
PoseidonCodeHash: state.PoseidonCodeHash.Bytes(),
CodeSize: state.CodeSize,
// Root omitted intentionally
}
}
// for sanity check
func verifyAccount(addr common.Address, data *types.StateAccount, leaf *SMTPathNode) error {
if leaf == nil {
if data != nil {
return fmt.Errorf("path has no corresponding leaf for account")
} else {
return nil
}
}
addrKey := addressToKey(addr)
if !bytes.Equal(addrKey[:], leaf.Sibling) {
if data != nil {
return fmt.Errorf("unmatch leaf node in address: %s", addr)
}
} else if data != nil {
arr, flag := data.MarshalFields()
h, err := zkt.HandlingElemsAndByte32(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(h[:], leaf.Value) {
return fmt.Errorf("unmatch data in leaf for address %s", addr)
}
}
return nil
}
// for sanity check
func verifyStorage(key *zkt.Byte32, data *zkt.Byte32, leaf *SMTPathNode) error {
emptyData := bytes.Equal(data[:], common.Hash{}.Bytes())
if leaf == nil {
if !emptyData {
return fmt.Errorf("path has no corresponding leaf for storage")
} else {
return nil
}
}
keyHash, err := key.Hash()
if err != nil {
return err
}
if !bytes.Equal(zkt.NewHashFromBigInt(keyHash)[:], leaf.Sibling) {
if !emptyData {
return fmt.Errorf("unmatch leaf node in storage: %x", key[:])
}
} else {
h, err := data.Hash()
//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 data: %v", err)
}
if !bytes.Equal(zkt.NewHashFromBigInt(h)[:], leaf.Value) {
return fmt.Errorf("unmatch data in leaf for storage %x", key[:])
}
}
return nil
}
// update traced account state, and return the corresponding trace object which
// is still opened for more infos
// the updated accData state is obtained by a closure which enable it being derived from current status
func (w *zktrieProofWriter) traceAccountUpdate(addr common.Address, updateAccData func(*types.StateAccount) *types.StateAccount) (*StorageTrace, error) {
out := new(StorageTrace)
//account trie
out.Address = addr.Bytes()
out.AccountPath = [2]*SMTPath{{}, {}}
//fill dummy
out.AccountUpdate = [2]*StateAccount{}
accDataBefore, existed := w.tracingAccounts[addr]
if !existed {
//sanity check
panic(fmt.Errorf("code do not add initialized status for account %s", addr))
}
var proof ProofList
s_key, _ := zkt.ToSecureKeyBytes(addr.Bytes())
if err := w.tracingZktrie.Prove(s_key.Bytes(), &proof); err != nil {
return nil, fmt.Errorf("prove BEFORE state fail: %s", err)
}
decodeProofForMPTPath(proof, out.AccountPath[0])
if err := verifyAccount(addr, accDataBefore, out.AccountPath[0].Leaf); err != nil {
panic(fmt.Errorf("code fail to trace account status correctly: %s", err))
}
if accDataBefore != nil {
// 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)),
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)),
KeccakCodeHash: accData.KeccakCodeHash,
PoseidonCodeHash: accData.PoseidonCodeHash,
CodeSize: accData.CodeSize,
}
}
if accData != nil {
if err := w.tracingZktrie.TryUpdateAccount(addr.Bytes32(), accData); err != nil {
return nil, fmt.Errorf("update zktrie account state fail: %s", err)
}
w.tracingAccounts[addr] = accData
} else if accDataBefore != nil {
if err := w.tracingZktrie.TryDelete(addr.Bytes32()); err != nil {
return nil, fmt.Errorf("delete zktrie account state fail: %s", err)
}
w.tracingAccounts[addr] = nil
} // notice if both before/after is nil, we do not touch zktrie
proof = ProofList{}
if err := w.tracingZktrie.Prove(s_key.Bytes(), &proof); err != nil {
return nil, fmt.Errorf("prove AFTER state fail: %s", err)
}
decodeProofForMPTPath(proof, out.AccountPath[1])
if err := verifyAccount(addr, accData, out.AccountPath[1].Leaf); err != nil {
panic(fmt.Errorf("state AFTER has no valid account: %s", err))
}
if accData != nil {
if out.AccountKey == nil {
out.AccountKey = out.AccountPath[1].Leaf.Sibling[:]
}
//now accountKey must has been filled
}
// notice we have change that no leaf (account data) exist in either before or after,
// for that case we had to calculate the nodeKey here
if out.AccountKey == nil {
word := zkt.NewByte32FromBytesPaddingZero(addr.Bytes())
k, err := word.Hash()
if err != nil {
panic(fmt.Errorf("unexpected hash error for address: %s", err))
}
kHash := zkt.NewHashFromBigInt(k)
out.AccountKey = hexutil.Bytes(kHash[:])
}
return out, nil
}
// update traced storage state, and return the corresponding trace object
func (w *zktrieProofWriter) traceStorageUpdate(addr common.Address, key, value []byte) (*StorageTrace, error) {
trie := w.tracingStorageTries[addr]
if trie == nil {
return nil, fmt.Errorf("no trace storage trie for %s", addr)
}
statePath := [2]*SMTPath{{}, {}}
stateUpdate := [2]*StateStorage{}
storeKey := zkt.NewByte32FromBytesPaddingZero(common.BytesToHash(key).Bytes())
storeValueBefore := trie.Get(storeKey[:])
storeValue := zkt.NewByte32FromBytes(value)
valZero := zkt.Byte32{}
if storeValueBefore != nil && !bytes.Equal(storeValueBefore[:], common.Hash{}.Bytes()) {
stateUpdate[0] = &StateStorage{
Key: storeKey.Bytes(),
Value: storeValueBefore,
}
}
var storageBeforeProof, storageAfterProof ProofList
s_key, _ := zkt.ToSecureKeyBytes(storeKey.Bytes())
if err := trie.Prove(s_key.Bytes(), &storageBeforeProof); err != nil {
return nil, fmt.Errorf("prove BEFORE storage state fail: %s", err)
}
decodeProofForMPTPath(storageBeforeProof, statePath[0])
if err := verifyStorage(storeKey, zkt.NewByte32FromBytes(storeValueBefore), statePath[0].Leaf); err != nil {
panic(fmt.Errorf("storage BEFORE has no valid data: %s (%v)", err, statePath[0]))
}
if !bytes.Equal(storeValue.Bytes(), common.Hash{}.Bytes()) {
if err := trie.TryUpdate(storeKey.Bytes(), storeValue.Bytes()); err != nil {
return nil, fmt.Errorf("update zktrie storage fail: %s", err)
}
stateUpdate[1] = &StateStorage{
Key: storeKey.Bytes(),
Value: storeValue.Bytes(),
}
} else {
if err := trie.TryDelete(storeKey.Bytes()); err != nil {
return nil, fmt.Errorf("delete zktrie storage fail: %s", err)
}
}
if err := trie.Prove(s_key.Bytes(), &storageAfterProof); err != nil {
return nil, fmt.Errorf("prove AFTER storage state fail: %s", err)
}
decodeProofForMPTPath(storageAfterProof, statePath[1])
if err := verifyStorage(storeKey, storeValue, statePath[1].Leaf); err != nil {
panic(fmt.Errorf("storage AFTER has no valid data: %s (%v)", err, statePath[1]))
}
out, err := w.traceAccountUpdate(addr,
func(acc *types.StateAccount) *types.StateAccount {
if acc == nil {
// in case we read an unexist account
if !bytes.Equal(valZero.Bytes(), value) {
panic(fmt.Errorf("write to an unexist account [%s] which is not allowed", addr))
}
return nil
}
//sanity check
if accRootFromState := zkt.ReverseByteOrder(statePath[0].Root); !bytes.Equal(acc.Root[:], accRootFromState) {
panic(fmt.Errorf("unexpected storage root before: [%s] vs [%x]", acc.Root, accRootFromState))
}
return &types.StateAccount{
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 {
return nil, fmt.Errorf("update account %s in SSTORE fail: %s", addr, err)
}
if stateUpdate[1] != nil {
out.StateKey = statePath[1].Leaf.Sibling
} else if stateUpdate[0] != nil {
out.StateKey = statePath[0].Leaf.Sibling
} else {
// it occurs when we are handling SLOAD with non-exist value
// still no pretty idea, had to touch the internal behavior in zktrie ....
if h, err := storeKey.Hash(); err != nil {
return nil, fmt.Errorf("hash storekey fail: %s", err)
} else {
out.StateKey = zkt.NewHashFromBigInt(h)[:]
}
stateUpdate[1] = &StateStorage{
Key: storeKey.Bytes(),
Value: valZero.Bytes(),
}
stateUpdate[0] = stateUpdate[1]
}
out.StatePath = statePath
out.StateUpdate = stateUpdate
return out, nil
}
func (w *zktrieProofWriter) HandleNewState(accountState *types.AccountWrapper) (*StorageTrace, error) {
if accountState.Storage != nil {
storeAddr := hexutil.MustDecode(accountState.Storage.Key)
storeValue := hexutil.MustDecode(accountState.Storage.Value)
return w.traceStorageUpdate(accountState.Address, storeAddr, storeValue)
} else {
var stateRoot common.Hash
accData := getAccountDataFromLogState(accountState)
out, err := w.traceAccountUpdate(accountState.Address, func(accBefore *types.StateAccount) *types.StateAccount {
if accBefore != nil {
stateRoot = accBefore.Root
}
// we need to restore stateRoot from before
if accData != nil {
accData.Root = stateRoot
}
return accData
})
if err != nil {
return nil, fmt.Errorf("update account state %s fail: %s", accountState.Address, err)
}
hash := zkt.NewHashFromBytes(stateRoot[:])
out.CommonStateRoot = hash[:]
return out, nil
}
}
func handleLogs(od opOrderer, currentContract common.Address, logs []*types.StructLogRes) {
logStack := []int{0}
contractStack := map[int]common.Address{}
callEnterAddress := currentContract
// now trace every OP which could cause changes on state:
for i, sLog := range logs {
//trace log stack by depth rather than scanning specified op
if sl := len(logStack); sl < sLog.Depth {
logStack = append(logStack, i)
//update currentContract according to previous op
contractStack[sl] = currentContract
currentContract = callEnterAddress
} else if sl > sLog.Depth {
logStack = logStack[:sl-1]
currentContract = contractStack[sLog.Depth]
resumePos := logStack[len(logStack)-1]
calledLog := logs[resumePos]
//no need to handle fail calling
if calledLog.ExtraData != nil {
if !calledLog.ExtraData.CallFailed {
//reentry the last log which "cause" the calling, some handling may needed
switch calledLog.Op {
case "CREATE", "CREATE2":
//addr, accDataBefore := getAccountDataFromProof(calledLog, posCALLBefore)
od.absorb(getAccountState(calledLog, posCREATEAfter))
}
} else {
od.readonly(false)
}
}
} else {
logStack[sl-1] = i
}
//sanity check
if len(logStack) != sLog.Depth {
panic("tracking log stack failure")
}
callEnterAddress = currentContract
//check extra status for current op if it is a call
if extraData := sLog.ExtraData; extraData != nil {
if extraData.CallFailed || len(sLog.ExtraData.Caller) < 2 {
// no enough caller data (2) is being capture indicate we are in an immediate failure
// i.e. it fail before stack entry (like no enough balance for a "call with value"),
// or we just not handle this calling op correctly yet
// for a failed option, now we just purpose nothing happens (FIXME: it is inconsentent with mpt_table)
// except for CREATE, for which the callee's nonce would be increased
switch sLog.Op {
case "CREATE", "CREATE2":
st := copyAccountState(extraData.Caller[0])
st.Nonce += 1
od.absorb(st)
}
}
if extraData.CallFailed {
od.readonly(true)
}
// now trace caller's status first
if caller := extraData.Caller; len(caller) >= 2 {
od.absorb(caller[1])
}
}
switch sLog.Op {
case "SELFDESTRUCT":
// NOTE: this op code has been disabled so we treat it as nothing now
//in SELFDESTRUCT, a call on target address is made so the balance would be updated
//in the last item
//stateTarget := getAccountState(sLog, posSELFDESTRUCT)
//od.absorb(stateTarget)
//then build an "deleted state", only address and other are default
//od.absorb(&types.AccountWrapper{Address: currentContract})
case "CREATE", "CREATE2":
// notice in immediate failure we have no enough tracing in extraData
if len(sLog.ExtraData.StateList) >= 2 {
state := getAccountState(sLog, posCREATE)
od.absorb(state)
//update contract to CREATE addr
callEnterAddress = state.Address
}
case "CALL", "CALLCODE":
// notice in immediate failure we have no enough tracing in extraData
if len(sLog.ExtraData.StateList) >= 3 {
state := getAccountState(sLog, posCALL)
od.absorb(state)
callEnterAddress = state.Address
}
case "STATICCALL":
//static call has no update on target address (and no immediate failure?)
callEnterAddress = getAccountState(sLog, posSTATICCALL).Address
case "DELEGATECALL":
case "SLOAD":
accountState := getAccountState(sLog, posSSTOREBefore)
od.absorbStorage(accountState, nil)
case "SSTORE":
log.Debug("build SSTORE", "pc", sLog.Pc, "key", sLog.Stack[len(sLog.Stack)-1])
accountState := copyAccountState(getAccountState(sLog, posSSTOREBefore))
// notice the log only provide the value BEFORE store and it is not suitable for our protocol,
// here we change it into value AFTER update
before := accountState.Storage
accountState.Storage = &types.StorageWrapper{
Key: sLog.Stack[len(sLog.Stack)-1],
Value: sLog.Stack[len(sLog.Stack)-2],
}
od.absorbStorage(accountState, before)
default:
}
}
}
func HandleTx(od opOrderer, txResult *types.ExecutionResult) {
// the from state is read before tx is handled and nonce is added, we combine both
preTxSt := copyAccountState(txResult.From)
preTxSt.Nonce += 1
od.absorb(preTxSt)
if txResult.Failed {
od.readonly(true)
}
var toAddr common.Address
if state := txResult.AccountCreated; state != nil {
od.absorb(state)
toAddr = state.Address
} else {
toAddr = txResult.To.Address
}
handleLogs(od, toAddr, txResult.StructLogs)
if txResult.Failed {
od.readonly(false)
}
for _, state := range txResult.AccountsAfter {
// special case: for suicide, the state has been captured in SELFDESTRUCT
// and we skip it here
if isDeletedAccount(state) {
log.Debug("skip suicide address", "address", state.Address)
continue
}
od.absorb(state)
}
}
const defaultOrdererScheme = MPTWitnessRWTbl
var usedOrdererScheme = defaultOrdererScheme
func SetOrderScheme(t MPTWitnessType) { usedOrdererScheme = t }
// HandleBlockTrace only for backward compatibility
func HandleBlockTrace(block *types.BlockTrace) ([]*StorageTrace, error) {
return HandleBlockTraceEx(block, usedOrdererScheme)
}
func HandleBlockTraceEx(block *types.BlockTrace, ordererScheme MPTWitnessType) ([]*StorageTrace, error) {
writer, err := NewZkTrieProofWriter(block.StorageTrace)
if err != nil {
return nil, err
}
var od opOrderer
switch ordererScheme {
case MPTWitnessNothing:
panic("should not come here when scheme is 0")
case MPTWitnessNatural:
od = &simpleOrderer{}
case MPTWitnessRWTbl:
od = NewRWTblOrderer(writer.tracingAccounts)
default:
return nil, fmt.Errorf("unrecognized scheme %d", ordererScheme)
}
for _, tx := range block.ExecutionResults {
HandleTx(od, tx)
}
// notice some coinbase addr (like all zero) is in fact not exist and should not be update
// TODO: not a good solution, just for patch ...
if coinbaseData := writer.tracingAccounts[block.Coinbase.Address]; coinbaseData != nil {
od.absorb(block.Coinbase)
}
opDisp := od.end_absorb()
var outTrace []*StorageTrace
for op := opDisp.next(); op != nil; op = opDisp.next() {
trace, err := writer.HandleNewState(op)
if err != nil {
return nil, err
}
outTrace = append(outTrace, trace)
}
finalHash := writer.tracingZktrie.Hash()
if !bytes.Equal(finalHash.Bytes(), block.StorageTrace.RootAfter.Bytes()) {
return outTrace, fmt.Errorf("unmatch hash: [%x] vs [%x]", finalHash.Bytes(), block.StorageTrace.RootAfter.Bytes())
}
return outTrace, nil
}
func FillBlockTraceForMPTWitness(order MPTWitnessType, block *types.BlockTrace) error {
if order == MPTWitnessNothing {
return nil
}
trace, err := HandleBlockTraceEx(block, order)
if err != nil {
return err
}
msg, err := json.Marshal(trace)
if err != nil {
return err
}
rawmsg := json.RawMessage(msg)
block.MPTWitness = &rawmsg
return nil
}

View file

@ -0,0 +1,183 @@
package trie
import (
"bytes"
"fmt"
zktrie "github.com/scroll-tech/zktrie/trie"
zkt "github.com/scroll-tech/zktrie/types"
"github.com/ethereum/go-ethereum/ethdb"
)
// Pick Node from its hash directly from database, notice it has different
// interface with the function of same name in `trie`
func (t *ZkTrie) TryGetNode(nodeHash *zkt.Hash) (*zktrie.Node, error) {
if bytes.Equal(nodeHash[:], zkt.HashZero[:]) {
return zktrie.NewEmptyNode(), nil
}
nBytes, err := t.db.Get(nodeHash[:])
if err == zktrie.ErrKeyNotFound {
return nil, zktrie.ErrKeyNotFound
} else if err != nil {
return nil, err
}
return zktrie.NewNodeFromBytes(nBytes)
}
type ProofTracer struct {
*ZkTrie
deletionTracer map[zkt.Hash]struct{}
rawPaths map[string][]*zktrie.Node
emptyTermPaths map[string][]*zktrie.Node
}
// NewProofTracer create a proof tracer object
func (t *ZkTrie) NewProofTracer() *ProofTracer {
return &ProofTracer{
ZkTrie: t,
// always consider 0 is "deleted"
deletionTracer: map[zkt.Hash]struct{}{zkt.HashZero: {}},
rawPaths: make(map[string][]*zktrie.Node),
emptyTermPaths: make(map[string][]*zktrie.Node),
}
}
// Merge merge the input tracer into current and return current tracer
func (t *ProofTracer) Merge(another *ProofTracer) *ProofTracer {
// sanity checking
if !bytes.Equal(t.Hash().Bytes(), another.Hash().Bytes()) {
panic("can not merge two proof tracer base on different trie")
}
for k := range another.deletionTracer {
t.deletionTracer[k] = struct{}{}
}
for k, v := range another.rawPaths {
t.rawPaths[k] = v
}
for k, v := range another.emptyTermPaths {
t.emptyTermPaths[k] = v
}
return t
}
// GetDeletionProofs generate current deletionTracer and collect deletion proofs
// which is possible to be used from all rawPaths, which enabling witness generator
// to predict the final state root after executing any deletion
// along any of the rawpath, no matter of the deletion occurs in any position of the mpt ops
// Note the collected sibling node has no key along with it since witness generator would
// always decode the node for its purpose
func (t *ProofTracer) GetDeletionProofs() ([][]byte, error) {
retMap := map[zkt.Hash][]byte{}
// check each path: reversively, skip the final leaf node
for _, path := range t.rawPaths {
checkPath := path[:len(path)-1]
for i := len(checkPath); i > 0; i-- {
n := checkPath[i-1]
_, deletedL := t.deletionTracer[*n.ChildL]
_, deletedR := t.deletionTracer[*n.ChildR]
if deletedL && deletedR {
nodeHash, _ := n.NodeHash()
t.deletionTracer[*nodeHash] = struct{}{}
} else {
var siblingHash *zkt.Hash
if deletedL {
siblingHash = n.ChildR
} else if deletedR {
siblingHash = n.ChildL
}
if siblingHash != nil {
sibling, err := t.TryGetNode(siblingHash)
if err != nil {
return nil, err
}
if sibling.Type != zktrie.NodeTypeEmpty_New {
retMap[*siblingHash] = sibling.Value()
}
}
break
}
}
}
var ret [][]byte
for _, bt := range retMap {
ret = append(ret, bt)
}
return ret, nil
}
// MarkDeletion mark a key has been involved into deletion
func (t *ProofTracer) MarkDeletion(key []byte) {
if path, existed := t.emptyTermPaths[string(key)]; existed {
// copy empty node terminated path for final scanning
t.rawPaths[string(key)] = path
} else if path, existed = t.rawPaths[string(key)]; existed {
// sanity check
leafNode := path[len(path)-1]
if leafNode.Type != zktrie.NodeTypeLeaf_New {
panic("all path recorded in proofTrace should be ended with leafNode")
}
nodeHash, _ := leafNode.NodeHash()
t.deletionTracer[*nodeHash] = struct{}{}
}
}
// Prove act the same as zktrie.Prove, while also collect the raw path
// for collecting deletion proofs in a post-work
func (t *ProofTracer) Prove(key []byte, fromLevel uint, proofDb ethdb.KeyValueWriter) error {
var mptPath []*zktrie.Node
err := t.ZkTrie.ProveWithDeletion(key, fromLevel,
func(n *zktrie.Node) error {
nodeHash, err := n.NodeHash()
if err != nil {
return err
}
switch n.Type {
case zktrie.NodeTypeLeaf_New:
preImage := t.GetKey(n.NodeKey.Bytes())
if len(preImage) > 0 {
n.KeyPreimage = &zkt.Byte32{}
copy(n.KeyPreimage[:], preImage)
}
case zktrie.NodeTypeBranch_0, zktrie.NodeTypeBranch_1,
zktrie.NodeTypeBranch_2, zktrie.NodeTypeBranch_3:
mptPath = append(mptPath, n)
case zktrie.NodeTypeEmpty_New:
// empty node is considered as "unhit" but it should be also being added
// into a temporary slot for possibly being marked as deletion later
mptPath = append(mptPath, n)
t.emptyTermPaths[string(key)] = mptPath
default:
panic(fmt.Errorf("unexpected node type %d", n.Type))
}
return proofDb.Put(nodeHash[:], n.Value())
},
func(n *zktrie.Node, _ *zktrie.Node) {
// only "hit" path (i.e. the leaf node corresponding the input key can be found)
// would be add into tracer
mptPath = append(mptPath, n)
t.rawPaths[string(key)] = mptPath
},
)
if err != nil {
return err
}
// we put this special kv pair in db so we can distinguish the type and
// make suitable Proof
return proofDb.Put(magicHash, zktrie.ProofMagicBytes())
}