mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-30 00:23:46 +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 {
|
||||
vm.EVMLogger
|
||||
state.StateLogger
|
||||
CaptureBlockStart(*types.Block)
|
||||
CaptureBlockEnd()
|
||||
OnGenesisBlock(*types.Block)
|
||||
}
|
||||
|
||||
// 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
|
||||
// to database if the genesis block is not present yet, or load the
|
||||
// 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 {
|
||||
return nil, genesisErr
|
||||
}
|
||||
|
|
@ -1739,6 +1742,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
|
|||
if err != nil {
|
||||
return it.index, err
|
||||
}
|
||||
statedb.SetLogger(bc.logger)
|
||||
|
||||
// Enable prefetching to pull in trie node paths while processing transactions
|
||||
statedb.StartPrefetcher("chain")
|
||||
|
|
|
|||
|
|
@ -350,7 +350,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
|
|||
// then generate chain on top.
|
||||
func GenerateChainWithGenesis(genesis *Genesis, engine consensus.Engine, n int, gen func(int, *BlockGen)) (ethdb.Database, []*types.Block, []types.Receipts) {
|
||||
db := rawdb.NewMemoryDatabase()
|
||||
_, err := genesis.Commit(db, trie.NewDatabase(db))
|
||||
_, err := genesis.Commit(db, trie.NewDatabase(db), nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -138,8 +138,9 @@ func (ga *GenesisAlloc) deriveHash() (common.Hash, error) {
|
|||
// flush is very similar with deriveHash, but the main difference is
|
||||
// all the generated states will be persisted into the given database.
|
||||
// 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.SetLogger(bcLogger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -200,7 +201,7 @@ func CommitGenesisState(db ethdb.Database, triedb *trie.Database, blockhash comm
|
|||
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.
|
||||
|
|
@ -282,10 +283,10 @@ type ChainOverrides struct {
|
|||
//
|
||||
// The returned chain configuration is never nil.
|
||||
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 {
|
||||
return params.AllEthashProtocolChanges, common.Hash{}, errGenesisNoConfig
|
||||
}
|
||||
|
|
@ -305,7 +306,7 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *trie.Database, gen
|
|||
} else {
|
||||
log.Info("Writing custom genesis block")
|
||||
}
|
||||
block, err := genesis.Commit(db, triedb)
|
||||
block, err := genesis.Commit(db, triedb, bcLogger)
|
||||
if err != nil {
|
||||
return genesis.Config, common.Hash{}, err
|
||||
}
|
||||
|
|
@ -324,7 +325,7 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *trie.Database, gen
|
|||
if hash != stored {
|
||||
return genesis.Config, hash, &GenesisMismatchError{stored, hash}
|
||||
}
|
||||
block, err := genesis.Commit(db, triedb)
|
||||
block, err := genesis.Commit(db, triedb, bcLogger)
|
||||
if err != nil {
|
||||
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.
|
||||
// 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()
|
||||
if block.Number().Sign() != 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 {
|
||||
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
|
||||
// specification as well as the specification itself into the provided
|
||||
// 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
|
||||
}
|
||||
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
|
||||
// if path-scheme is preferred.
|
||||
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 {
|
||||
panic(err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -236,6 +236,9 @@ func (s *stateObject) SetState(db Database, key, value common.Hash) {
|
|||
key: key,
|
||||
prevalue: prev,
|
||||
})
|
||||
if s.db.logger != nil {
|
||||
s.db.logger.OnStorageChange(s.address, key, prev, value)
|
||||
}
|
||||
s.setState(key, value)
|
||||
}
|
||||
|
||||
|
|
@ -399,6 +402,9 @@ func (s *stateObject) SetBalance(amount *big.Int) {
|
|||
account: &s.address,
|
||||
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)
|
||||
}
|
||||
|
||||
|
|
@ -470,6 +476,9 @@ func (s *stateObject) SetCode(codeHash common.Hash, code []byte) {
|
|||
prevhash: s.CodeHash(),
|
||||
prevcode: prevcode,
|
||||
})
|
||||
if s.db.logger != nil {
|
||||
s.db.logger.OnCodeChange(s.address, common.BytesToHash(s.CodeHash()), prevcode, codeHash, code)
|
||||
}
|
||||
s.setCode(codeHash, code)
|
||||
}
|
||||
|
||||
|
|
@ -484,6 +493,9 @@ func (s *stateObject) SetNonce(nonce uint64) {
|
|||
account: &s.address,
|
||||
prev: s.data.Nonce,
|
||||
})
|
||||
if s.db.logger != nil {
|
||||
s.db.logger.OnNonceChange(s.address, s.data.Nonce, nonce)
|
||||
}
|
||||
s.setNonce(nonce)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -53,6 +53,13 @@ func (n *proofList) Delete(key []byte) error {
|
|||
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
|
||||
// within the merkle trie. StateDBs take care of caching and storing
|
||||
// nested states. It's the general query interface to retrieve:
|
||||
|
|
@ -63,6 +70,7 @@ type StateDB struct {
|
|||
prefetcher *triePrefetcher
|
||||
trie Trie
|
||||
hasher crypto.KeccakState
|
||||
logger StateLogger
|
||||
|
||||
// originalRoot is the pre-state root, before any changes were made.
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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
|
||||
// state trie concurrently while the state is mutated so that when we reach the
|
||||
// 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() {
|
||||
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 {
|
||||
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 {
|
||||
return nil, genesisErr
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue