From 53161ca33c3bb5e2c4dc5da2faca9e9af4a3a84d Mon Sep 17 00:00:00 2001 From: Gheis Mohammadi Date: Tue, 11 Apr 2023 23:56:34 +0000 Subject: [PATCH] Add prefix for validator wrapper (#4402) * add separate prefix for validator wrapper * update comments * make read/write backward compatible * add validator codes to stats * goimports * goimports accessor_state --- core/genesis.go | 2 +- core/rawdb/accessors_state.go | 54 ++++++++++++++++++++++++++ core/rawdb/database.go | 4 ++ core/rawdb/schema.go | 23 +++++++++-- core/state/database.go | 47 ++++++++++++++++++++++ core/state/dump.go | 2 +- core/state/iterator.go | 6 +++ core/state/iterator_test.go | 2 +- core/state/journal.go | 2 +- core/state/prefeth.go | 2 +- core/state/state_object.go | 43 ++++++++++++++------ core/state/state_test.go | 8 ++-- core/state/statedb.go | 27 ++++++++----- core/state/statedb_test.go | 44 ++++++++++----------- core/state/trie_prefetcher_test.go | 6 +-- core/vm/contracts_write.go | 2 +- core/vm/evm.go | 10 ++--- core/vm/gas_table_test.go | 2 +- core/vm/instructions.go | 4 +- core/vm/interface.go | 6 +-- core/vm/logger_test.go | 8 ++-- core/vm/runtime/runtime.go | 2 +- core/vm/runtime/runtime_test.go | 4 +- hmy/tracers/block_tracer.go | 2 +- hmy/tracers/tracer.go | 2 +- rosetta/services/block.go | 4 +- rosetta/services/construction_check.go | 2 +- rpc/contract.go | 2 +- staking/availability/measure_test.go | 6 +-- 29 files changed, 241 insertions(+), 87 deletions(-) diff --git a/core/genesis.go b/core/genesis.go index 3bd4f718a..3e230cf9e 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -247,7 +247,7 @@ func (g *Genesis) ToBlock(db ethdb.Database) *types.Block { statedb, _ := state.New(common.Hash{}, state.NewDatabase(db), nil) for addr, account := range g.Alloc { statedb.AddBalance(addr, account.Balance) - statedb.SetCode(addr, account.Code) + statedb.SetCode(addr, account.Code, false) statedb.SetNonce(addr, account.Nonce) for key, value := range account.Storage { statedb.SetState(addr, key, value) diff --git a/core/rawdb/accessors_state.go b/core/rawdb/accessors_state.go index 351928fcd..72dbe94fb 100644 --- a/core/rawdb/accessors_state.go +++ b/core/rawdb/accessors_state.go @@ -93,3 +93,57 @@ func DeleteCode(db ethdb.KeyValueWriter, hash common.Hash) { utils.Logger().Error().Err(err).Msg("Failed to delete contract code") } } + +// ReadValidatorCode retrieves the validator code of the provided code hash. +func ReadValidatorCode(db ethdb.KeyValueReader, hash common.Hash) []byte { + // Try with the prefixed code scheme first, if not then try with legacy + // scheme. + data := ReadValidatorCodeWithPrefix(db, hash) + if len(data) != 0 { + return data + } + data, _ = db.Get(hash.Bytes()) + return data +} + +// ReadValidatorCodeWithPrefix retrieves the validator code of the provided code hash. +// The main difference between this function and ReadValidatorCode is this function +// will only check the existence with latest scheme(with prefix). +func ReadValidatorCodeWithPrefix(db ethdb.KeyValueReader, hash common.Hash) []byte { + data, _ := db.Get(validatorCodeKey(hash)) + return data +} + +// HasValidatorCode checks if the validator code corresponding to the +// provided code hash is present in the db. +func HasValidatorCode(db ethdb.KeyValueReader, hash common.Hash) bool { + // Try with the prefixed code scheme first, if not then try with legacy + // scheme. + if ok := HasValidatorCodeWithPrefix(db, hash); ok { + return true + } + ok, _ := db.Has(hash.Bytes()) + return ok +} + +// HasValidatorCodeWithPrefix checks if the validator code corresponding to the +// provided code hash is present in the db. This function will only check +// presence using the prefix-scheme. +func HasValidatorCodeWithPrefix(db ethdb.KeyValueReader, hash common.Hash) bool { + ok, _ := db.Has(validatorCodeKey(hash)) + return ok +} + +// WriteValidatorCode writes the provided validator code to database. +func WriteValidatorCode(db ethdb.KeyValueWriter, hash common.Hash, code []byte) { + if err := db.Put(validatorCodeKey(hash), code); err != nil { + utils.Logger().Error().Err(err).Msg("Failed to store validator code") + } +} + +// DeleteValidatorCode deletes the specified validator code from the database. +func DeleteValidatorCode(db ethdb.KeyValueWriter, hash common.Hash) { + if err := db.Delete(validatorCodeKey(hash)); err != nil { + utils.Logger().Error().Err(err).Msg("Failed to delete validator code") + } +} diff --git a/core/rawdb/database.go b/core/rawdb/database.go index 5cdae00e3..c1421b507 100644 --- a/core/rawdb/database.go +++ b/core/rawdb/database.go @@ -316,6 +316,7 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error { hashNumPairings stat tries stat codes stat + validatorCodes stat txLookups stat accountSnaps stat storageSnaps stat @@ -359,6 +360,8 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error { tries.Add(size) case bytes.HasPrefix(key, CodePrefix) && len(key) == len(CodePrefix)+common.HashLength: codes.Add(size) + case bytes.HasPrefix(key, ValidatorCodePrefix) && len(key) == len(ValidatorCodePrefix)+common.HashLength: + validatorCodes.Add(size) case bytes.HasPrefix(key, txLookupPrefix) && len(key) == (len(txLookupPrefix)+common.HashLength): txLookups.Add(size) case bytes.HasPrefix(key, SnapshotAccountPrefix) && len(key) == (len(SnapshotAccountPrefix)+common.HashLength): @@ -422,6 +425,7 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error { {"Key-Value store", "Transaction index", txLookups.Size(), txLookups.Count()}, {"Key-Value store", "Bloombit index", bloomBits.Size(), bloomBits.Count()}, {"Key-Value store", "Contract codes", codes.Size(), codes.Count()}, + {"Key-Value store", "Validator codes", validatorCodes.Size(), validatorCodes.Count()}, {"Key-Value store", "Trie nodes", tries.Size(), tries.Count()}, {"Key-Value store", "Trie preimages", preimages.Size(), preimages.Count()}, {"Key-Value store", "Account snapshot", accountSnaps.Size(), accountSnaps.Count()}, diff --git a/core/rawdb/schema.go b/core/rawdb/schema.go index 798f27f59..56147b51d 100644 --- a/core/rawdb/schema.go +++ b/core/rawdb/schema.go @@ -126,10 +126,11 @@ var ( snapdbInfoKey = []byte("SnapdbInfo") // Data item prefixes (use single byte to avoid mixing data types, avoid `i`, used for indexes). - SnapshotAccountPrefix = []byte("a") // SnapshotAccountPrefix + account hash -> account trie value - SnapshotStoragePrefix = []byte("o") // SnapshotStoragePrefix + account hash + storage hash -> storage trie value - CodePrefix = []byte("c") // CodePrefix + code hash -> account code -> We not using this at the moment - skeletonHeaderPrefix = []byte("S") // skeletonHeaderPrefix + num (uint64 big endian) -> header + SnapshotAccountPrefix = []byte("a") // SnapshotAccountPrefix + account hash -> account trie value + SnapshotStoragePrefix = []byte("o") // SnapshotStoragePrefix + account hash + storage hash -> storage trie value + CodePrefix = []byte("c") // CodePrefix + code hash -> account code + ValidatorCodePrefix = []byte("vc") // ValidatorCodePrefix + code hash -> validator code + skeletonHeaderPrefix = []byte("S") // skeletonHeaderPrefix + num (uint64 big endian) -> header // Path-based trie node scheme. trieNodeAccountPrefix = []byte("A") // trieNodeAccountPrefix + hexPath -> trie node @@ -196,6 +197,20 @@ func IsCodeKey(key []byte) (bool, []byte) { return false, nil } +// validatorCodeKey = ValidatorCodePrefix + hash +func validatorCodeKey(hash common.Hash) []byte { + return append(ValidatorCodePrefix, hash.Bytes()...) +} + +// IsValidatorCodeKey reports whether the given byte slice is the key of validator code, +// if so return the raw code hash as well. +func IsValidatorCodeKey(key []byte) (bool, []byte) { + if bytes.HasPrefix(key, ValidatorCodePrefix) && len(key) == common.HashLength+len(ValidatorCodePrefix) { + return true, key[len(ValidatorCodePrefix):] + } + return false, nil +} + // genesisStateSpecKey = genesisPrefix + hash func genesisStateSpecKey(hash common.Hash) []byte { return append(genesisPrefix, hash.Bytes()...) diff --git a/core/state/database.go b/core/state/database.go index d6a0e7e15..c1e375ccd 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -53,6 +53,12 @@ type Database interface { // ContractCodeSize retrieves a particular contracts code's size. ContractCodeSize(addrHash, codeHash common.Hash) (int, error) + // ValidatorCode retrieves a particular validator's code. + ValidatorCode(addrHash, codeHash common.Hash) ([]byte, error) + + // ValidatorCodeSize retrieves a particular validator code's size. + ValidatorCodeSize(addrHash, codeHash common.Hash) (int, error) + // DiskDB returns the underlying key-value disk database. DiskDB() ethdb.KeyValueStore @@ -234,6 +240,47 @@ func (db *cachingDB) ContractCodeSize(addrHash, codeHash common.Hash) (int, erro return len(code), err } +// ValidatorCodeSize retrieves a particular validators code's size. +func (db *cachingDB) ValidatorCodeSize(addrHash, codeHash common.Hash) (int, error) { + if cached, ok := db.codeSizeCache.Get(codeHash); ok { + return cached, nil + } + code, err := db.ValidatorCode(addrHash, codeHash) + return len(code), err +} + +// ValidatorCode retrieves a particular validator's code. +func (db *cachingDB) ValidatorCode(addrHash, codeHash common.Hash) ([]byte, error) { + code, _ := db.codeCache.Get(codeHash) + if len(code) > 0 { + return code, nil + } + code = rawdb.ReadValidatorCode(db.disk, codeHash) + if len(code) > 0 { + db.codeCache.Add(codeHash, code) + db.codeSizeCache.Add(codeHash, len(code)) + return code, nil + } + return nil, errors.New("not found") +} + +// ValidatorCodeWithPrefix retrieves a particular validator's code. If the +// code can't be found in the cache, then check the existence with **new** +// db scheme. +func (db *cachingDB) ValidatorCodeWithPrefix(addrHash, codeHash common.Hash) ([]byte, error) { + code, _ := db.codeCache.Get(codeHash) + if len(code) > 0 { + return code, nil + } + code = rawdb.ReadValidatorCodeWithPrefix(db.disk, codeHash) + if len(code) > 0 { + db.codeCache.Add(codeHash, code) + db.codeSizeCache.Add(codeHash, len(code)) + return code, nil + } + return nil, errors.New("not found") +} + // DiskDB returns the underlying key-value disk database. func (db *cachingDB) DiskDB() ethdb.KeyValueStore { return db.disk diff --git a/core/state/dump.go b/core/state/dump.go index d9e031ed4..c4d70f6e0 100644 --- a/core/state/dump.go +++ b/core/state/dump.go @@ -165,7 +165,7 @@ func (s *DB) DumpToCollector(c DumpCollector, conf *DumpConfig) (nextKey []byte) addr := common.BytesToAddress(addrBytes) obj := newObject(s, addr, data) if !conf.SkipCode { - account.Code = obj.Code(s.db) + account.Code = obj.Code(s.db, false) } if !conf.SkipStorage { account.Storage = make(map[common.Hash]string) diff --git a/core/state/iterator.go b/core/state/iterator.go index dea2c81b0..8bc26332d 100644 --- a/core/state/iterator.go +++ b/core/state/iterator.go @@ -124,6 +124,12 @@ func (it *NodeIterator) step() error { if err != nil { return fmt.Errorf("code %x: %v", account.CodeHash, err) } + if it.code == nil || len(it.code) == 0 { + it.code, err = it.state.db.ValidatorCode(addrHash, common.BytesToHash(account.CodeHash)) + if err != nil { + return fmt.Errorf("code %x: %v", account.CodeHash, err) + } + } } it.accountHash = it.stateIt.Parent() return nil diff --git a/core/state/iterator_test.go b/core/state/iterator_test.go index 50374059b..8333dc8bc 100644 --- a/core/state/iterator_test.go +++ b/core/state/iterator_test.go @@ -54,7 +54,7 @@ func makeTestState() (ethdb.Database, Database, common.Hash, []*testAccount) { acc.nonce = uint64(42 * i) if i%3 == 0 { - obj.SetCode(crypto.Keccak256Hash([]byte{i, i, i, i, i}), []byte{i, i, i, i, i}) + obj.SetCode(crypto.Keccak256Hash([]byte{i, i, i, i, i}), []byte{i, i, i, i, i}, false) acc.code = []byte{i, i, i, i, i} } if i%5 == 0 { diff --git a/core/state/journal.go b/core/state/journal.go index 48dd66f66..210f38808 100644 --- a/core/state/journal.go +++ b/core/state/journal.go @@ -217,7 +217,7 @@ func (ch nonceChange) dirtied() *common.Address { } func (ch codeChange) revert(s *DB) { - s.getStateObject(*ch.account).setCode(common.BytesToHash(ch.prevhash), ch.prevcode) + s.getStateObject(*ch.account).setCode(common.BytesToHash(ch.prevhash), ch.prevcode, false) } func (ch codeChange) dirtied() *common.Address { diff --git a/core/state/prefeth.go b/core/state/prefeth.go index 4d3b317bb..0b19f80d7 100644 --- a/core/state/prefeth.go +++ b/core/state/prefeth.go @@ -100,7 +100,7 @@ func (s *DB) prefetchWorker(job *prefetchJob, jobs chan *prefetchJob) { addr := common.BytesToAddress(addrBytes) obj := newObject(s, addr, data) if data.CodeHash != nil { - obj.Code(s.db) + obj.Code(s.db, false) } // build account trie tree diff --git a/core/state/state_object.go b/core/state/state_object.go index a235b18f7..262f5136e 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -93,9 +93,10 @@ type Object struct { // Cache flags. // When an object is marked suicided it will be delete from the trie // during the "update" phase of the state transition. - dirtyCode bool // true if the code was updated - suicided bool - deleted bool + validatorWrapper bool // true if the code belongs to validator wrapper + dirtyCode bool // true if the code was updated + suicided bool + deleted bool } // empty returns whether the account is considered empty. @@ -497,14 +498,24 @@ func (s *Object) Address() common.Address { return s.address } -// Code returns the contract code associated with this object, if any. -func (s *Object) Code(db Database) []byte { +// Code returns the contract/validator code associated with this object, if any. +func (s *Object) Code(db Database, isValidatorCode bool) []byte { if s.code != nil { return s.code } if bytes.Equal(s.CodeHash(), types.EmptyCodeHash.Bytes()) { return nil } + if s.validatorWrapper || isValidatorCode { + code, err := db.ValidatorCode(s.addrHash, common.BytesToHash(s.CodeHash())) + if err != nil { + s.setError(fmt.Errorf("can't load validator code hash %x: %v", s.CodeHash(), err)) + } + if code != nil { + s.code = code + return code + } + } code, err := db.ContractCode(s.addrHash, common.BytesToHash(s.CodeHash())) if err != nil { s.setError(fmt.Errorf("can't load code hash %x: %v", s.CodeHash(), err)) @@ -513,16 +524,25 @@ func (s *Object) Code(db Database) []byte { return code } -// CodeSize returns the size of the contract code associated with this object, +// CodeSize returns the size of the contract/validator code associated with this object, // or zero if none. This method is an almost mirror of Code, but uses a cache // inside the database to avoid loading codes seen recently. -func (s *Object) CodeSize(db Database) int { +func (s *Object) CodeSize(db Database, isValidatorCode bool) int { if s.code != nil { return len(s.code) } if bytes.Equal(s.CodeHash(), types.EmptyCodeHash.Bytes()) { return 0 } + if s.validatorWrapper || isValidatorCode { + size, err := db.ValidatorCodeSize(s.addrHash, common.BytesToHash(s.CodeHash())) + if err != nil { + s.setError(fmt.Errorf("can't load validator code size %x: %v", s.CodeHash(), err)) + } + if size > 0 { + return size + } + } size, err := db.ContractCodeSize(s.addrHash, common.BytesToHash(s.CodeHash())) if err != nil { s.setError(fmt.Errorf("can't load code size %x: %v", s.CodeHash(), err)) @@ -530,20 +550,21 @@ func (s *Object) CodeSize(db Database) int { return size } -func (s *Object) SetCode(codeHash common.Hash, code []byte) { - prevcode := s.Code(s.db.db) +func (s *Object) SetCode(codeHash common.Hash, code []byte, isValidatorCode bool) { + prevcode := s.Code(s.db.db, isValidatorCode) s.db.journal.append(codeChange{ account: &s.address, prevhash: s.CodeHash(), prevcode: prevcode, }) - s.setCode(codeHash, code) + s.setCode(codeHash, code, isValidatorCode) } -func (s *Object) setCode(codeHash common.Hash, code []byte) { +func (s *Object) setCode(codeHash common.Hash, code []byte, isValidatorCode bool) { s.code = code s.data.CodeHash = codeHash[:] s.dirtyCode = true + s.validatorWrapper = isValidatorCode } func (s *Object) SetNonce(nonce uint64) { diff --git a/core/state/state_test.go b/core/state/state_test.go index 9209d3de2..9d209a80b 100644 --- a/core/state/state_test.go +++ b/core/state/state_test.go @@ -48,7 +48,7 @@ func TestDump(t *testing.T) { obj1 := s.state.GetOrNewStateObject(common.BytesToAddress([]byte{0x01})) obj1.AddBalance(big.NewInt(22)) obj2 := s.state.GetOrNewStateObject(common.BytesToAddress([]byte{0x01, 0x02})) - obj2.SetCode(crypto.Keccak256Hash([]byte{3, 3, 3, 3, 3, 3, 3}), []byte{3, 3, 3, 3, 3, 3, 3}) + obj2.SetCode(crypto.Keccak256Hash([]byte{3, 3, 3, 3, 3, 3, 3}), []byte{3, 3, 3, 3, 3, 3, 3}, false) obj3 := s.state.GetOrNewStateObject(common.BytesToAddress([]byte{0x02})) obj3.SetBalance(big.NewInt(44)) @@ -166,7 +166,7 @@ func TestSnapshot2(t *testing.T) { so0 := state.getStateObject(stateobjaddr0) so0.SetBalance(big.NewInt(42)) so0.SetNonce(43) - so0.SetCode(crypto.Keccak256Hash([]byte{'c', 'a', 'f', 'e'}), []byte{'c', 'a', 'f', 'e'}) + so0.SetCode(crypto.Keccak256Hash([]byte{'c', 'a', 'f', 'e'}), []byte{'c', 'a', 'f', 'e'}, false) so0.suicided = false so0.deleted = false state.setStateObject(so0) @@ -178,7 +178,7 @@ func TestSnapshot2(t *testing.T) { so1 := state.getStateObject(stateobjaddr1) so1.SetBalance(big.NewInt(52)) so1.SetNonce(53) - so1.SetCode(crypto.Keccak256Hash([]byte{'c', 'a', 'f', 'e', '2'}), []byte{'c', 'a', 'f', 'e', '2'}) + so1.SetCode(crypto.Keccak256Hash([]byte{'c', 'a', 'f', 'e', '2'}), []byte{'c', 'a', 'f', 'e', '2'}, false) so1.suicided = true so1.deleted = true state.setStateObject(so1) @@ -194,7 +194,7 @@ func TestSnapshot2(t *testing.T) { so0Restored := state.getStateObject(stateobjaddr0) // Update lazily-loaded values before comparing. so0Restored.GetState(state.db, storageaddr) - so0Restored.Code(state.db) + so0Restored.Code(state.db, false) // non-deleted is equal (restored) compareStateObjects(so0Restored, so0, t) diff --git a/core/state/statedb.go b/core/state/statedb.go index eff2a37c2..30692e4d4 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -342,18 +342,18 @@ func (db *DB) BlockHash() common.Hash { return db.bhash } -func (db *DB) GetCode(addr common.Address) []byte { +func (db *DB) GetCode(addr common.Address, isValidatorCode bool) []byte { Object := db.getStateObject(addr) if Object != nil { - return Object.Code(db.db) + return Object.Code(db.db, isValidatorCode) } return nil } -func (db *DB) GetCodeSize(addr common.Address) int { +func (db *DB) GetCodeSize(addr common.Address, isValidatorCode bool) int { Object := db.getStateObject(addr) if Object != nil { - return Object.CodeSize(db.db) + return Object.CodeSize(db.db, isValidatorCode) } return 0 } @@ -475,10 +475,10 @@ func (db *DB) SetNonce(addr common.Address, nonce uint64) { } } -func (db *DB) SetCode(addr common.Address, code []byte) { +func (db *DB) SetCode(addr common.Address, code []byte, isValidatorCode bool) { Object := db.GetOrNewStateObject(addr) if Object != nil { - Object.SetCode(crypto.Keccak256Hash(code), code) + Object.SetCode(crypto.Keccak256Hash(code), code, isValidatorCode) } } @@ -1053,7 +1053,11 @@ func (db *DB) Commit(deleteEmptyObjects bool) (common.Hash, error) { if obj := db.stateObjects[addr]; !obj.deleted { // Write any contract code associated with the state object if obj.code != nil && obj.dirtyCode { - rawdb.WriteCode(codeWriter, common.BytesToHash(obj.CodeHash()), obj.code) + if obj.validatorWrapper { + rawdb.WriteValidatorCode(codeWriter, common.BytesToHash(obj.CodeHash()), obj.code) + } else { + rawdb.WriteCode(codeWriter, common.BytesToHash(obj.CodeHash()), obj.code) + } obj.dirtyCode = false } // Write any storage changes in the state object to its storage trie @@ -1237,9 +1241,12 @@ func (db *DB) ValidatorWrapper( return copyValidatorWrapperIfNeeded(cached, sendOriginal, copyDelegations), nil } - by := db.GetCode(addr) + by := db.GetCode(addr, true) if len(by) == 0 { - return nil, ErrAddressNotPresent + by = db.GetCode(addr, false) + if len(by) == 0 { + return nil, ErrAddressNotPresent + } } val := stk.ValidatorWrapper{} if err := rlp.DecodeBytes(by, &val); err != nil { @@ -1285,7 +1292,7 @@ func (db *DB) UpdateValidatorWrapper( return err } // has revert in-built for the code field - db.SetCode(addr, by) + db.SetCode(addr, by, true) // update cache db.stateValidators[addr] = val return nil diff --git a/core/state/statedb_test.go b/core/state/statedb_test.go index db2cf5ebf..f4277809b 100644 --- a/core/state/statedb_test.go +++ b/core/state/statedb_test.go @@ -50,7 +50,7 @@ func TestUpdateLeaks(t *testing.T) { state.SetState(addr, common.BytesToHash([]byte{i, i, i}), common.BytesToHash([]byte{i, i, i, i})) } if i%3 == 0 { - state.SetCode(addr, []byte{i, i, i, i, i}) + state.SetCode(addr, []byte{i, i, i, i, i}, false) } } @@ -84,7 +84,7 @@ func TestIntermediateLeaks(t *testing.T) { state.SetState(addr, common.Hash{i, i, i, tweak}, common.Hash{i, i, i, i, tweak}) } if i%3 == 0 { - state.SetCode(addr, []byte{i, i, i, i, i, tweak}) + state.SetCode(addr, []byte{i, i, i, i, i, tweak}, false) } } @@ -286,7 +286,7 @@ func newTestAction(addr common.Address, r *rand.Rand) testAction { code := make([]byte, 16) binary.BigEndian.PutUint64(code, uint64(a.args[0])) binary.BigEndian.PutUint64(code[8:], uint64(a.args[1])) - s.SetCode(addr, code) + s.SetCode(addr, code, false) }, args: make([]int64, 2), }, @@ -452,9 +452,9 @@ func (test *snapshotTest) checkEqual(state, checkstate *DB) error { checkeq("HasSuicided", state.HasSuicided(addr), checkstate.HasSuicided(addr)) checkeq("GetBalance", state.GetBalance(addr), checkstate.GetBalance(addr)) checkeq("GetNonce", state.GetNonce(addr), checkstate.GetNonce(addr)) - checkeq("GetCode", state.GetCode(addr), checkstate.GetCode(addr)) + checkeq("GetCode", state.GetCode(addr, false), checkstate.GetCode(addr, false)) checkeq("GetCodeHash", state.GetCodeHash(addr), checkstate.GetCodeHash(addr)) - checkeq("GetCodeSize", state.GetCodeSize(addr), checkstate.GetCodeSize(addr)) + checkeq("GetCodeSize", state.GetCodeSize(addr, false), checkstate.GetCodeSize(addr, false)) // Check storage. if obj := state.getStateObject(addr); obj != nil { state.ForEachStorage(addr, func(key, value common.Hash) bool { @@ -525,14 +525,14 @@ func TestCopyCommitCopy(t *testing.T) { skey := common.HexToHash("aaa") sval := common.HexToHash("bbb") - state.SetBalance(addr, big.NewInt(42)) // Change the account trie - state.SetCode(addr, []byte("hello")) // Change an external metadata - state.SetState(addr, skey, sval) // Change the storage trie + state.SetBalance(addr, big.NewInt(42)) // Change the account trie + state.SetCode(addr, []byte("hello"), false) // Change an external metadata + state.SetState(addr, skey, sval) // Change the storage trie if balance := state.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { t.Fatalf("initial balance mismatch: have %v, want %v", balance, 42) } - if code := state.GetCode(addr); !bytes.Equal(code, []byte("hello")) { + if code := state.GetCode(addr, false); !bytes.Equal(code, []byte("hello")) { t.Fatalf("initial code mismatch: have %x, want %x", code, []byte("hello")) } if val := state.GetState(addr, skey); val != sval { @@ -546,7 +546,7 @@ func TestCopyCommitCopy(t *testing.T) { if balance := copyOne.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { t.Fatalf("first copy pre-commit balance mismatch: have %v, want %v", balance, 42) } - if code := copyOne.GetCode(addr); !bytes.Equal(code, []byte("hello")) { + if code := copyOne.GetCode(addr, false); !bytes.Equal(code, []byte("hello")) { t.Fatalf("first copy pre-commit code mismatch: have %x, want %x", code, []byte("hello")) } if val := copyOne.GetState(addr, skey); val != sval { @@ -560,7 +560,7 @@ func TestCopyCommitCopy(t *testing.T) { if balance := copyOne.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { t.Fatalf("first copy post-commit balance mismatch: have %v, want %v", balance, 42) } - if code := copyOne.GetCode(addr); !bytes.Equal(code, []byte("hello")) { + if code := copyOne.GetCode(addr, false); !bytes.Equal(code, []byte("hello")) { t.Fatalf("first copy post-commit code mismatch: have %x, want %x", code, []byte("hello")) } if val := copyOne.GetState(addr, skey); val != sval { @@ -574,7 +574,7 @@ func TestCopyCommitCopy(t *testing.T) { if balance := copyTwo.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { t.Fatalf("second copy balance mismatch: have %v, want %v", balance, 42) } - if code := copyTwo.GetCode(addr); !bytes.Equal(code, []byte("hello")) { + if code := copyTwo.GetCode(addr, false); !bytes.Equal(code, []byte("hello")) { t.Fatalf("second copy code mismatch: have %x, want %x", code, []byte("hello")) } if val := copyTwo.GetState(addr, skey); val != sval { @@ -597,14 +597,14 @@ func TestCopyCopyCommitCopy(t *testing.T) { skey := common.HexToHash("aaa") sval := common.HexToHash("bbb") - state.SetBalance(addr, big.NewInt(42)) // Change the account trie - state.SetCode(addr, []byte("hello")) // Change an external metadata - state.SetState(addr, skey, sval) // Change the storage trie + state.SetBalance(addr, big.NewInt(42)) // Change the account trie + state.SetCode(addr, []byte("hello"), false) // Change an external metadata + state.SetState(addr, skey, sval) // Change the storage trie if balance := state.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { t.Fatalf("initial balance mismatch: have %v, want %v", balance, 42) } - if code := state.GetCode(addr); !bytes.Equal(code, []byte("hello")) { + if code := state.GetCode(addr, false); !bytes.Equal(code, []byte("hello")) { t.Fatalf("initial code mismatch: have %x, want %x", code, []byte("hello")) } if val := state.GetState(addr, skey); val != sval { @@ -618,7 +618,7 @@ func TestCopyCopyCommitCopy(t *testing.T) { if balance := copyOne.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { t.Fatalf("first copy balance mismatch: have %v, want %v", balance, 42) } - if code := copyOne.GetCode(addr); !bytes.Equal(code, []byte("hello")) { + if code := copyOne.GetCode(addr, false); !bytes.Equal(code, []byte("hello")) { t.Fatalf("first copy code mismatch: have %x, want %x", code, []byte("hello")) } if val := copyOne.GetState(addr, skey); val != sval { @@ -632,7 +632,7 @@ func TestCopyCopyCommitCopy(t *testing.T) { if balance := copyTwo.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { t.Fatalf("second copy pre-commit balance mismatch: have %v, want %v", balance, 42) } - if code := copyTwo.GetCode(addr); !bytes.Equal(code, []byte("hello")) { + if code := copyTwo.GetCode(addr, false); !bytes.Equal(code, []byte("hello")) { t.Fatalf("second copy pre-commit code mismatch: have %x, want %x", code, []byte("hello")) } if val := copyTwo.GetState(addr, skey); val != sval { @@ -645,7 +645,7 @@ func TestCopyCopyCommitCopy(t *testing.T) { if balance := copyTwo.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { t.Fatalf("second copy post-commit balance mismatch: have %v, want %v", balance, 42) } - if code := copyTwo.GetCode(addr); !bytes.Equal(code, []byte("hello")) { + if code := copyTwo.GetCode(addr, false); !bytes.Equal(code, []byte("hello")) { t.Fatalf("second copy post-commit code mismatch: have %x, want %x", code, []byte("hello")) } if val := copyTwo.GetState(addr, skey); val != sval { @@ -659,7 +659,7 @@ func TestCopyCopyCommitCopy(t *testing.T) { if balance := copyThree.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { t.Fatalf("third copy balance mismatch: have %v, want %v", balance, 42) } - if code := copyThree.GetCode(addr); !bytes.Equal(code, []byte("hello")) { + if code := copyThree.GetCode(addr, false); !bytes.Equal(code, []byte("hello")) { t.Fatalf("third copy code mismatch: have %x, want %x", code, []byte("hello")) } if val := copyThree.GetState(addr, skey); val != sval { @@ -717,10 +717,10 @@ func TestMissingTrieNodes(t *testing.T) { addr := common.BytesToAddress([]byte("so")) { state.SetBalance(addr, big.NewInt(1)) - state.SetCode(addr, []byte{1, 2, 3}) + state.SetCode(addr, []byte{1, 2, 3}, false) a2 := common.BytesToAddress([]byte("another")) state.SetBalance(a2, big.NewInt(100)) - state.SetCode(a2, []byte{1, 2, 4}) + state.SetCode(a2, []byte{1, 2, 4}, false) root, _ = state.Commit(false) t.Logf("root: %x", root) // force-flush diff --git a/core/state/trie_prefetcher_test.go b/core/state/trie_prefetcher_test.go index ffd67e02a..d5774d38f 100644 --- a/core/state/trie_prefetcher_test.go +++ b/core/state/trie_prefetcher_test.go @@ -33,9 +33,9 @@ func filledStateDB() *DB { skey := common.HexToHash("aaa") sval := common.HexToHash("bbb") - state.SetBalance(addr, big.NewInt(42)) // Change the account trie - state.SetCode(addr, []byte("hello")) // Change an external metadata - state.SetState(addr, skey, sval) // Change the storage trie + state.SetBalance(addr, big.NewInt(42)) // Change the account trie + state.SetCode(addr, []byte("hello"), false) // Change an external metadata + state.SetState(addr, skey, sval) // Change the storage trie for i := 0; i < 100; i++ { sk := common.BigToHash(big.NewInt(int64(i))) state.SetState(addr, sk, sk) // Change the storage trie diff --git a/core/vm/contracts_write.go b/core/vm/contracts_write.go index 46ba7fe92..7e24eb9a2 100644 --- a/core/vm/contracts_write.go +++ b/core/vm/contracts_write.go @@ -242,7 +242,7 @@ func (c *crossShardXferPrecompile) RunWriteCapable( return nil, err } // validate not a contract (toAddress can still be a contract) - if len(evm.StateDB.GetCode(fromAddress)) > 0 && !evm.IsValidator(evm.StateDB, fromAddress) { + if len(evm.StateDB.GetCode(fromAddress, false)) > 0 && !evm.IsValidator(evm.StateDB, fromAddress) { return nil, errors.New("cross shard xfer not yet implemented for contracts") } // can't have too many shards diff --git a/core/vm/evm.go b/core/vm/evm.go index 49857255f..53da390db 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -336,7 +336,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas evm.Transfer(evm.StateDB, caller.Address(), to.Address(), value, txType) codeHash := evm.StateDB.GetCodeHash(addr) - code := evm.StateDB.GetCode(addr) + code := evm.StateDB.GetCode(addr, false) // If address is a validator address, then it's not a smart contract address // we don't use its code and codeHash fields if evm.Context.IsValidator(evm.StateDB, addr) { @@ -402,7 +402,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, // EVM. The contract is a scoped environment for this execution context // only. contract := NewContract(caller, to, value, gas) - contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) + contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr, false)) ret, err = run(evm, contract, input, false) if err != nil { @@ -435,7 +435,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by // Initialise a new contract and make initialise the delegate values contract := NewContract(caller, to, nil, gas).AsDelegate() - contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) + contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr, false)) ret, err = run(evm, contract, input, false) if err != nil { @@ -468,7 +468,7 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte // EVM. The contract is a scoped environment for this execution context // only. contract := NewContract(caller, to, new(big.Int), gas) - contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) + contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr, false)) // We do an AddBalance of zero here, just in order to trigger a touch. // This doesn't matter on Mainnet, where all empties are gone at the time of Byzantium, @@ -553,7 +553,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, if err == nil && !maxCodeSizeExceeded { createDataGas := uint64(len(ret)) * params.CreateDataGas if contract.UseGas(createDataGas) { - evm.StateDB.SetCode(address, ret) + evm.StateDB.SetCode(address, ret, false) } else { err = ErrCodeStoreOutOfGas } diff --git a/core/vm/gas_table_test.go b/core/vm/gas_table_test.go index 08e265c74..65973e832 100644 --- a/core/vm/gas_table_test.go +++ b/core/vm/gas_table_test.go @@ -85,7 +85,7 @@ func TestEIP2200(t *testing.T) { statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) statedb.CreateAccount(address) - statedb.SetCode(address, hexutil.MustDecode(tt.input)) + statedb.SetCode(address, hexutil.MustDecode(tt.input), false) statedb.SetState(address, common.Hash{}, common.BytesToHash([]byte{tt.original})) statedb.Finalise(true) // Push the state into the "original" slot diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 091ba28ff..73f826a63 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -488,7 +488,7 @@ func opExtCodeSize(pc *uint64, interpreter *EVMInterpreter, contract *Contract, slot.SetUint64(0) return nil, nil } - slot.SetUint64(uint64(interpreter.evm.StateDB.GetCodeSize(common.BigToAddress(slot)))) + slot.SetUint64(uint64(interpreter.evm.StateDB.GetCodeSize(common.BigToAddress(slot), false))) return nil, nil } @@ -528,7 +528,7 @@ func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contract, // for EOAs that are not validators, statedb returns nil code = nil } else { - code = interpreter.evm.StateDB.GetCode(addr) + code = interpreter.evm.StateDB.GetCode(addr, false) } codeCopy := getDataBig(code, codeOffset, length) memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy) diff --git a/core/vm/interface.go b/core/vm/interface.go index 3e3994eda..3b481fd69 100644 --- a/core/vm/interface.go +++ b/core/vm/interface.go @@ -38,9 +38,9 @@ type StateDB interface { SetNonce(common.Address, uint64) GetCodeHash(common.Address) common.Hash - GetCode(common.Address) []byte - SetCode(common.Address, []byte) - GetCodeSize(common.Address) int + GetCode(common.Address, bool) []byte + SetCode(common.Address, []byte, bool) + GetCodeSize(common.Address, bool) int ValidatorWrapper(common.Address, bool, bool) (*staking.ValidatorWrapper, error) UpdateValidatorWrapper(common.Address, *staking.ValidatorWrapper) error diff --git a/core/vm/logger_test.go b/core/vm/logger_test.go index 01db3293b..191733eed 100644 --- a/core/vm/logger_test.go +++ b/core/vm/logger_test.go @@ -28,10 +28,10 @@ type dummyContractRef struct { calledForEach bool } -func (dummyContractRef) ReturnGas(*big.Int) {} -func (dummyContractRef) Address() common.Address { return common.Address{} } -func (dummyContractRef) Value() *big.Int { return new(big.Int) } -func (dummyContractRef) SetCode(common.Hash, []byte) {} +func (dummyContractRef) ReturnGas(*big.Int) {} +func (dummyContractRef) Address() common.Address { return common.Address{} } +func (dummyContractRef) Value() *big.Int { return new(big.Int) } +func (dummyContractRef) SetCode(common.Hash, []byte, bool) {} func (d *dummyContractRef) ForEachStorage(callback func(key, value common.Hash) bool) { d.calledForEach = true } diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go index 5595866da..d60883a97 100644 --- a/core/vm/runtime/runtime.go +++ b/core/vm/runtime/runtime.go @@ -112,7 +112,7 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.DB, error) { ) cfg.State.CreateAccount(address) // set the receiver's (the executing contract) code for execution. - cfg.State.SetCode(address, code) + cfg.State.SetCode(address, code, false) // Call the code with the given configuration. ret, _, err := vmenv.Call( sender, diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go index a4f86ed8b..1ad8d1976 100644 --- a/core/vm/runtime/runtime_test.go +++ b/core/vm/runtime/runtime_test.go @@ -105,7 +105,7 @@ func TestCall(t *testing.T) { byte(vm.PUSH1), 32, byte(vm.PUSH1), 0, byte(vm.RETURN), - }) + }, false) ret, _, err := Call(address, nil, &Config{State: state}) if err != nil { @@ -158,7 +158,7 @@ func benchmarkEVMCreate(bench *testing.B, code string) { ) statedb.CreateAccount(sender) - statedb.SetCode(receiver, common.FromHex(code)) + statedb.SetCode(receiver, common.FromHex(code), false) runtimeConfig := Config{ Origin: sender, State: statedb, diff --git a/hmy/tracers/block_tracer.go b/hmy/tracers/block_tracer.go index 12391c6fb..daaf4171d 100644 --- a/hmy/tracers/block_tracer.go +++ b/hmy/tracers/block_tracer.go @@ -353,7 +353,7 @@ func (jst *ParityBlockTracer) CaptureState(env *vm.EVM, pc uint64, op vm.OpCode, ret := stackPeek(0) if ret.Sign() != 0 { call.to = common.BigToAddress(ret) - call.output = env.StateDB.GetCode(call.to) + call.output = env.StateDB.GetCode(call.to, false) } else if call.err == nil { call.err = errors.New("internal failure") } diff --git a/hmy/tracers/tracer.go b/hmy/tracers/tracer.go index bc349a514..69d52e3fd 100644 --- a/hmy/tracers/tracer.go +++ b/hmy/tracers/tracer.go @@ -210,7 +210,7 @@ func (dw *dbWrapper) pushObject(vm *duktape.Context) { // Push the wrapper for statedb.GetCode vm.PushGoFunction(func(ctx *duktape.Context) int { - code := dw.db.GetCode(common.BytesToAddress(popSlice(ctx))) + code := dw.db.GetCode(common.BytesToAddress(popSlice(ctx)), false) ptr := ctx.PushFixedBuffer(len(code)) copy(makeSlice(ptr, uint(len(code))), code) diff --git a/rosetta/services/block.go b/rosetta/services/block.go index c488c5ff9..8a939b108 100644 --- a/rosetta/services/block.go +++ b/rosetta/services/block.go @@ -178,11 +178,11 @@ func (s *BlockAPI) BlockTransaction( // check for contract related operations, if it is a plain transaction. if txInfo.tx.To() != nil { // possible call to existing contract so fetch relevant data - contractInfo.ContractCode = state.GetCode(*txInfo.tx.To()) + contractInfo.ContractCode = state.GetCode(*txInfo.tx.To(), false) contractInfo.ContractAddress = txInfo.tx.To() } else { // contract creation, so address is in receipt - contractInfo.ContractCode = state.GetCode(txInfo.receipt.ContractAddress) + contractInfo.ContractCode = state.GetCode(txInfo.receipt.ContractAddress, false) contractInfo.ContractAddress = &txInfo.receipt.ContractAddress } contractInfo.ExecutionResult, rosettaError = s.getTransactionTrace(ctx, blk, txInfo) diff --git a/rosetta/services/construction_check.go b/rosetta/services/construction_check.go index c842770ab..d08ed6e8f 100644 --- a/rosetta/services/construction_check.go +++ b/rosetta/services/construction_check.go @@ -289,7 +289,7 @@ func (s *ConstructAPI) ConstructionMetadata( GasPrice: sugNativePrice, GasLimit: estGasUsed, Transaction: options.TransactionMetadata, - ContractCode: state.GetCode(contractAddress), + ContractCode: state.GetCode(contractAddress, false), EvmErrorMessage: evmErrorMsg, EvmReturn: evmReturn, }) diff --git a/rpc/contract.go b/rpc/contract.go index abcb4f941..daed35edd 100644 --- a/rpc/contract.go +++ b/rpc/contract.go @@ -123,7 +123,7 @@ func (s *PublicContractService) GetCode( DoMetricRPCQueryInfo(GetCode, FailedNumber) return nil, err } - code := state.GetCode(address) + code := state.GetCode(address, false) // Response output is the same for all versions return code, state.Error() diff --git a/staking/availability/measure_test.go b/staking/availability/measure_test.go index 8f0f502b1..9a35ad80e 100644 --- a/staking/availability/measure_test.go +++ b/staking/availability/measure_test.go @@ -434,8 +434,8 @@ func (ctx *incStateTestCtx) checkAddrIncStateByType(addr common.Address, typeInc // checkHmyNodeStateChangeByAddr checks the state change for hmy nodes. Since hmy nodes does not // have wrapper, it is supposed to be unchanged in code field func (ctx *incStateTestCtx) checkHmyNodeStateChangeByAddr(addr common.Address) error { - snapCode := ctx.snapState.GetCode(addr) - curCode := ctx.state.GetCode(addr) + snapCode := ctx.snapState.GetCode(addr, false) + curCode := ctx.state.GetCode(addr, false) if !reflect.DeepEqual(snapCode, curCode) { return errors.New("code not expected") } @@ -618,7 +618,7 @@ func (state testStateDB) UpdateValidatorWrapper(addr common.Address, wrapper *st return nil } -func (state testStateDB) GetCode(addr common.Address) []byte { +func (state testStateDB) GetCode(addr common.Address, isValidatorCode bool) []byte { wrapper, ok := state[addr] if !ok { return nil