diff --git a/XDCx/tradingstate/XDCx_trie_test.go b/XDCx/tradingstate/XDCx_trie_test.go index ab880f5d6def..2063743cf22e 100644 --- a/XDCx/tradingstate/XDCx_trie_test.go +++ b/XDCx/tradingstate/XDCx_trie_test.go @@ -16,7 +16,7 @@ func TestXDCxTrieTest(t *testing.T) { t.SkipNow() db := rawdb.NewMemoryDatabase() stateCache := NewDatabase(db) - trie, _ := stateCache.OpenStorageTrie(EmptyHash, types.EmptyRootHash) + trie, _ := stateCache.OpenStorageTrie(EmptyHash, common.Address{}, types.EmptyRootHash) max := 1000000 for i := 1; i < max; i++ { k := common.BigToHash(big.NewInt(int64(i))).Bytes() diff --git a/XDCx/tradingstate/database.go b/XDCx/tradingstate/database.go index 53e872732e33..4fe29d34ebb6 100644 --- a/XDCx/tradingstate/database.go +++ b/XDCx/tradingstate/database.go @@ -33,16 +33,16 @@ type Database interface { OpenTrie(root common.Hash) (Trie, error) // OpenStorageTrie opens the storage trie of an account. - OpenStorageTrie(addrHash, root common.Hash) (Trie, error) + OpenStorageTrie(stateRoot common.Hash, address common.Address, root common.Hash) (Trie, error) // CopyTrie returns an independent copy of the given trie. CopyTrie(Trie) Trie // ContractCode retrieves a particular contract's code. - ContractCode(addrHash, codeHash common.Hash) ([]byte, error) + ContractCode(address common.Address, codeHash common.Hash) ([]byte, error) // ContractCodeSize retrieves a particular contracts code's size. - ContractCodeSize(addrHash, codeHash common.Hash) (int, error) + ContractCodeSize(address common.Address, codeHash common.Hash) (int, error) // TrieDB retrieves the low level trie database used for data storage. TrieDB() *trie.Database @@ -83,7 +83,7 @@ func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) { } // OpenStorageTrie opens the storage trie of an account. -func (db *cachingDB) OpenStorageTrie(addrHash, root common.Hash) (Trie, error) { +func (db *cachingDB) OpenStorageTrie(stateRoot common.Hash, address common.Address, root common.Hash) (Trie, error) { return NewXDCXTrie(root, db.db) } @@ -98,12 +98,12 @@ func (db *cachingDB) CopyTrie(t Trie) Trie { } // ContractCode retrieves a particular contract's code. -func (db *cachingDB) ContractCode(addrHash, codeHash common.Hash) ([]byte, error) { +func (db *cachingDB) ContractCode(address common.Address, codeHash common.Hash) ([]byte, error) { return nil, nil } // ContractCodeSize retrieves a particular contracts code's size. -func (db *cachingDB) ContractCodeSize(addrHash, codeHash common.Hash) (int, error) { +func (db *cachingDB) ContractCodeSize(address common.Address, codeHash common.Hash) (int, error) { return 0, nil } diff --git a/XDCx/tradingstate/state_lendingbook.go b/XDCx/tradingstate/state_lendingbook.go index 4285a7e6024a..ef8efaca9039 100644 --- a/XDCx/tradingstate/state_lendingbook.go +++ b/XDCx/tradingstate/state_lendingbook.go @@ -79,9 +79,9 @@ func (s *stateLendingBook) setError(err error) { func (s *stateLendingBook) getTrie(db Database) Trie { if s.trie == nil { var err error - s.trie, err = db.OpenStorageTrie(s.lendingBook, s.data.Root) + s.trie, err = db.OpenStorageTrie(s.lendingBook, common.Address{}, s.data.Root) if err != nil { - s.trie, _ = db.OpenStorageTrie(s.price, types.EmptyRootHash) + s.trie, _ = db.OpenStorageTrie(s.price, common.Address{}, types.EmptyRootHash) s.setError(fmt.Errorf("can't create storage trie: %v", err)) } } diff --git a/XDCx/tradingstate/state_liquidationprice.go b/XDCx/tradingstate/state_liquidationprice.go index accdb2465d91..0178fa8d375b 100644 --- a/XDCx/tradingstate/state_liquidationprice.go +++ b/XDCx/tradingstate/state_liquidationprice.go @@ -102,9 +102,9 @@ func (s *liquidationPriceState) createLendingBook(db Database, lendingBook commo func (s *liquidationPriceState) getTrie(db Database) Trie { if s.trie == nil { var err error - s.trie, err = db.OpenStorageTrie(s.liquidationPrice, s.data.Root) + s.trie, err = db.OpenStorageTrie(s.liquidationPrice, common.Address{}, s.data.Root) if err != nil { - s.trie, _ = db.OpenStorageTrie(s.liquidationPrice, types.EmptyRootHash) + s.trie, _ = db.OpenStorageTrie(s.liquidationPrice, common.Address{}, types.EmptyRootHash) s.setError(fmt.Errorf("can't create storage trie: %v", err)) } } diff --git a/XDCx/tradingstate/state_orderList.go b/XDCx/tradingstate/state_orderList.go index fc4486ff6f00..b5d3dcb60e04 100644 --- a/XDCx/tradingstate/state_orderList.go +++ b/XDCx/tradingstate/state_orderList.go @@ -90,9 +90,9 @@ func (s *stateOrderList) setError(err error) { func (s *stateOrderList) getTrie(db Database) Trie { if s.trie == nil { var err error - s.trie, err = db.OpenStorageTrie(s.price, s.data.Root) + s.trie, err = db.OpenStorageTrie(s.price, common.Address{}, s.data.Root) if err != nil { - s.trie, _ = db.OpenStorageTrie(s.price, types.EmptyRootHash) + s.trie, _ = db.OpenStorageTrie(s.price, common.Address{}, types.EmptyRootHash) s.setError(fmt.Errorf("can't create storage trie: %v", err)) } } diff --git a/XDCx/tradingstate/state_orderbook.go b/XDCx/tradingstate/state_orderbook.go index 032a550d9067..21ea848c766e 100644 --- a/XDCx/tradingstate/state_orderbook.go +++ b/XDCx/tradingstate/state_orderbook.go @@ -134,9 +134,9 @@ func (te *tradingExchanges) setError(err error) { func (te *tradingExchanges) getAsksTrie(db Database) Trie { if te.asksTrie == nil { var err error - te.asksTrie, err = db.OpenStorageTrie(te.orderBookHash, te.data.AskRoot) + te.asksTrie, err = db.OpenStorageTrie(te.orderBookHash, common.Address{}, te.data.AskRoot) if err != nil { - te.asksTrie, _ = db.OpenStorageTrie(te.orderBookHash, types.EmptyRootHash) + te.asksTrie, _ = db.OpenStorageTrie(te.orderBookHash, common.Address{}, types.EmptyRootHash) te.setError(fmt.Errorf("can't create asks trie: %v", err)) } } @@ -146,9 +146,9 @@ func (te *tradingExchanges) getAsksTrie(db Database) Trie { func (te *tradingExchanges) getOrdersTrie(db Database) Trie { if te.ordersTrie == nil { var err error - te.ordersTrie, err = db.OpenStorageTrie(te.orderBookHash, te.data.OrderRoot) + te.ordersTrie, err = db.OpenStorageTrie(te.orderBookHash, common.Address{}, te.data.OrderRoot) if err != nil { - te.ordersTrie, _ = db.OpenStorageTrie(te.orderBookHash, types.EmptyRootHash) + te.ordersTrie, _ = db.OpenStorageTrie(te.orderBookHash, common.Address{}, types.EmptyRootHash) te.setError(fmt.Errorf("can't create asks trie: %v", err)) } } @@ -264,9 +264,9 @@ func (te *tradingExchanges) CommitAsksTrie(db Database) error { func (te *tradingExchanges) getBidsTrie(db Database) Trie { if te.bidsTrie == nil { var err error - te.bidsTrie, err = db.OpenStorageTrie(te.orderBookHash, te.data.BidRoot) + te.bidsTrie, err = db.OpenStorageTrie(te.orderBookHash, common.Address{}, te.data.BidRoot) if err != nil { - te.bidsTrie, _ = db.OpenStorageTrie(te.orderBookHash, types.EmptyRootHash) + te.bidsTrie, _ = db.OpenStorageTrie(te.orderBookHash, common.Address{}, types.EmptyRootHash) te.setError(fmt.Errorf("can't create bids trie: %v", err)) } } @@ -635,9 +635,9 @@ func (te *tradingExchanges) createStateLiquidationPrice(db Database, liquidation func (te *tradingExchanges) getLiquidationPriceTrie(db Database) Trie { if te.liquidationPriceTrie == nil { var err error - te.liquidationPriceTrie, err = db.OpenStorageTrie(te.orderBookHash, te.data.LiquidationPriceRoot) + te.liquidationPriceTrie, err = db.OpenStorageTrie(te.orderBookHash, common.Address{}, te.data.LiquidationPriceRoot) if err != nil { - te.liquidationPriceTrie, _ = db.OpenStorageTrie(te.orderBookHash, types.EmptyRootHash) + te.liquidationPriceTrie, _ = db.OpenStorageTrie(te.orderBookHash, common.Address{}, types.EmptyRootHash) te.setError(fmt.Errorf("can't create liquidation liquidationPrice trie: %v", err)) } } diff --git a/XDCxlending/lendingstate/database.go b/XDCxlending/lendingstate/database.go index 5f63ddf992fb..1e373a543604 100644 --- a/XDCxlending/lendingstate/database.go +++ b/XDCxlending/lendingstate/database.go @@ -33,16 +33,16 @@ type Database interface { OpenTrie(root common.Hash) (Trie, error) // OpenStorageTrie opens the storage trie of an account. - OpenStorageTrie(addrHash, root common.Hash) (Trie, error) + OpenStorageTrie(stateRoot common.Hash, address common.Address, root common.Hash) (Trie, error) // CopyTrie returns an independent copy of the given trie. CopyTrie(Trie) Trie // ContractCode retrieves a particular contract's code. - ContractCode(addrHash, codeHash common.Hash) ([]byte, error) + ContractCode(address common.Address, codeHash common.Hash) ([]byte, error) // ContractCodeSize retrieves a particular contracts code's size. - ContractCodeSize(addrHash, codeHash common.Hash) (int, error) + ContractCodeSize(address common.Address, codeHash common.Hash) (int, error) // TrieDB retrieves the low level trie database used for data storage. TrieDB() *trie.Database @@ -83,7 +83,7 @@ func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) { } // OpenStorageTrie opens the storage trie of an account. -func (db *cachingDB) OpenStorageTrie(addrHash, root common.Hash) (Trie, error) { +func (db *cachingDB) OpenStorageTrie(stateRoot common.Hash, address common.Address, root common.Hash) (Trie, error) { return NewXDCXTrie(root, db.db) } @@ -98,12 +98,12 @@ func (db *cachingDB) CopyTrie(t Trie) Trie { } // ContractCode retrieves a particular contract's code. -func (db *cachingDB) ContractCode(addrHash, codeHash common.Hash) ([]byte, error) { +func (db *cachingDB) ContractCode(address common.Address, codeHash common.Hash) ([]byte, error) { return nil, nil } // ContractCodeSize retrieves a particular contracts code's size. -func (db *cachingDB) ContractCodeSize(addrHash, codeHash common.Hash) (int, error) { +func (db *cachingDB) ContractCodeSize(address common.Address, codeHash common.Hash) (int, error) { return 0, nil } diff --git a/XDCxlending/lendingstate/state_itemList.go b/XDCxlending/lendingstate/state_itemList.go index 7ff64a2ace08..469b27bd5cf9 100644 --- a/XDCxlending/lendingstate/state_itemList.go +++ b/XDCxlending/lendingstate/state_itemList.go @@ -78,9 +78,9 @@ func (il *itemListState) setError(err error) { func (il *itemListState) getTrie(db Database) Trie { if il.trie == nil { var err error - il.trie, err = db.OpenStorageTrie(il.key, il.data.Root) + il.trie, err = db.OpenStorageTrie(il.key, common.Address{}, il.data.Root) if err != nil { - il.trie, _ = db.OpenStorageTrie(il.key, types.EmptyRootHash) + il.trie, _ = db.OpenStorageTrie(il.key, common.Address{}, types.EmptyRootHash) il.setError(fmt.Errorf("can't create storage trie: %v", err)) } } diff --git a/XDCxlending/lendingstate/state_lendingbook.go b/XDCxlending/lendingstate/state_lendingbook.go index 1c81d0b5ac65..770dfc222797 100644 --- a/XDCxlending/lendingstate/state_lendingbook.go +++ b/XDCxlending/lendingstate/state_lendingbook.go @@ -127,9 +127,9 @@ func (s *lendingExchangeState) setError(err error) { func (s *lendingExchangeState) getLendingItemTrie(db Database) Trie { if s.lendingItemTrie == nil { var err error - s.lendingItemTrie, err = db.OpenStorageTrie(s.lendingBook, s.data.LendingItemRoot) + s.lendingItemTrie, err = db.OpenStorageTrie(s.lendingBook, common.Address{}, s.data.LendingItemRoot) if err != nil { - s.lendingItemTrie, _ = db.OpenStorageTrie(s.lendingBook, types.EmptyRootHash) + s.lendingItemTrie, _ = db.OpenStorageTrie(s.lendingBook, common.Address{}, types.EmptyRootHash) s.setError(fmt.Errorf("can't create Lendings trie: %v", err)) } } @@ -139,9 +139,9 @@ func (s *lendingExchangeState) getLendingItemTrie(db Database) Trie { func (s *lendingExchangeState) getLendingTradeTrie(db Database) Trie { if s.lendingTradeTrie == nil { var err error - s.lendingTradeTrie, err = db.OpenStorageTrie(s.lendingBook, s.data.LendingTradeRoot) + s.lendingTradeTrie, err = db.OpenStorageTrie(s.lendingBook, common.Address{}, s.data.LendingTradeRoot) if err != nil { - s.lendingTradeTrie, _ = db.OpenStorageTrie(s.lendingBook, types.EmptyRootHash) + s.lendingTradeTrie, _ = db.OpenStorageTrie(s.lendingBook, common.Address{}, types.EmptyRootHash) s.setError(fmt.Errorf("can't create Lendings trie: %v", err)) } } @@ -151,9 +151,9 @@ func (s *lendingExchangeState) getLendingTradeTrie(db Database) Trie { func (s *lendingExchangeState) getInvestingTrie(db Database) Trie { if s.investingTrie == nil { var err error - s.investingTrie, err = db.OpenStorageTrie(s.lendingBook, s.data.InvestingRoot) + s.investingTrie, err = db.OpenStorageTrie(s.lendingBook, common.Address{}, s.data.InvestingRoot) if err != nil { - s.investingTrie, _ = db.OpenStorageTrie(s.lendingBook, types.EmptyRootHash) + s.investingTrie, _ = db.OpenStorageTrie(s.lendingBook, common.Address{}, types.EmptyRootHash) s.setError(fmt.Errorf("can't create Lendings trie: %v", err)) } } @@ -163,9 +163,9 @@ func (s *lendingExchangeState) getInvestingTrie(db Database) Trie { func (s *lendingExchangeState) getBorrowingTrie(db Database) Trie { if s.borrowingTrie == nil { var err error - s.borrowingTrie, err = db.OpenStorageTrie(s.lendingBook, s.data.BorrowingRoot) + s.borrowingTrie, err = db.OpenStorageTrie(s.lendingBook, common.Address{}, s.data.BorrowingRoot) if err != nil { - s.borrowingTrie, _ = db.OpenStorageTrie(s.lendingBook, types.EmptyRootHash) + s.borrowingTrie, _ = db.OpenStorageTrie(s.lendingBook, common.Address{}, types.EmptyRootHash) s.setError(fmt.Errorf("can't create bids trie: %v", err)) } } @@ -175,9 +175,9 @@ func (s *lendingExchangeState) getBorrowingTrie(db Database) Trie { func (s *lendingExchangeState) getLiquidationTimeTrie(db Database) Trie { if s.liquidationTimeTrie == nil { var err error - s.liquidationTimeTrie, err = db.OpenStorageTrie(s.lendingBook, s.data.LiquidationTimeRoot) + s.liquidationTimeTrie, err = db.OpenStorageTrie(s.lendingBook, common.Address{}, s.data.LiquidationTimeRoot) if err != nil { - s.liquidationTimeTrie, _ = db.OpenStorageTrie(s.lendingBook, types.EmptyRootHash) + s.liquidationTimeTrie, _ = db.OpenStorageTrie(s.lendingBook, common.Address{}, types.EmptyRootHash) s.setError(fmt.Errorf("can't create bids trie: %v", err)) } } diff --git a/XDCxlending/lendingstate/state_liquidationtime.go b/XDCxlending/lendingstate/state_liquidationtime.go index 125cab2ddf07..b7dab1842088 100644 --- a/XDCxlending/lendingstate/state_liquidationtime.go +++ b/XDCxlending/lendingstate/state_liquidationtime.go @@ -77,9 +77,9 @@ func (lt *liquidationTimeState) setError(err error) { func (lt *liquidationTimeState) getTrie(db Database) Trie { if lt.trie == nil { var err error - lt.trie, err = db.OpenStorageTrie(lt.lendingBook, lt.data.Root) + lt.trie, err = db.OpenStorageTrie(lt.lendingBook, common.Address{}, lt.data.Root) if err != nil { - lt.trie, _ = db.OpenStorageTrie(lt.time, types.EmptyRootHash) + lt.trie, _ = db.OpenStorageTrie(lt.lendingBook, common.Address{}, types.EmptyRootHash) lt.setError(fmt.Errorf("can't create storage trie: %v", err)) } } diff --git a/core/blockchain_reader.go b/core/blockchain_reader.go index 7e92a1f50baf..2554d4d295a3 100644 --- a/core/blockchain_reader.go +++ b/core/blockchain_reader.go @@ -265,7 +265,7 @@ func (bc *BlockChain) TrieNode(hash common.Hash) ([]byte, error) { // ContractCode retrieves a blob of data associated with a contract hash // either from ephemeral in-memory cache, or from persistent storage. func (bc *BlockChain) ContractCode(hash common.Hash) ([]byte, error) { - return bc.stateCache.ContractCode(common.Hash{}, hash) + return bc.stateCache.ContractCode(common.Address{}, hash) } // ContractCodeWithPrefix retrieves a blob of data associated with a contract @@ -275,9 +275,11 @@ func (bc *BlockChain) ContractCode(hash common.Hash) ([]byte, error) { // new code scheme. func (bc *BlockChain) ContractCodeWithPrefix(hash common.Hash) ([]byte, error) { type codeReader interface { - ContractCodeWithPrefix(addrHash, codeHash common.Hash) ([]byte, error) + ContractCodeWithPrefix(address common.Address, codeHash common.Hash) ([]byte, error) } - return bc.stateCache.(codeReader).ContractCodeWithPrefix(common.Hash{}, hash) + // TODO(rjl493456442) The associated account address is also required + // in Verkle scheme. Fix it once snap-sync is supported for Verkle. + return bc.stateCache.(codeReader).ContractCodeWithPrefix(common.Address{}, hash) } // State returns a new mutable state based on the current HEAD block. diff --git a/core/rawdb/database.go b/core/rawdb/database.go index a2c8f8efee7c..040ceea23bc6 100644 --- a/core/rawdb/database.go +++ b/core/rawdb/database.go @@ -163,7 +163,7 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error { receiptSize += size case bytes.HasPrefix(key, txLookupPrefix) && len(key) == (len(txLookupPrefix)+common.HashLength): txlookupSize += size - case bytes.HasPrefix(key, preimagePrefix) && len(key) == (len(preimagePrefix)+common.HashLength): + case bytes.HasPrefix(key, PreimagePrefix) && len(key) == (len(PreimagePrefix)+common.HashLength): preimageSize += size case bytes.HasPrefix(key, bloomBitsPrefix) && len(key) == (len(bloomBitsPrefix)+10+common.HashLength): bloomBitsSize += size diff --git a/core/rawdb/schema.go b/core/rawdb/schema.go index d9738d8dbba4..5295a47ded04 100644 --- a/core/rawdb/schema.go +++ b/core/rawdb/schema.go @@ -69,7 +69,7 @@ var ( trieNodeAccountPrefix = []byte("A") // trieNodeAccountPrefix + hexPath -> trie node trieNodeStoragePrefix = []byte("O") // trieNodeStoragePrefix + accountHash + hexPath -> trie node - preimagePrefix = []byte("secure-key-") // preimagePrefix + hash -> preimage + PreimagePrefix = []byte("secure-key-") // PreimagePrefix + hash -> preimage configPrefix = []byte("ethereum-config-") // config prefix for the db genesisPrefix = []byte("ethereum-genesis-") // genesis state prefix for the db @@ -173,9 +173,9 @@ func bloomBitsKey(bit uint, section uint64, hash common.Hash) []byte { return key } -// preimageKey = preimagePrefix + hash +// preimageKey = PreimagePrefix + hash func preimageKey(hash common.Hash) []byte { - return append(preimagePrefix, hash.Bytes()...) + return append(PreimagePrefix, hash.Bytes()...) } // codeKey = codePrefix + hash diff --git a/core/state/database.go b/core/state/database.go index 446dfab22bcf..b07bc8cb2af3 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -24,6 +24,7 @@ import ( "github.com/XinFinOrg/XDPoSChain/common/lru" "github.com/XinFinOrg/XDPoSChain/core/rawdb" "github.com/XinFinOrg/XDPoSChain/core/types" + "github.com/XinFinOrg/XDPoSChain/crypto" "github.com/XinFinOrg/XDPoSChain/ethdb" "github.com/XinFinOrg/XDPoSChain/trie" "github.com/XinFinOrg/XDPoSChain/trie/trienode" @@ -43,16 +44,16 @@ type Database interface { OpenTrie(root common.Hash) (Trie, error) // OpenStorageTrie opens the storage trie of an account. - OpenStorageTrie(stateRoot common.Hash, addrHash, root common.Hash) (Trie, error) + OpenStorageTrie(stateRoot common.Hash, address common.Address, root common.Hash) (Trie, error) // CopyTrie returns an independent copy of the given trie. CopyTrie(Trie) Trie // ContractCode retrieves a particular contract's code. - ContractCode(addrHash, codeHash common.Hash) ([]byte, error) + ContractCode(address common.Address, codeHash common.Hash) ([]byte, error) // ContractCodeSize retrieves a particular contracts code's size. - ContractCodeSize(addrHash, codeHash common.Hash) (int, error) + ContractCodeSize(address common.Address, codeHash common.Hash) (int, error) // DiskDB returns the underlying key-value disk database. DiskDB() ethdb.KeyValueStore @@ -183,8 +184,8 @@ func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) { } // OpenStorageTrie opens the storage trie of an account. -func (db *cachingDB) OpenStorageTrie(stateRoot common.Hash, addrHash, root common.Hash) (Trie, error) { - tr, err := trie.NewStateTrie(trie.StorageTrieID(stateRoot, addrHash, root), db.triedb) +func (db *cachingDB) OpenStorageTrie(stateRoot common.Hash, address common.Address, root common.Hash) (Trie, error) { + tr, err := trie.NewStateTrie(trie.StorageTrieID(stateRoot, crypto.Keccak256Hash(address.Bytes()), root), db.triedb) if err != nil { return nil, err } @@ -202,11 +203,12 @@ func (db *cachingDB) CopyTrie(t Trie) Trie { } // ContractCode retrieves a particular contract's code. -func (db *cachingDB) ContractCode(addrHash, codeHash common.Hash) ([]byte, error) { - if code, _ := db.codeCache.Get(codeHash); len(code) > 0 { +func (db *cachingDB) ContractCode(address common.Address, codeHash common.Hash) ([]byte, error) { + code, _ := db.codeCache.Get(codeHash) + if len(code) > 0 { return code, nil } - code := rawdb.ReadCode(db.disk, codeHash) + code = rawdb.ReadCode(db.disk, codeHash) if len(code) > 0 { db.codeCache.Add(codeHash, code) db.codeSizeCache.Add(codeHash, len(code)) @@ -218,11 +220,12 @@ func (db *cachingDB) ContractCode(addrHash, codeHash common.Hash) ([]byte, error // ContractCodeWithPrefix retrieves a particular contract's code. If the // code can't be found in the cache, then check the existence with **new** // db scheme. -func (db *cachingDB) ContractCodeWithPrefix(addrHash, codeHash common.Hash) ([]byte, error) { - if code, _ := db.codeCache.Get(codeHash); len(code) > 0 { +func (db *cachingDB) ContractCodeWithPrefix(address common.Address, codeHash common.Hash) ([]byte, error) { + code, _ := db.codeCache.Get(codeHash) + if len(code) > 0 { return code, nil } - code := rawdb.ReadCodeWithPrefix(db.disk, codeHash) + code = rawdb.ReadCodeWithPrefix(db.disk, codeHash) if len(code) > 0 { db.codeCache.Add(codeHash, code) db.codeSizeCache.Add(codeHash, len(code)) @@ -232,11 +235,11 @@ func (db *cachingDB) ContractCodeWithPrefix(addrHash, codeHash common.Hash) ([]b } // ContractCodeSize retrieves a particular contracts code's size. -func (db *cachingDB) ContractCodeSize(addrHash, codeHash common.Hash) (int, error) { +func (db *cachingDB) ContractCodeSize(addr common.Address, codeHash common.Hash) (int, error) { if cached, ok := db.codeSizeCache.Get(codeHash); ok { return cached, nil } - code, err := db.ContractCode(addrHash, codeHash) + code, err := db.ContractCode(addr, codeHash) return len(code), err } diff --git a/core/state/iterator.go b/core/state/iterator.go index 66264061272b..de517d69694d 100644 --- a/core/state/iterator.go +++ b/core/state/iterator.go @@ -18,6 +18,7 @@ package state import ( "bytes" + "errors" "fmt" "github.com/XinFinOrg/XDPoSChain/common" @@ -27,7 +28,8 @@ import ( ) // nodeIterator is an iterator to traverse the entire state trie post-order, -// including all of the contract code and contract state tries. +// including all of the contract code and contract state tries. Preimage is +// required in order to resolve the contract address. type nodeIterator struct { state *StateDB // State being iterated @@ -113,7 +115,15 @@ func (it *nodeIterator) step() error { if err := rlp.Decode(bytes.NewReader(it.stateIt.LeafBlob()), &account); err != nil { return err } - dataTrie, err := it.state.db.OpenStorageTrie(it.state.originalRoot, common.BytesToHash(it.stateIt.LeafKey()), account.Root) + // Lookup the preimage of account hash + preimage := it.state.trie.GetKey(it.stateIt.LeafKey()) + if preimage == nil { + return errors.New("account address is not available") + } + address := common.BytesToAddress(preimage) + + // Traverse the storage slots belong to the account + dataTrie, err := it.state.db.OpenStorageTrie(it.state.originalRoot, address, account.Root) if err != nil { return err } @@ -126,8 +136,7 @@ func (it *nodeIterator) step() error { } if !bytes.Equal(account.CodeHash, types.EmptyCodeHash.Bytes()) { it.codeHash = common.BytesToHash(account.CodeHash) - addrHash := common.BytesToHash(it.stateIt.LeafKey()) - it.code, err = it.state.db.ContractCode(addrHash, common.BytesToHash(account.CodeHash)) + it.code, err = it.state.db.ContractCode(address, common.BytesToHash(account.CodeHash)) if err != nil { return fmt.Errorf("code %x: %v", account.CodeHash, err) } diff --git a/core/state/state_object.go b/core/state/state_object.go index 011d908bb6c5..c667334d1c04 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -140,7 +140,7 @@ func (s *stateObject) touch() { // be loaded. func (s *stateObject) getTrie() (Trie, error) { if s.trie == nil { - tr, err := s.db.db.OpenStorageTrie(s.db.originalRoot, s.addrHash, s.data.Root) + tr, err := s.db.db.OpenStorageTrie(s.db.originalRoot, s.address, s.data.Root) if err != nil { return nil, err } @@ -376,7 +376,7 @@ func (s *stateObject) Code() []byte { if bytes.Equal(s.CodeHash(), types.EmptyCodeHash.Bytes()) { return nil } - code, err := s.db.db.ContractCode(s.addrHash, common.BytesToHash(s.CodeHash())) + code, err := s.db.db.ContractCode(s.address, common.BytesToHash(s.CodeHash())) if err != nil { s.db.setError(fmt.Errorf("can't load code hash %x: %v", s.CodeHash(), err)) } @@ -394,7 +394,7 @@ func (s *stateObject) CodeSize() int { if bytes.Equal(s.CodeHash(), types.EmptyCodeHash.Bytes()) { return 0 } - size, err := s.db.db.ContractCodeSize(s.addrHash, common.BytesToHash(s.CodeHash())) + size, err := s.db.db.ContractCodeSize(s.address, common.BytesToHash(s.CodeHash())) if err != nil { s.db.setError(fmt.Errorf("can't load code size %x: %v", s.CodeHash(), err)) } diff --git a/core/state/statedb.go b/core/state/statedb.go index 3754f4725b86..8543fbdcec05 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -323,7 +323,7 @@ func (s *StateDB) GetAccountInfo(addr common.Address) *AccountInfo { if stateObject.code != nil { result.CodeSize = len(stateObject.code) } else { - size, err := s.db.ContractCodeSize(stateObject.addrHash, common.BytesToHash(stateObject.CodeHash())) + size, err := s.db.ContractCodeSize(stateObject.address, common.BytesToHash(stateObject.CodeHash())) if err != nil { s.setError(err) } diff --git a/core/state/sync_test.go b/core/state/sync_test.go index a135b37d3840..2d801e39de3a 100644 --- a/core/state/sync_test.go +++ b/core/state/sync_test.go @@ -42,7 +42,7 @@ type testAccount struct { func makeTestState() (ethdb.Database, Database, common.Hash, []*testAccount) { // Create an empty state db := rawdb.NewMemoryDatabase() - sdb := NewDatabase(db) + sdb := NewDatabaseWithConfig(db, &trie.Config{Preimages: true}) state, _ := New(types.EmptyRootHash, sdb) // Fill it with some arbitrary data @@ -100,28 +100,9 @@ func checkStateAccounts(t *testing.T, db ethdb.Database, root common.Hash, accou } } -// checkTrieConsistency checks that all nodes in a (sub-)trie are indeed present. -func checkTrieConsistency(db ethdb.Database, root common.Hash) error { - if v, _ := db.Get(root[:]); v == nil { - return nil // Consider a non existent state consistent. - } - trie, err := trie.New(trie.StateTrieID(root), trie.NewDatabase(db)) - if err != nil { - return err - } - it := trie.MustNodeIterator(nil) - for it.Next(true) { - } - return it.Error() -} - // checkStateConsistency checks that all data of a state root is present. func checkStateConsistency(db ethdb.Database, root common.Hash) error { - // Create and iterate a state trie rooted in a sub-node - if _, err := db.Get(root.Bytes()); err != nil { - return nil // Consider a non existent state consistent. - } - state, err := New(root, NewDatabase(db)) + state, err := New(root, NewDatabaseWithConfig(db, &trie.Config{Preimages: true})) if err != nil { return err } @@ -172,7 +153,7 @@ type stateElement struct { func testIterativeStateSync(t *testing.T, count int, commit bool, bypath bool) { // Create a random state to copy - _, srcDb, srcRoot, srcAccounts := makeTestState() + srcDisk, srcDb, srcRoot, srcAccounts := makeTestState() if commit { srcDb.TrieDB().Commit(srcRoot, false) } @@ -205,7 +186,7 @@ func testIterativeStateSync(t *testing.T, count int, commit bool, bypath bool) { codeResults = make([]trie.CodeSyncResult, len(codeElements)) ) for i, element := range codeElements { - data, err := srcDb.ContractCode(common.Hash{}, element.code) + data, err := srcDb.ContractCode(common.Address{}, element.code) if err != nil { t.Fatalf("failed to retrieve contract bytecode for hash %x", element.code) } @@ -275,6 +256,10 @@ func testIterativeStateSync(t *testing.T, count int, commit bool, bypath bool) { }) } } + // Copy the preimages from source db in order to traverse the state. + srcDb.TrieDB().WritePreimages() + copyPreimages(srcDisk, dstDb) + // Cross check that the two states are in sync checkStateAccounts(t, dstDb, srcRoot, srcAccounts) } @@ -283,7 +268,7 @@ func testIterativeStateSync(t *testing.T, count int, commit bool, bypath bool) { // partial results are returned, and the others sent only later. func TestIterativeDelayedStateSync(t *testing.T) { // Create a random state to copy - _, srcDb, srcRoot, srcAccounts := makeTestState() + srcDisk, srcDb, srcRoot, srcAccounts := makeTestState() // Create a destination state and sync with the scheduler dstDb := rawdb.NewMemoryDatabase() @@ -313,7 +298,7 @@ func TestIterativeDelayedStateSync(t *testing.T) { if len(codeElements) > 0 { codeResults := make([]trie.CodeSyncResult, len(codeElements)/2+1) for i, element := range codeElements[:len(codeResults)] { - data, err := srcDb.ContractCode(common.Hash{}, element.code) + data, err := srcDb.ContractCode(common.Address{}, element.code) if err != nil { t.Fatalf("failed to retrieve contract bytecode for %x", element.code) } @@ -364,6 +349,10 @@ func TestIterativeDelayedStateSync(t *testing.T) { }) } } + // Copy the preimages from source db in order to traverse the state. + srcDb.TrieDB().WritePreimages() + copyPreimages(srcDisk, dstDb) + // Cross check that the two states are in sync checkStateAccounts(t, dstDb, srcRoot, srcAccounts) } @@ -376,7 +365,7 @@ func TestIterativeRandomStateSyncBatched(t *testing.T) { testIterativeRandomS func testIterativeRandomStateSync(t *testing.T, count int) { // Create a random state to copy - _, srcDb, srcRoot, srcAccounts := makeTestState() + srcDisk, srcDb, srcRoot, srcAccounts := makeTestState() // Create a destination state and sync with the scheduler dstDb := rawdb.NewMemoryDatabase() @@ -400,7 +389,7 @@ func testIterativeRandomStateSync(t *testing.T, count int) { if len(codeQueue) > 0 { results := make([]trie.CodeSyncResult, 0, len(codeQueue)) for hash := range codeQueue { - data, err := srcDb.ContractCode(common.Hash{}, hash) + data, err := srcDb.ContractCode(common.Address{}, hash) if err != nil { t.Fatalf("failed to retrieve node data for %x", hash) } @@ -448,6 +437,10 @@ func testIterativeRandomStateSync(t *testing.T, count int) { codeQueue[hash] = struct{}{} } } + // Copy the preimages from source db in order to traverse the state. + srcDb.TrieDB().WritePreimages() + copyPreimages(srcDisk, dstDb) + // Cross check that the two states are in sync checkStateAccounts(t, dstDb, srcRoot, srcAccounts) } @@ -456,7 +449,7 @@ func testIterativeRandomStateSync(t *testing.T, count int) { // partial results are returned (Even those randomly), others sent only later. func TestIterativeRandomDelayedStateSync(t *testing.T) { // Create a random state to copy - _, srcDb, srcRoot, srcAccounts := makeTestState() + srcDisk, srcDb, srcRoot, srcAccounts := makeTestState() // Create a destination state and sync with the scheduler dstDb := rawdb.NewMemoryDatabase() @@ -482,7 +475,7 @@ func TestIterativeRandomDelayedStateSync(t *testing.T) { for hash := range codeQueue { delete(codeQueue, hash) - data, err := srcDb.ContractCode(common.Hash{}, hash) + data, err := srcDb.ContractCode(common.Address{}, hash) if err != nil { t.Fatalf("failed to retrieve node data for %x", hash) } @@ -538,6 +531,10 @@ func TestIterativeRandomDelayedStateSync(t *testing.T) { codeQueue[hash] = struct{}{} } } + // Copy the preimages from source db in order to traverse the state. + srcDb.TrieDB().WritePreimages() + copyPreimages(srcDisk, dstDb) + // Cross check that the two states are in sync checkStateAccounts(t, dstDb, srcRoot, srcAccounts) } @@ -556,7 +553,6 @@ func TestIncompleteStateSync(t *testing.T) { } } isCode[types.EmptyCodeHash] = struct{}{} - checkTrieConsistency(db, srcRoot) // Create a destination state and sync with the scheduler dstDb := rawdb.NewMemoryDatabase() @@ -589,7 +585,7 @@ func TestIncompleteStateSync(t *testing.T) { if len(codeQueue) > 0 { results := make([]trie.CodeSyncResult, 0, len(codeQueue)) for hash := range codeQueue { - data, err := srcDb.ContractCode(common.Hash{}, hash) + data, err := srcDb.ContractCode(common.Address{}, hash) if err != nil { t.Fatalf("failed to retrieve node data for %x", hash) } @@ -603,7 +599,6 @@ func TestIncompleteStateSync(t *testing.T) { } } } - var nodehashes []common.Hash if len(nodeQueue) > 0 { results := make([]trie.NodeSyncResult, 0, len(nodeQueue)) for path, element := range nodeQueue { @@ -618,7 +613,6 @@ func TestIncompleteStateSync(t *testing.T) { addedPaths = append(addedPaths, element.path) addedHashes = append(addedHashes, element.hash) } - nodehashes = append(nodehashes, element.hash) } // Process each of the state nodes for _, result := range results { @@ -633,13 +627,6 @@ func TestIncompleteStateSync(t *testing.T) { } batch.Write() - for _, root := range nodehashes { - // Can't use checkStateConsistency here because subtrie keys may have odd - // length and crash in LeafKey. - if err := checkTrieConsistency(dstDb, root); err != nil { - t.Fatalf("state inconsistent: %v", err) - } - } // Fetch the next batch to retrieve nodeQueue = make(map[string]stateElement) codeQueue = make(map[common.Hash]struct{}) @@ -655,6 +642,10 @@ func TestIncompleteStateSync(t *testing.T) { codeQueue[hash] = struct{}{} } } + // Copy the preimages from source db in order to traverse the state. + srcDb.TrieDB().WritePreimages() + copyPreimages(db, dstDb) + // Sanity check that removing any node from the database is detected for _, node := range addedCodes { val := rawdb.ReadCode(dstDb, node) @@ -679,3 +670,15 @@ func TestIncompleteStateSync(t *testing.T) { rawdb.WriteTrieNode(dstDb, owner, inner, hash, val, scheme) } } + +func copyPreimages(srcDb, dstDb ethdb.Database) { + it := srcDb.NewIterator(rawdb.PreimagePrefix, nil) + defer it.Release() + + preimages := make(map[common.Hash][]byte) + for it.Next() { + hash := it.Key()[len(rawdb.PreimagePrefix):] + preimages[common.BytesToHash(hash)] = common.CopyBytes(it.Value()) + } + rawdb.WritePreimages(dstDb, preimages) +} diff --git a/trie/database.go b/trie/database.go index ac6e64599999..9136ca0e568d 100644 --- a/trie/database.go +++ b/trie/database.go @@ -182,10 +182,15 @@ func (db *Database) Scheme() string { // It is meant to be called when closing the blockchain object, so that all // resources held can be released correctly. func (db *Database) Close() error { + db.WritePreimages() + return db.backend.Close() +} + +// WritePreimages flushes all accumulated preimages to disk forcibly. +func (db *Database) WritePreimages() { if db.preimages != nil { db.preimages.commit(true) } - return db.backend.Close() } // Cap iteratively flushes old but still referenced trie nodes until the total