mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-25 22:26:42 +00:00
core, miner: ChainFork as BlockReader. Updated VM Env to use reader fn
ChainFork is now usable as a BlockReader interface and can be used to read out chain data. The VM Env is now taking a block-number-to-hash function instead of BlockChain to create a block-number-to-hash internally. This makes it slightly more flexible to use and allows us to pass around the ChainFork NumToHash method.
This commit is contained in:
parent
7d5e2443e2
commit
888b5c706e
11 changed files with 63 additions and 30 deletions
|
|
@ -120,7 +120,7 @@ func (b *SimulatedBackend) ContractCall(contract common.Address, data []byte, pe
|
|||
data: data,
|
||||
}
|
||||
// Execute the call and return
|
||||
vmenv := core.NewEnv(statedb, chainConfig, b.blockchain, msg, block.Header(), vm.Config{})
|
||||
vmenv := core.NewEnv(statedb, chainConfig, core.GetHashFn(block.ParentHash(), b.blockchain), msg, block.Header(), vm.Config{})
|
||||
gaspool := new(core.GasPool).AddGas(common.MaxBig)
|
||||
|
||||
out, _, err := core.ApplyMessage(vmenv, msg, gaspool)
|
||||
|
|
@ -168,7 +168,7 @@ func (b *SimulatedBackend) EstimateGasLimit(sender common.Address, contract *com
|
|||
data: data,
|
||||
}
|
||||
// Execute the call and return
|
||||
vmenv := core.NewEnv(statedb, chainConfig, b.blockchain, msg, block.Header(), vm.Config{})
|
||||
vmenv := core.NewEnv(statedb, chainConfig, core.GetHashFn(block.ParentHash(), b.blockchain), msg, block.Header(), vm.Config{})
|
||||
gaspool := new(core.GasPool).AddGas(common.MaxBig)
|
||||
|
||||
_, gas, _, err := core.NewStateTransition(vmenv, msg, gaspool).TransitionDb()
|
||||
|
|
|
|||
|
|
@ -191,7 +191,7 @@ func (be *registryAPIBackend) Call(fromStr, toStr, valueStr, gasStr, gasPriceStr
|
|||
}
|
||||
|
||||
header := be.bc.CurrentBlock().Header()
|
||||
vmenv := core.NewEnv(statedb, be.config, be.bc, msg, header, vm.Config{})
|
||||
vmenv := core.NewEnv(statedb, be.config, core.GetHashFn(header.ParentHash, be.bc), msg, header, vm.Config{})
|
||||
gp := new(core.GasPool).AddGas(common.MaxBig)
|
||||
res, gas, err := core.ApplyMessage(vmenv, msg, gp)
|
||||
|
||||
|
|
|
|||
|
|
@ -162,6 +162,11 @@ func NewBlockChain(chainDb ethdb.Database, config *ChainConfig, pow pow.PoW, mux
|
|||
return bc, nil
|
||||
}
|
||||
|
||||
// XXX temporary
|
||||
func (self *BlockChain) Db() ethdb.Database {
|
||||
return self.chainDb
|
||||
}
|
||||
|
||||
func (self *BlockChain) getProcInterrupt() bool {
|
||||
return atomic.LoadInt32(&self.procInterrupt) == 1
|
||||
}
|
||||
|
|
@ -896,7 +901,7 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
|
|||
return i, err
|
||||
}
|
||||
// Process block using the parent state as reference point.
|
||||
receipts, logs, usedGas, err := self.processor.Process(block, statedb, self.config.VmConfig)
|
||||
receipts, logs, usedGas, err := self.processor.Process(GetHashFn(block.ParentHash(), self), block, statedb, self.config.VmConfig)
|
||||
if err != nil {
|
||||
reportBlock(block, err)
|
||||
return i, err
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
receipts, _, usedGas, err := blockchain.Processor().Process(block, statedb, vm.Config{})
|
||||
receipts, _, usedGas, err := blockchain.Processor().Process(GetHashFn(block.ParentHash(), blockchain), block, statedb, vm.Config{})
|
||||
if err != nil {
|
||||
reportBlock(block, err)
|
||||
return err
|
||||
|
|
@ -435,7 +435,7 @@ func (bproc) ValidateHeader(*types.Header, *types.Header, bool) error { return n
|
|||
func (bproc) ValidateState(block, parent *types.Block, state *state.StateDB, receipts types.Receipts, usedGas *big.Int) error {
|
||||
return nil
|
||||
}
|
||||
func (bproc) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, vm.Logs, *big.Int, error) {
|
||||
func (bproc) Process(getHashFn BlockNoToHashFn, block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, vm.Logs, *big.Int, error) {
|
||||
return nil, nil, nil, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
31
core/fork.go
31
core/fork.go
|
|
@ -69,16 +69,18 @@ type ChainFork struct {
|
|||
origin *types.Block // origin notes the start of the fork
|
||||
currentBlock *types.Block // the current block within this transaction
|
||||
|
||||
changes []Changes // changes
|
||||
changes []Changes // changes
|
||||
hashToIdx map[common.Hash]int // mapping from block hash to array changes index
|
||||
}
|
||||
|
||||
// Fork returns a new blockchain with the given database as backing layer
|
||||
// for the localised blockchain transaction.
|
||||
func Fork(config *ChainConfig, blockReader BlockReader, origin common.Hash) (*ChainFork, error) {
|
||||
fork := &ChainFork{
|
||||
db: blockReader.Db(),
|
||||
reader: blockReader,
|
||||
config: config,
|
||||
db: blockReader.Db(),
|
||||
reader: blockReader,
|
||||
config: config,
|
||||
hashToIdx: make(map[common.Hash]int),
|
||||
}
|
||||
|
||||
// get the origin block from which this fork originates
|
||||
|
|
@ -120,10 +122,30 @@ func (fork *ChainFork) GetNumHash(n uint64) common.Hash {
|
|||
return common.Hash{}
|
||||
}
|
||||
|
||||
// State returns the current pending state of the fork. This state is re-used throughout the entire
|
||||
// session of the fork.
|
||||
func (fork *ChainFork) State() *state.StateDB {
|
||||
return fork.state
|
||||
}
|
||||
|
||||
// GetBlock returns the block within the fork that corresponds to the given hash. If the
|
||||
// block is not found within the fork nil will be returned -- this is subject to change
|
||||
// and might include blocks that lay outside of the fork, in the future.
|
||||
func (fork *ChainFork) GetBlock(hash common.Hash) *types.Block {
|
||||
if len(fork.changes) == 0 {
|
||||
if fork.origin.Hash() == hash {
|
||||
return fork.origin
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if idx, ok := fork.hashToIdx[hash]; ok {
|
||||
return fork.changes[idx].block
|
||||
}
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
// CommitBlock commits a new block to the fork. The block that's being commited their parent hash must
|
||||
// match the previously committed block or the origin if the fork is empty.
|
||||
func (fork *ChainFork) CommitBlock(td *big.Int, block *types.Block, receipts types.Receipts) error {
|
||||
|
|
@ -135,6 +157,7 @@ func (fork *ChainFork) CommitBlock(td *big.Int, block *types.Block, receipts typ
|
|||
return errUnboundedParent
|
||||
}
|
||||
|
||||
fork.hashToIdx[block.Hash()] = len(fork.changes)
|
||||
fork.changes = append(fork.changes, Changes{
|
||||
td: td,
|
||||
block: block,
|
||||
|
|
|
|||
|
|
@ -59,5 +59,10 @@ func TestGetNumHash(t *testing.T) {
|
|||
if fork.GetNumHash(fork.originN+i+1) != blocks[i].Block.Hash() {
|
||||
t.Errorf("%d failed: expected %x got %x", i, fork.GetNumHash(fork.originN+i+1), blocks[i].Block.Hash())
|
||||
}
|
||||
|
||||
idx := fork.hashToIdx[blocks[i].Block.Hash()]
|
||||
if uint64(idx) != i {
|
||||
t.Errorf("%d failed: expected hash %x to map to %d got %d", i, blocks[i].Block.Hash(), i, idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ func NewStateProcessor(config *ChainConfig, bc *BlockChain) *StateProcessor {
|
|||
// Process returns the receipts and logs accumulated during the process and
|
||||
// returns the amount of gas that was used in the process. If any of the
|
||||
// transactions failed to execute due to insufficient gas it will return an error.
|
||||
func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, vm.Logs, *big.Int, error) {
|
||||
func (p *StateProcessor) Process(getHashFn BlockNoToHashFn, block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, vm.Logs, *big.Int, error) {
|
||||
var (
|
||||
receipts types.Receipts
|
||||
totalUsedGas = big.NewInt(0)
|
||||
|
|
@ -68,7 +68,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
|
|||
|
||||
for i, tx := range block.Transactions() {
|
||||
statedb.StartRecord(tx.Hash(), block.Hash(), i)
|
||||
receipt, logs, _, err := ApplyTransaction(p.config, p.bc, gp, statedb, header, tx, totalUsedGas, cfg)
|
||||
receipt, logs, _, err := ApplyTransaction(p.config, getHashFn, gp, statedb, header, tx, totalUsedGas, cfg)
|
||||
if err != nil {
|
||||
return nil, nil, totalUsedGas, err
|
||||
}
|
||||
|
|
@ -85,8 +85,8 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
|
|||
//
|
||||
// ApplyTransactions returns the generated receipts and vm logs during the
|
||||
// execution of the state transition phase.
|
||||
func ApplyTransaction(config *ChainConfig, bc *BlockChain, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *big.Int, cfg vm.Config) (*types.Receipt, vm.Logs, *big.Int, error) {
|
||||
_, gas, err := ApplyMessage(NewEnv(statedb, config, bc, tx, header, cfg), tx, gp)
|
||||
func ApplyTransaction(config *ChainConfig, getHashFn BlockNoToHashFn, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *big.Int, cfg vm.Config) (*types.Receipt, vm.Logs, *big.Int, error) {
|
||||
_, gas, err := ApplyMessage(NewEnv(statedb, config, getHashFn, tx, header, cfg), tx, gp)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ type HeaderValidator interface {
|
|||
// of gas used in the process and return an error if any of the internal rules
|
||||
// failed.
|
||||
type Processor interface {
|
||||
Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, vm.Logs, *big.Int, error)
|
||||
Process(getHashFn BlockNoToHashFn, block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, vm.Logs, *big.Int, error)
|
||||
}
|
||||
|
||||
// Backend is an interface defining the basic functionality for an operable node
|
||||
|
|
|
|||
|
|
@ -28,9 +28,9 @@ import (
|
|||
// GetHashFn returns a function for which the VM env can query block hashes through
|
||||
// up to the limit defined by the Yellow Paper and uses the given block chain
|
||||
// to query for information.
|
||||
func GetHashFn(ref common.Hash, chain *BlockChain) func(n uint64) common.Hash {
|
||||
func GetHashFn(ref common.Hash, bc *BlockChain) func(n uint64) common.Hash {
|
||||
return func(n uint64) common.Hash {
|
||||
for block := chain.GetBlock(ref); block != nil; block = chain.GetBlock(block.ParentHash()) {
|
||||
for block := bc.GetBlock(ref); block != nil; block = bc.GetBlock(block.ParentHash()) {
|
||||
if block.NumberU64() == n {
|
||||
return block.Hash()
|
||||
}
|
||||
|
|
@ -47,20 +47,20 @@ type VMEnv struct {
|
|||
depth int // Current execution depth
|
||||
msg Message // Message appliod
|
||||
|
||||
header *types.Header // Header information
|
||||
chain *BlockChain // Blockchain handle
|
||||
logs []vm.StructLog // Logs for the custom structured logger
|
||||
getHashFn func(uint64) common.Hash // getHashFn callback is used to retrieve block hashes
|
||||
header *types.Header // Header information
|
||||
logs []vm.StructLog // Logs for the custom structured logger
|
||||
getHashFn BlockNoToHashFn // getHashFn callback is used to retrieve block hashes
|
||||
}
|
||||
|
||||
func NewEnv(state *state.StateDB, chainConfig *ChainConfig, chain *BlockChain, msg Message, header *types.Header, cfg vm.Config) *VMEnv {
|
||||
type BlockNoToHashFn func(n uint64) common.Hash
|
||||
|
||||
func NewEnv(state *state.StateDB, chainConfig *ChainConfig, getHashFn BlockNoToHashFn, msg Message, header *types.Header, cfg vm.Config) *VMEnv {
|
||||
env := &VMEnv{
|
||||
chainConfig: chainConfig,
|
||||
chain: chain,
|
||||
state: state,
|
||||
header: header,
|
||||
msg: msg,
|
||||
getHashFn: GetHashFn(header.ParentHash, chain),
|
||||
getHashFn: getHashFn, //GetHashFn(header.ParentHash, reader),
|
||||
}
|
||||
|
||||
// if no log collector is present set self as the collector
|
||||
|
|
|
|||
10
eth/api.go
10
eth/api.go
|
|
@ -777,7 +777,7 @@ func (s *PublicBlockChainAPI) doCall(args CallArgs, blockNr rpc.BlockNumber) (st
|
|||
}
|
||||
|
||||
// Execute the call and return
|
||||
vmenv := core.NewEnv(stateDb, s.config, s.bc, msg, block.Header(), s.config.VmConfig)
|
||||
vmenv := core.NewEnv(stateDb, s.config, core.GetHashFn(block.ParentHash(), s.bc), msg, block.Header(), s.config.VmConfig)
|
||||
gp := new(core.GasPool).AddGas(common.MaxBig)
|
||||
|
||||
res, requiredGas, _, err := core.NewStateTransition(vmenv, msg, gp).TransitionDb()
|
||||
|
|
@ -1753,7 +1753,7 @@ func (api *PrivateDebugAPI) traceBlock(block *types.Block, config *vm.Config) (b
|
|||
return false, collector.traces, err
|
||||
}
|
||||
|
||||
receipts, _, usedGas, err := processor.Process(block, statedb, *config)
|
||||
receipts, _, usedGas, err := processor.Process(core.GetHashFn(block.ParentHash(), api.eth.BlockChain()), block, statedb, *config)
|
||||
if err != nil {
|
||||
return false, collector.traces, err
|
||||
}
|
||||
|
|
@ -1871,7 +1871,7 @@ func (api *PrivateDebugAPI) TraceTransaction(txHash common.Hash, logger *vm.LogC
|
|||
}
|
||||
// Mutate the state if we haven't reached the tracing transaction yet
|
||||
if uint64(idx) < txIndex {
|
||||
vmenv := core.NewEnv(stateDb, api.config, api.eth.BlockChain(), msg, block.Header(), vm.Config{})
|
||||
vmenv := core.NewEnv(stateDb, api.config, core.GetHashFn(block.ParentHash(), api.eth.BlockChain()), msg, block.Header(), vm.Config{})
|
||||
_, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas()))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("mutation failed: %v", err)
|
||||
|
|
@ -1879,7 +1879,7 @@ func (api *PrivateDebugAPI) TraceTransaction(txHash common.Hash, logger *vm.LogC
|
|||
continue
|
||||
}
|
||||
// Otherwise trace the transaction and return
|
||||
vmenv := core.NewEnv(stateDb, api.config, api.eth.BlockChain(), msg, block.Header(), vm.Config{Debug: true, Logger: *logger})
|
||||
vmenv := core.NewEnv(stateDb, api.config, core.GetHashFn(block.ParentHash(), api.eth.BlockChain()), msg, block.Header(), vm.Config{Debug: true, Logger: *logger})
|
||||
ret, gas, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas()))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("tracing failed: %v", err)
|
||||
|
|
@ -1933,7 +1933,7 @@ func (s *PublicBlockChainAPI) TraceCall(args CallArgs, blockNr rpc.BlockNumber)
|
|||
}
|
||||
|
||||
// Execute the call and return
|
||||
vmenv := core.NewEnv(stateDb, s.config, s.bc, msg, block.Header(), vm.Config{
|
||||
vmenv := core.NewEnv(stateDb, s.config, core.GetHashFn(block.ParentHash(), s.bc), msg, block.Header(), vm.Config{
|
||||
Debug: true,
|
||||
})
|
||||
gp := new(core.GasPool).AddGas(common.MaxBig)
|
||||
|
|
|
|||
|
|
@ -656,7 +656,7 @@ func (env *Work) commitTransaction(tx *types.Transaction, bc *core.BlockChain, g
|
|||
}
|
||||
config.ForceJit = false // disable forcing jit
|
||||
|
||||
receipt, logs, _, err := core.ApplyTransaction(env.config, bc, gp, env.state, env.header, tx, env.header.GasUsed, config)
|
||||
receipt, logs, _, err := core.ApplyTransaction(env.config, core.GetHashFn(env.header.ParentHash, bc), gp, env.state, env.header, tx, env.header.GasUsed, config)
|
||||
if err != nil {
|
||||
env.state.Set(snap)
|
||||
return err, nil
|
||||
|
|
|
|||
Loading…
Reference in a new issue