mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-14 16:03:45 +00:00
add hooks to state object & genesis
This commit is contained in:
parent
e25065bfc3
commit
f67ac095a6
7 changed files with 65 additions and 12 deletions
|
|
@ -155,8 +155,10 @@ var defaultCacheConfig = &CacheConfig{
|
||||||
|
|
||||||
type BlockchainLogger interface {
|
type BlockchainLogger interface {
|
||||||
vm.EVMLogger
|
vm.EVMLogger
|
||||||
|
state.StateLogger
|
||||||
CaptureBlockStart(*types.Block)
|
CaptureBlockStart(*types.Block)
|
||||||
CaptureBlockEnd()
|
CaptureBlockEnd()
|
||||||
|
OnGenesisBlock(*types.Block)
|
||||||
}
|
}
|
||||||
|
|
||||||
// BlockChain represents the canonical chain given a database with a genesis
|
// BlockChain represents the canonical chain given a database with a genesis
|
||||||
|
|
@ -251,7 +253,8 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
|
||||||
// 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
|
||||||
// stored one from database.
|
// stored one from database.
|
||||||
chainConfig, genesisHash, genesisErr := SetupGenesisBlockWithOverride(db, triedb, genesis, overrides)
|
// TODO: pass in blockchainLogger here to catch genesis block and allocs
|
||||||
|
chainConfig, genesisHash, genesisErr := SetupGenesisBlockWithOverride(db, triedb, genesis, overrides, nil)
|
||||||
if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok {
|
if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok {
|
||||||
return nil, genesisErr
|
return nil, genesisErr
|
||||||
}
|
}
|
||||||
|
|
@ -1739,6 +1742,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return it.index, err
|
return it.index, err
|
||||||
}
|
}
|
||||||
|
statedb.SetLogger(bc.logger)
|
||||||
|
|
||||||
// Enable prefetching to pull in trie node paths while processing transactions
|
// Enable prefetching to pull in trie node paths while processing transactions
|
||||||
statedb.StartPrefetcher("chain")
|
statedb.StartPrefetcher("chain")
|
||||||
|
|
|
||||||
|
|
@ -350,7 +350,7 @@ 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()
|
||||||
_, err := genesis.Commit(db, trie.NewDatabase(db))
|
_, err := genesis.Commit(db, trie.NewDatabase(db), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -138,8 +138,9 @@ func (ga *GenesisAlloc) deriveHash() (common.Hash, error) {
|
||||||
// flush is very similar with deriveHash, but the main difference is
|
// flush is very similar with deriveHash, but the main difference is
|
||||||
// all the generated states will be persisted into the given database.
|
// all the generated states will be persisted into the given database.
|
||||||
// Also, the genesis state specification will be flushed as well.
|
// Also, the genesis state specification will be flushed as well.
|
||||||
func (ga *GenesisAlloc) flush(db ethdb.Database, triedb *trie.Database, blockhash common.Hash) error {
|
func (ga *GenesisAlloc) flush(db ethdb.Database, triedb *trie.Database, blockhash common.Hash, bcLogger BlockchainLogger) error {
|
||||||
statedb, err := state.New(types.EmptyRootHash, state.NewDatabaseWithNodeDB(db, triedb), nil)
|
statedb, err := state.New(types.EmptyRootHash, state.NewDatabaseWithNodeDB(db, triedb), nil)
|
||||||
|
statedb.SetLogger(bcLogger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -200,7 +201,7 @@ func CommitGenesisState(db ethdb.Database, triedb *trie.Database, blockhash comm
|
||||||
return errors.New("not found")
|
return errors.New("not found")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return alloc.flush(db, triedb, blockhash)
|
return alloc.flush(db, triedb, blockhash, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenesisAccount is an account in the state of the genesis block.
|
// GenesisAccount is an account in the state of the genesis block.
|
||||||
|
|
@ -282,10 +283,10 @@ type ChainOverrides struct {
|
||||||
//
|
//
|
||||||
// The returned chain configuration is never nil.
|
// The returned chain configuration is never nil.
|
||||||
func SetupGenesisBlock(db ethdb.Database, triedb *trie.Database, genesis *Genesis) (*params.ChainConfig, common.Hash, error) {
|
func SetupGenesisBlock(db ethdb.Database, triedb *trie.Database, genesis *Genesis) (*params.ChainConfig, common.Hash, error) {
|
||||||
return SetupGenesisBlockWithOverride(db, triedb, genesis, nil)
|
return SetupGenesisBlockWithOverride(db, triedb, genesis, nil, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *trie.Database, genesis *Genesis, overrides *ChainOverrides) (*params.ChainConfig, common.Hash, error) {
|
func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *trie.Database, genesis *Genesis, overrides *ChainOverrides, bcLogger BlockchainLogger) (*params.ChainConfig, common.Hash, error) {
|
||||||
if genesis != nil && genesis.Config == nil {
|
if genesis != nil && genesis.Config == nil {
|
||||||
return params.AllEthashProtocolChanges, common.Hash{}, errGenesisNoConfig
|
return params.AllEthashProtocolChanges, common.Hash{}, errGenesisNoConfig
|
||||||
}
|
}
|
||||||
|
|
@ -305,7 +306,7 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *trie.Database, gen
|
||||||
} else {
|
} else {
|
||||||
log.Info("Writing custom genesis block")
|
log.Info("Writing custom genesis block")
|
||||||
}
|
}
|
||||||
block, err := genesis.Commit(db, triedb)
|
block, err := genesis.Commit(db, triedb, bcLogger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return genesis.Config, common.Hash{}, err
|
return genesis.Config, common.Hash{}, err
|
||||||
}
|
}
|
||||||
|
|
@ -324,7 +325,7 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *trie.Database, gen
|
||||||
if hash != stored {
|
if hash != stored {
|
||||||
return genesis.Config, hash, &GenesisMismatchError{stored, hash}
|
return genesis.Config, hash, &GenesisMismatchError{stored, hash}
|
||||||
}
|
}
|
||||||
block, err := genesis.Commit(db, triedb)
|
block, err := genesis.Commit(db, triedb, bcLogger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return genesis.Config, hash, err
|
return genesis.Config, hash, err
|
||||||
}
|
}
|
||||||
|
|
@ -468,7 +469,7 @@ 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, bcLogger BlockchainLogger) (*types.Block, error) {
|
||||||
block := g.ToBlock()
|
block := g.ToBlock()
|
||||||
if block.Number().Sign() != 0 {
|
if block.Number().Sign() != 0 {
|
||||||
return nil, errors.New("can't commit genesis block with number > 0")
|
return nil, errors.New("can't commit genesis block with number > 0")
|
||||||
|
|
@ -483,10 +484,13 @@ func (g *Genesis) Commit(db ethdb.Database, triedb *trie.Database) (*types.Block
|
||||||
if config.Clique != nil && len(block.Extra()) < 32+crypto.SignatureLength {
|
if config.Clique != nil && len(block.Extra()) < 32+crypto.SignatureLength {
|
||||||
return nil, errors.New("can't start clique chain without signers")
|
return nil, errors.New("can't start clique chain without signers")
|
||||||
}
|
}
|
||||||
|
if bcLogger != nil {
|
||||||
|
bcLogger.OnGenesisBlock(block)
|
||||||
|
}
|
||||||
// All the checks has passed, flush the states derived from the genesis
|
// All the checks has passed, flush the states derived from the genesis
|
||||||
// specification as well as the specification itself into the provided
|
// specification as well as the specification itself into the provided
|
||||||
// database.
|
// database.
|
||||||
if err := g.Alloc.flush(db, triedb, block.Hash()); err != nil {
|
if err := g.Alloc.flush(db, triedb, block.Hash(), bcLogger); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
rawdb.WriteTd(db, block.Hash(), block.NumberU64(), block.Difficulty())
|
rawdb.WriteTd(db, block.Hash(), block.NumberU64(), block.Difficulty())
|
||||||
|
|
@ -505,7 +509,7 @@ func (g *Genesis) Commit(db ethdb.Database, triedb *trie.Database) (*types.Block
|
||||||
// Note the state changes will be committed in hash-based scheme, use Commit
|
// Note the state changes will be committed in hash-based scheme, use Commit
|
||||||
// if path-scheme is preferred.
|
// if path-scheme is preferred.
|
||||||
func (g *Genesis) MustCommit(db ethdb.Database) *types.Block {
|
func (g *Genesis) MustCommit(db ethdb.Database) *types.Block {
|
||||||
block, err := g.Commit(db, trie.NewDatabase(db))
|
block, err := g.Commit(db, trie.NewDatabase(db), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -236,6 +236,9 @@ func (s *stateObject) SetState(db Database, key, value common.Hash) {
|
||||||
key: key,
|
key: key,
|
||||||
prevalue: prev,
|
prevalue: prev,
|
||||||
})
|
})
|
||||||
|
if s.db.logger != nil {
|
||||||
|
s.db.logger.OnStorageChange(s.address, key, prev, value)
|
||||||
|
}
|
||||||
s.setState(key, value)
|
s.setState(key, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -399,6 +402,9 @@ func (s *stateObject) SetBalance(amount *big.Int) {
|
||||||
account: &s.address,
|
account: &s.address,
|
||||||
prev: new(big.Int).Set(s.data.Balance),
|
prev: new(big.Int).Set(s.data.Balance),
|
||||||
})
|
})
|
||||||
|
if s.db.logger != nil {
|
||||||
|
s.db.logger.OnBalanceChange(s.address, s.Balance(), amount)
|
||||||
|
}
|
||||||
s.setBalance(amount)
|
s.setBalance(amount)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -470,6 +476,9 @@ func (s *stateObject) SetCode(codeHash common.Hash, code []byte) {
|
||||||
prevhash: s.CodeHash(),
|
prevhash: s.CodeHash(),
|
||||||
prevcode: prevcode,
|
prevcode: prevcode,
|
||||||
})
|
})
|
||||||
|
if s.db.logger != nil {
|
||||||
|
s.db.logger.OnCodeChange(s.address, common.BytesToHash(s.CodeHash()), prevcode, codeHash, code)
|
||||||
|
}
|
||||||
s.setCode(codeHash, code)
|
s.setCode(codeHash, code)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -484,6 +493,9 @@ func (s *stateObject) SetNonce(nonce uint64) {
|
||||||
account: &s.address,
|
account: &s.address,
|
||||||
prev: s.data.Nonce,
|
prev: s.data.Nonce,
|
||||||
})
|
})
|
||||||
|
if s.db.logger != nil {
|
||||||
|
s.db.logger.OnNonceChange(s.address, s.data.Nonce, nonce)
|
||||||
|
}
|
||||||
s.setNonce(nonce)
|
s.setNonce(nonce)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,13 @@ func (n *proofList) Delete(key []byte) error {
|
||||||
panic("not supported")
|
panic("not supported")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type StateLogger interface {
|
||||||
|
OnBalanceChange(addr common.Address, prev, new *big.Int)
|
||||||
|
OnNonceChange(addr common.Address, prev, new uint64)
|
||||||
|
OnCodeChange(addr common.Address, prevCodeHash common.Hash, prevCode []byte, codeHash common.Hash, code []byte)
|
||||||
|
OnStorageChange(addr common.Address, slot common.Hash, prev, new common.Hash)
|
||||||
|
}
|
||||||
|
|
||||||
// StateDB structs within the ethereum protocol are used to store anything
|
// StateDB structs within the ethereum protocol are used to store anything
|
||||||
// within the merkle trie. StateDBs take care of caching and storing
|
// within the merkle trie. StateDBs take care of caching and storing
|
||||||
// nested states. It's the general query interface to retrieve:
|
// nested states. It's the general query interface to retrieve:
|
||||||
|
|
@ -63,6 +70,7 @@ type StateDB struct {
|
||||||
prefetcher *triePrefetcher
|
prefetcher *triePrefetcher
|
||||||
trie Trie
|
trie Trie
|
||||||
hasher crypto.KeccakState
|
hasher crypto.KeccakState
|
||||||
|
logger StateLogger
|
||||||
|
|
||||||
// originalRoot is the pre-state root, before any changes were made.
|
// originalRoot is the pre-state root, before any changes were made.
|
||||||
// It will be updated when the Commit is called.
|
// It will be updated when the Commit is called.
|
||||||
|
|
@ -161,6 +169,11 @@ func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error)
|
||||||
return sdb, nil
|
return sdb, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: move to New
|
||||||
|
func (s *StateDB) SetLogger(l StateLogger) {
|
||||||
|
s.logger = l
|
||||||
|
}
|
||||||
|
|
||||||
// StartPrefetcher initializes a new trie prefetcher to pull in nodes from the
|
// StartPrefetcher initializes a new trie prefetcher to pull in nodes from the
|
||||||
// state trie concurrently while the state is mutated so that when we reach the
|
// state trie concurrently while the state is mutated so that when we reach the
|
||||||
// commit phase, most of the needed data is already hot.
|
// commit phase, most of the needed data is already hot.
|
||||||
|
|
|
||||||
|
|
@ -65,3 +65,23 @@ func (p *Printer) CaptureBlockStart(b *types.Block) {
|
||||||
func (p *Printer) CaptureBlockEnd() {
|
func (p *Printer) CaptureBlockEnd() {
|
||||||
fmt.Printf("CaptureBlockEnd\n")
|
fmt.Printf("CaptureBlockEnd\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Printer) OnGenesisBlock(b *types.Block) {
|
||||||
|
fmt.Printf("OnGenesisBlock: b=%v\n", b.NumberU64())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Printer) OnBalanceChange(a common.Address, prev, new *big.Int) {
|
||||||
|
fmt.Printf("OnBalanceChange: a=%v, prev=%v, new=%v\n", a, prev, new)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Printer) OnNonceChange(a common.Address, prev, new uint64) {
|
||||||
|
fmt.Printf("OnNonceChange: a=%v, prev=%v, new=%v\n", a, prev, new)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Printer) OnCodeChange(a common.Address, prevCodeHash common.Hash, prev []byte, codeHash common.Hash, code []byte) {
|
||||||
|
fmt.Printf("OnCodeChange: a=%v, prevCodeHash=%v, prev=%v, codeHash=%v, code=%v\n", a, prevCodeHash, prev, codeHash, code)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Printer) OnStorageChange(a common.Address, k, prev, new common.Hash) {
|
||||||
|
fmt.Printf("OnStorageChange: a=%v, k=%v, prev=%v, new=%v\n", a, k, prev, new)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -97,7 +97,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*LightEthereum, error) {
|
||||||
if config.OverrideCancun != nil {
|
if config.OverrideCancun != nil {
|
||||||
overrides.OverrideCancun = config.OverrideCancun
|
overrides.OverrideCancun = config.OverrideCancun
|
||||||
}
|
}
|
||||||
chainConfig, genesisHash, genesisErr := core.SetupGenesisBlockWithOverride(chainDb, trie.NewDatabase(chainDb), config.Genesis, &overrides)
|
chainConfig, genesisHash, genesisErr := core.SetupGenesisBlockWithOverride(chainDb, trie.NewDatabase(chainDb), config.Genesis, &overrides, nil)
|
||||||
if _, isCompat := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !isCompat {
|
if _, isCompat := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !isCompat {
|
||||||
return nil, genesisErr
|
return nil, genesisErr
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue