add state variable to verifyHeader(), verifyHeaders() in the consensus interface

This commit is contained in:
Tuna 2019-01-08 14:51:52 +07:00
parent c7144977e4
commit 206fcfd8b6
10 changed files with 86 additions and 62 deletions

View file

@ -33,7 +33,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/fdlimit" "github.com/ethereum/go-ethereum/common/fdlimit"
"github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/consensus/ethash" //"github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/consensus/posv" "github.com/ethereum/go-ethereum/consensus/posv"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
@ -1245,17 +1245,18 @@ func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chai
if config.Posv != nil { if config.Posv != nil {
engine = posv.New(config.Posv, chainDb) engine = posv.New(config.Posv, chainDb)
} else { } else {
engine = ethash.NewFaker() //engine = ethash.NewFaker()
if !ctx.GlobalBool(FakePoWFlag.Name) { //if !ctx.GlobalBool(FakePoWFlag.Name) {
engine = ethash.New(ethash.Config{ // engine = ethash.New(ethash.Config{
CacheDir: stack.ResolvePath(eth.DefaultConfig.Ethash.CacheDir), // CacheDir: stack.ResolvePath(eth.DefaultConfig.Ethash.CacheDir),
CachesInMem: eth.DefaultConfig.Ethash.CachesInMem, // CachesInMem: eth.DefaultConfig.Ethash.CachesInMem,
CachesOnDisk: eth.DefaultConfig.Ethash.CachesOnDisk, // CachesOnDisk: eth.DefaultConfig.Ethash.CachesOnDisk,
DatasetDir: stack.ResolvePath(eth.DefaultConfig.Ethash.DatasetDir), // DatasetDir: stack.ResolvePath(eth.DefaultConfig.Ethash.DatasetDir),
DatasetsInMem: eth.DefaultConfig.Ethash.DatasetsInMem, // DatasetsInMem: eth.DefaultConfig.Ethash.DatasetsInMem,
DatasetsOnDisk: eth.DefaultConfig.Ethash.DatasetsOnDisk, // DatasetsOnDisk: eth.DefaultConfig.Ethash.DatasetsOnDisk,
}) // })
} //}
Fatalf("Only support posv consensus")
} }
if gcmode := ctx.GlobalString(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" { if gcmode := ctx.GlobalString(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" {
Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name) Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name)

View file

@ -58,13 +58,13 @@ type Engine interface {
// VerifyHeader checks whether a header conforms to the consensus rules of a // VerifyHeader checks whether a header conforms to the consensus rules of a
// given engine. Verifying the seal may be done optionally here, or explicitly // given engine. Verifying the seal may be done optionally here, or explicitly
// via the VerifySeal method. // via the VerifySeal method.
VerifyHeader(chain ChainReader, header *types.Header, fullVerify bool) error VerifyHeader(chain ChainReader, state *state.StateDB, header *types.Header, fullVerify bool) error
// VerifyHeaders is similar to VerifyHeader, but verifies a batch of headers // VerifyHeaders is similar to VerifyHeader, but verifies a batch of headers
// concurrently. The method returns a quit channel to abort the operations and // concurrently. The method returns a quit channel to abort the operations and
// a results channel to retrieve the async verifications (the order is that of // a results channel to retrieve the async verifications (the order is that of
// the input slice). // the input slice).
VerifyHeaders(chain ChainReader, headers []*types.Header, seals []bool) (chan<- struct{}, <-chan error) VerifyHeaders(chain ChainReader, state *state.StateDB, headers []*types.Header, seals []bool) (chan<- struct{}, <-chan error)
// VerifyUncles verifies that the given block's uncles conform to the consensus // VerifyUncles verifies that the given block's uncles conform to the consensus
// rules of a given engine. // rules of a given engine.
@ -76,7 +76,7 @@ type Engine interface {
// Prepare initializes the consensus fields of a block header according to the // Prepare initializes the consensus fields of a block header according to the
// rules of a particular engine. The changes are executed inline. // rules of a particular engine. The changes are executed inline.
Prepare(chain ChainReader, header *types.Header) error Prepare(chain ChainReader, state *state.StateDB, header *types.Header) error
// Finalize runs any post-transaction state modifications (e.g. block rewards) // Finalize runs any post-transaction state modifications (e.g. block rewards)
// and assembles the final block. // and assembles the final block.

View file

@ -261,20 +261,20 @@ func (c *Posv) Author(header *types.Header) (common.Address, error) {
} }
// VerifyHeader checks whether a header conforms to the consensus rules. // VerifyHeader checks whether a header conforms to the consensus rules.
func (c *Posv) VerifyHeader(chain consensus.ChainReader, header *types.Header, fullVerify bool) error { func (c *Posv) VerifyHeader(chain consensus.ChainReader, state *state.StateDB, header *types.Header, fullVerify bool) error {
return c.verifyHeaderWithCache(chain, header, nil, fullVerify) return c.verifyHeaderWithCache(chain, state, header, nil, fullVerify)
} }
// VerifyHeaders is similar to VerifyHeader, but verifies a batch of headers. The // VerifyHeaders is similar to VerifyHeader, but verifies a batch of headers. The
// method returns a quit channel to abort the operations and a results channel to // method returns a quit channel to abort the operations and a results channel to
// retrieve the async verifications (the order is that of the input slice). // retrieve the async verifications (the order is that of the input slice).
func (c *Posv) VerifyHeaders(chain consensus.ChainReader, headers []*types.Header, fullVerifies []bool) (chan<- struct{}, <-chan error) { func (c *Posv) VerifyHeaders(chain consensus.ChainReader, state *state.StateDB, headers []*types.Header, fullVerifies []bool) (chan<- struct{}, <-chan error) {
abort := make(chan struct{}) abort := make(chan struct{})
results := make(chan error, len(headers)) results := make(chan error, len(headers))
go func() { go func() {
for i, header := range headers { for i, header := range headers {
err := c.verifyHeaderWithCache(chain, header, headers[:i], fullVerifies[i]) err := c.verifyHeaderWithCache(chain, state, header, headers[:i], fullVerifies[i])
select { select {
case <-abort: case <-abort:
@ -286,12 +286,12 @@ func (c *Posv) VerifyHeaders(chain consensus.ChainReader, headers []*types.Heade
return abort, results return abort, results
} }
func (c *Posv) verifyHeaderWithCache(chain consensus.ChainReader, header *types.Header, parents []*types.Header, fullVerify bool) error { func (c *Posv) verifyHeaderWithCache(chain consensus.ChainReader, state *state.StateDB, header *types.Header, parents []*types.Header, fullVerify bool) error {
_, check := c.verifiedHeaders.Get(header.Hash()) _, check := c.verifiedHeaders.Get(header.Hash())
if check { if check {
return nil return nil
} }
err := c.verifyHeader(chain, header, parents, fullVerify) err := c.verifyHeader(chain, state, header, parents, fullVerify)
if err == nil { if err == nil {
c.verifiedHeaders.Add(header.Hash(), true) c.verifiedHeaders.Add(header.Hash(), true)
} }
@ -302,7 +302,7 @@ func (c *Posv) verifyHeaderWithCache(chain consensus.ChainReader, header *types.
// caller may optionally pass in a batch of parents (ascending order) to avoid // caller may optionally pass in a batch of parents (ascending order) to avoid
// looking those up from the database. This is useful for concurrently verifying // looking those up from the database. This is useful for concurrently verifying
// a batch of new headers. // a batch of new headers.
func (c *Posv) verifyHeader(chain consensus.ChainReader, header *types.Header, parents []*types.Header, fullVerify bool) error { func (c *Posv) verifyHeader(chain consensus.ChainReader, state *state.StateDB, header *types.Header, parents []*types.Header, fullVerify bool) error {
if header.Number == nil { if header.Number == nil {
return errUnknownBlock return errUnknownBlock
} }
@ -357,14 +357,14 @@ func (c *Posv) verifyHeader(chain consensus.ChainReader, header *types.Header, p
return err return err
} }
// All basic checks passed, verify cascading fields // All basic checks passed, verify cascading fields
return c.verifyCascadingFields(chain, header, parents, fullVerify) return c.verifyCascadingFields(chain, state, header, parents, fullVerify)
} }
// verifyCascadingFields verifies all the header fields that are not standalone, // verifyCascadingFields verifies all the header fields that are not standalone,
// rather depend on a batch of previous headers. The caller may optionally pass // rather depend on a batch of previous headers. The caller may optionally pass
// in a batch of parents (ascending order) to avoid looking those up from the // in a batch of parents (ascending order) to avoid looking those up from the
// database. This is useful for concurrently verifying a batch of new headers. // database. This is useful for concurrently verifying a batch of new headers.
func (c *Posv) verifyCascadingFields(chain consensus.ChainReader, header *types.Header, parents []*types.Header, fullVerify bool) error { func (c *Posv) verifyCascadingFields(chain consensus.ChainReader, state *state.StateDB, header *types.Header, parents []*types.Header, fullVerify bool) error {
// The genesis block is the always valid dead-end // The genesis block is the always valid dead-end
number := header.Number.Uint64() number := header.Number.Uint64()
if number == 0 { if number == 0 {
@ -390,8 +390,6 @@ func (c *Posv) verifyCascadingFields(chain consensus.ChainReader, header *types.
} }
// If the block is a checkpoint block, verify the signer list // If the block is a checkpoint block, verify the signer list
if number%c.config.Epoch == 0 { if number%c.config.Epoch == 0 {
database := state.NewDatabase(c.db)
state, _ := state.New(parent.Hash(), database)
penPenalties := []common.Address{} penPenalties := []common.Address{}
if c.HookPenalty != nil { if c.HookPenalty != nil {
penPenalties, err = c.HookPenalty(state, chain, number) penPenalties, err = c.HookPenalty(state, chain, number)
@ -541,7 +539,7 @@ func (c *Posv) snapshot(chain consensus.ChainReader, number uint64, hash common.
// If we're at block zero, make a snapshot // If we're at block zero, make a snapshot
if number == 0 { if number == 0 {
genesis := chain.GetHeaderByNumber(0) genesis := chain.GetHeaderByNumber(0)
if err := c.VerifyHeader(chain, genesis, true); err != nil { if err := c.VerifyHeader(chain, nil, genesis, true); err != nil {
return nil, err return nil, err
} }
signers := make([]common.Address, (len(genesis.Extra)-extraVanity-extraSeal)/common.AddressLength) signers := make([]common.Address, (len(genesis.Extra)-extraVanity-extraSeal)/common.AddressLength)
@ -731,7 +729,7 @@ func (c *Posv) GetValidator(creator common.Address, chain consensus.ChainReader,
// Prepare implements consensus.Engine, preparing all the consensus fields of the // Prepare implements consensus.Engine, preparing all the consensus fields of the
// header for running the transactions on top. // header for running the transactions on top.
func (c *Posv) Prepare(chain consensus.ChainReader, header *types.Header) error { func (c *Posv) Prepare(chain consensus.ChainReader, state *state.StateDB, header *types.Header) error {
// If the block isn't a checkpoint, cast a random vote (good enough for now) // If the block isn't a checkpoint, cast a random vote (good enough for now)
header.Coinbase = common.Address{} header.Coinbase = common.Address{}
header.Nonce = types.BlockNonce{} header.Nonce = types.BlockNonce{}
@ -777,8 +775,6 @@ func (c *Posv) Prepare(chain consensus.ChainReader, header *types.Header) error
header.Extra = header.Extra[:extraVanity] header.Extra = header.Extra[:extraVanity]
masternodes := snap.GetSigners() masternodes := snap.GetSigners()
if number > 0 && number%c.config.Epoch == 0 { if number > 0 && number%c.config.Epoch == 0 {
database := state.NewDatabase(c.db)
state, _ := state.New(parent.Hash(), database)
if c.HookPenalty != nil { if c.HookPenalty != nil {
penMasternodes, err := c.HookPenalty(state, chain, number) penMasternodes, err := c.HookPenalty(state, chain, number)
if err != nil { if err != nil {

View file

@ -1069,7 +1069,11 @@ func (bc *BlockChain) insertChain(chain types.Blocks) (int, []interface{}, []*ty
seals[i] = true seals[i] = true
bc.downloadingBlock.Add(block.Hash(), true) bc.downloadingBlock.Add(block.Hash(), true)
} }
abort, results := bc.engine.VerifyHeaders(bc, headers, seals) st, err := bc.State()
if err != nil {
return 0, nil, nil, err
}
abort, results := bc.engine.VerifyHeaders(bc, st, headers, seals)
defer close(abort) defer close(abort)
// Iterate over the blocks and insert when the verifier permits // Iterate over the blocks and insert when the verifier permits
@ -1246,7 +1250,11 @@ func (bc *BlockChain) PrepareBlock(block *types.Block) (err error) {
log.Debug("Stop prepare a block because inserting", "number", block.NumberU64(), "hash", block.Hash(), "validator", block.Header().Validator) log.Debug("Stop prepare a block because inserting", "number", block.NumberU64(), "hash", block.Hash(), "validator", block.Header().Validator)
return nil return nil
} }
err = bc.engine.VerifyHeader(bc, block.Header(), false) state, err := bc.State()
if err != nil {
return err
}
err = bc.engine.VerifyHeader(bc, state, block.Header(), false)
if err != nil { if err != nil {
return err return err
} }
@ -1678,7 +1686,11 @@ Error: %v
// because nonces can be verified sparsely, not needing to check each. // because nonces can be verified sparsely, not needing to check each.
func (bc *BlockChain) InsertHeaderChain(chain []*types.Header, checkFreq int) (int, error) { func (bc *BlockChain) InsertHeaderChain(chain []*types.Header, checkFreq int) (int, error) {
start := time.Now() start := time.Now()
if i, err := bc.hc.ValidateHeaderChain(chain, checkFreq); err != nil { state, err := bc.State()
if err != nil {
return 0, err
}
if i, err := bc.hc.ValidateHeaderChain(chain, state, checkFreq); err != nil {
return i, err return i, err
} }

View file

@ -33,6 +33,7 @@ import (
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/hashicorp/golang-lru" "github.com/hashicorp/golang-lru"
"github.com/ethereum/go-ethereum/core/state"
) )
const ( const (
@ -203,7 +204,7 @@ func (hc *HeaderChain) WriteHeader(header *types.Header) (status WriteStatus, er
// header writes should be protected by the parent chain mutex individually. // header writes should be protected by the parent chain mutex individually.
type WhCallback func(*types.Header) error type WhCallback func(*types.Header) error
func (hc *HeaderChain) ValidateHeaderChain(chain []*types.Header, checkFreq int) (int, error) { func (hc *HeaderChain) ValidateHeaderChain(chain []*types.Header, state *state.StateDB, checkFreq int) (int, error) {
// Do a sanity check that the provided chain is actually ordered and linked // Do a sanity check that the provided chain is actually ordered and linked
for i := 1; i < len(chain); i++ { for i := 1; i < len(chain); i++ {
if chain[i].Number.Uint64() != chain[i-1].Number.Uint64()+1 || chain[i].ParentHash != chain[i-1].Hash() { if chain[i].Number.Uint64() != chain[i-1].Number.Uint64()+1 || chain[i].ParentHash != chain[i-1].Hash() {
@ -227,7 +228,7 @@ func (hc *HeaderChain) ValidateHeaderChain(chain []*types.Header, checkFreq int)
} }
seals[len(seals)-1] = true // Last should always be verified to avoid junk seals[len(seals)-1] = true // Last should always be verified to avoid junk
abort, results := hc.engine.VerifyHeaders(hc, chain, seals) abort, results := hc.engine.VerifyHeaders(hc, state, chain, seals)
defer close(abort) defer close(abort)
// Iterate over the headers and ensure they all check out // Iterate over the headers and ensure they all check out

View file

@ -387,7 +387,11 @@ func (api *PrivateDebugAPI) TraceBlockFromFile(ctx context.Context, file string,
// per transaction, dependent on the requestd tracer. // per transaction, dependent on the requestd tracer.
func (api *PrivateDebugAPI) traceBlock(ctx context.Context, block *types.Block, config *TraceConfig) ([]*txTraceResult, error) { func (api *PrivateDebugAPI) traceBlock(ctx context.Context, block *types.Block, config *TraceConfig) ([]*txTraceResult, error) {
// Create the parent state database // Create the parent state database
if err := api.eth.engine.VerifyHeader(api.eth.blockchain, block.Header(), true); err != nil { state, err := api.eth.blockchain.State()
if err != nil {
return nil, err
}
if err = api.eth.engine.VerifyHeader(api.eth.blockchain, state, block.Header(), true); err != nil {
return nil, err return nil, err
} }
parent := api.eth.blockchain.GetBlock(block.ParentHash(), block.NumberU64()-1) parent := api.eth.blockchain.GetBlock(block.ParentHash(), block.NumberU64()-1)

View file

@ -393,29 +393,31 @@ func CreateConsensusEngine(ctx *node.ServiceContext, config *ethash.Config, chai
if chainConfig.Posv != nil { if chainConfig.Posv != nil {
return posv.New(chainConfig.Posv, db) return posv.New(chainConfig.Posv, db)
} }
// Otherwise assume proof-of-work // Otherwise, return nil
switch { return nil
case config.PowMode == ethash.ModeFake: //// Otherwise assume proof-of-work
log.Warn("Ethash used in fake mode") //switch {
return ethash.NewFaker() //case config.PowMode == ethash.ModeFake:
case config.PowMode == ethash.ModeTest: // log.Warn("Ethash used in fake mode")
log.Warn("Ethash used in test mode") // return ethash.NewFaker()
return ethash.NewTester() //case config.PowMode == ethash.ModeTest:
case config.PowMode == ethash.ModeShared: // log.Warn("Ethash used in test mode")
log.Warn("Ethash used in shared mode") // return ethash.NewTester()
return ethash.NewShared() //case config.PowMode == ethash.ModeShared:
default: // log.Warn("Ethash used in shared mode")
engine := ethash.New(ethash.Config{ // return ethash.NewShared()
CacheDir: ctx.ResolvePath(config.CacheDir), //default:
CachesInMem: config.CachesInMem, // engine := ethash.New(ethash.Config{
CachesOnDisk: config.CachesOnDisk, // CacheDir: ctx.ResolvePath(config.CacheDir),
DatasetDir: config.DatasetDir, // CachesInMem: config.CachesInMem,
DatasetsInMem: config.DatasetsInMem, // CachesOnDisk: config.CachesOnDisk,
DatasetsOnDisk: config.DatasetsOnDisk, // DatasetDir: config.DatasetDir,
}) // DatasetsInMem: config.DatasetsInMem,
engine.SetThreads(-1) // Disable CPU mining // DatasetsOnDisk: config.DatasetsOnDisk,
return engine // })
} // engine.SetThreads(-1) // Disable CPU mining
// return engine
//}
} }
// APIs returns the collection of RPC services the ethereum package offers. // APIs returns the collection of RPC services the ethereum package offers.

View file

@ -165,7 +165,11 @@ func NewProtocolManager(config *params.ChainConfig, mode downloader.SyncMode, ne
manager.downloader = downloader.New(mode, chaindb, manager.eventMux, blockchain, nil, manager.removePeer) manager.downloader = downloader.New(mode, chaindb, manager.eventMux, blockchain, nil, manager.removePeer)
validator := func(header *types.Header) error { validator := func(header *types.Header) error {
return engine.VerifyHeader(blockchain, header, true) state, err := blockchain.State()
if err != nil {
return err
}
return engine.VerifyHeader(blockchain, state, header, true)
} }
heighter := func() uint64 { heighter := func() uint64 {
return blockchain.CurrentBlock().NumberU64() return blockchain.CurrentBlock().NumberU64()

View file

@ -344,7 +344,11 @@ func (self *LightChain) postChainEvents(events []interface{}) {
// chain events when necessary. // chain events when necessary.
func (self *LightChain) InsertHeaderChain(chain []*types.Header, checkFreq int) (int, error) { func (self *LightChain) InsertHeaderChain(chain []*types.Header, checkFreq int) (int, error) {
start := time.Now() start := time.Now()
if i, err := self.hc.ValidateHeaderChain(chain, checkFreq); err != nil { state, err := self.State()
if err != nil {
return 0, err
}
if i, err := self.hc.ValidateHeaderChain(chain, state, checkFreq); err != nil {
return i, err return i, err
} }

View file

@ -552,7 +552,7 @@ func (self *worker) commitNewWork() {
if atomic.LoadInt32(&self.mining) == 1 { if atomic.LoadInt32(&self.mining) == 1 {
header.Coinbase = self.coinbase header.Coinbase = self.coinbase
} }
if err := self.engine.Prepare(self.chain, header); err != nil { if err := self.engine.Prepare(self.chain, self.current.state, header); err != nil {
log.Error("Failed to prepare header for new block", "err", err) log.Error("Failed to prepare header for new block", "err", err)
return return
} }