diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index fbeecee31a..5aac42b208 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -33,7 +33,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/fdlimit" "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/core" "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 { engine = posv.New(config.Posv, chainDb) } else { - engine = ethash.NewFaker() - if !ctx.GlobalBool(FakePoWFlag.Name) { - engine = ethash.New(ethash.Config{ - CacheDir: stack.ResolvePath(eth.DefaultConfig.Ethash.CacheDir), - CachesInMem: eth.DefaultConfig.Ethash.CachesInMem, - CachesOnDisk: eth.DefaultConfig.Ethash.CachesOnDisk, - DatasetDir: stack.ResolvePath(eth.DefaultConfig.Ethash.DatasetDir), - DatasetsInMem: eth.DefaultConfig.Ethash.DatasetsInMem, - DatasetsOnDisk: eth.DefaultConfig.Ethash.DatasetsOnDisk, - }) - } + //engine = ethash.NewFaker() + //if !ctx.GlobalBool(FakePoWFlag.Name) { + // engine = ethash.New(ethash.Config{ + // CacheDir: stack.ResolvePath(eth.DefaultConfig.Ethash.CacheDir), + // CachesInMem: eth.DefaultConfig.Ethash.CachesInMem, + // CachesOnDisk: eth.DefaultConfig.Ethash.CachesOnDisk, + // DatasetDir: stack.ResolvePath(eth.DefaultConfig.Ethash.DatasetDir), + // DatasetsInMem: eth.DefaultConfig.Ethash.DatasetsInMem, + // DatasetsOnDisk: eth.DefaultConfig.Ethash.DatasetsOnDisk, + // }) + //} + Fatalf("Only support posv consensus") } if gcmode := ctx.GlobalString(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" { Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name) diff --git a/consensus/consensus.go b/consensus/consensus.go index b02afa63c4..8d992b5dee 100644 --- a/consensus/consensus.go +++ b/consensus/consensus.go @@ -58,13 +58,13 @@ type Engine interface { // VerifyHeader checks whether a header conforms to the consensus rules of a // given engine. Verifying the seal may be done optionally here, or explicitly // 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 // 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 // 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 // rules of a given engine. @@ -76,7 +76,7 @@ type Engine interface { // Prepare initializes the consensus fields of a block header according to the // 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) // and assembles the final block. diff --git a/consensus/posv/posv.go b/consensus/posv/posv.go index 54fbddf1b8..b86028cce0 100644 --- a/consensus/posv/posv.go +++ b/consensus/posv/posv.go @@ -261,20 +261,20 @@ func (c *Posv) Author(header *types.Header) (common.Address, error) { } // VerifyHeader checks whether a header conforms to the consensus rules. -func (c *Posv) VerifyHeader(chain consensus.ChainReader, header *types.Header, fullVerify bool) error { - return c.verifyHeaderWithCache(chain, header, nil, fullVerify) +func (c *Posv) VerifyHeader(chain consensus.ChainReader, state *state.StateDB, header *types.Header, fullVerify bool) error { + return c.verifyHeaderWithCache(chain, state, header, nil, fullVerify) } // 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 // 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{}) results := make(chan error, len(headers)) go func() { 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 { case <-abort: @@ -286,12 +286,12 @@ func (c *Posv) VerifyHeaders(chain consensus.ChainReader, headers []*types.Heade 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()) if check { return nil } - err := c.verifyHeader(chain, header, parents, fullVerify) + err := c.verifyHeader(chain, state, header, parents, fullVerify) if err == nil { 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 // looking those up from the database. This is useful for concurrently verifying // 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 { return errUnknownBlock } @@ -357,14 +357,14 @@ func (c *Posv) verifyHeader(chain consensus.ChainReader, header *types.Header, p return err } // 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, // 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 // 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 number := header.Number.Uint64() 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 number%c.config.Epoch == 0 { - database := state.NewDatabase(c.db) - state, _ := state.New(parent.Hash(), database) penPenalties := []common.Address{} if c.HookPenalty != nil { 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 number == 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 } 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 // 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) header.Coinbase = common.Address{} header.Nonce = types.BlockNonce{} @@ -777,8 +775,6 @@ func (c *Posv) Prepare(chain consensus.ChainReader, header *types.Header) error header.Extra = header.Extra[:extraVanity] masternodes := snap.GetSigners() if number > 0 && number%c.config.Epoch == 0 { - database := state.NewDatabase(c.db) - state, _ := state.New(parent.Hash(), database) if c.HookPenalty != nil { penMasternodes, err := c.HookPenalty(state, chain, number) if err != nil { diff --git a/core/blockchain.go b/core/blockchain.go index 4d6c2cc011..46d9739ffb 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1069,7 +1069,11 @@ func (bc *BlockChain) insertChain(chain types.Blocks) (int, []interface{}, []*ty seals[i] = 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) // 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) 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 { return err } @@ -1678,7 +1686,11 @@ Error: %v // because nonces can be verified sparsely, not needing to check each. func (bc *BlockChain) InsertHeaderChain(chain []*types.Header, checkFreq int) (int, error) { 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 } diff --git a/core/headerchain.go b/core/headerchain.go index 2d1b0a2a18..f0ecd73868 100644 --- a/core/headerchain.go +++ b/core/headerchain.go @@ -33,6 +33,7 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" "github.com/hashicorp/golang-lru" + "github.com/ethereum/go-ethereum/core/state" ) 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. 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 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() { @@ -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 - abort, results := hc.engine.VerifyHeaders(hc, chain, seals) + abort, results := hc.engine.VerifyHeaders(hc, state, chain, seals) defer close(abort) // Iterate over the headers and ensure they all check out diff --git a/eth/api_tracer.go b/eth/api_tracer.go index 07c4457bc3..5f992494b0 100644 --- a/eth/api_tracer.go +++ b/eth/api_tracer.go @@ -387,7 +387,11 @@ func (api *PrivateDebugAPI) TraceBlockFromFile(ctx context.Context, file string, // per transaction, dependent on the requestd tracer. func (api *PrivateDebugAPI) traceBlock(ctx context.Context, block *types.Block, config *TraceConfig) ([]*txTraceResult, error) { // 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 } parent := api.eth.blockchain.GetBlock(block.ParentHash(), block.NumberU64()-1) diff --git a/eth/backend.go b/eth/backend.go index 2553de199a..ad58f0677c 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -393,29 +393,31 @@ func CreateConsensusEngine(ctx *node.ServiceContext, config *ethash.Config, chai if chainConfig.Posv != nil { return posv.New(chainConfig.Posv, db) } - // Otherwise assume proof-of-work - switch { - case config.PowMode == ethash.ModeFake: - log.Warn("Ethash used in fake mode") - return ethash.NewFaker() - case config.PowMode == ethash.ModeTest: - log.Warn("Ethash used in test mode") - return ethash.NewTester() - case config.PowMode == ethash.ModeShared: - log.Warn("Ethash used in shared mode") - return ethash.NewShared() - default: - engine := ethash.New(ethash.Config{ - CacheDir: ctx.ResolvePath(config.CacheDir), - CachesInMem: config.CachesInMem, - CachesOnDisk: config.CachesOnDisk, - DatasetDir: config.DatasetDir, - DatasetsInMem: config.DatasetsInMem, - DatasetsOnDisk: config.DatasetsOnDisk, - }) - engine.SetThreads(-1) // Disable CPU mining - return engine - } + // Otherwise, return nil + return nil + //// Otherwise assume proof-of-work + //switch { + //case config.PowMode == ethash.ModeFake: + // log.Warn("Ethash used in fake mode") + // return ethash.NewFaker() + //case config.PowMode == ethash.ModeTest: + // log.Warn("Ethash used in test mode") + // return ethash.NewTester() + //case config.PowMode == ethash.ModeShared: + // log.Warn("Ethash used in shared mode") + // return ethash.NewShared() + //default: + // engine := ethash.New(ethash.Config{ + // CacheDir: ctx.ResolvePath(config.CacheDir), + // CachesInMem: config.CachesInMem, + // CachesOnDisk: config.CachesOnDisk, + // DatasetDir: config.DatasetDir, + // DatasetsInMem: config.DatasetsInMem, + // DatasetsOnDisk: config.DatasetsOnDisk, + // }) + // engine.SetThreads(-1) // Disable CPU mining + // return engine + //} } // APIs returns the collection of RPC services the ethereum package offers. diff --git a/eth/handler.go b/eth/handler.go index 322a888ade..df2435b080 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -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) 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 { return blockchain.CurrentBlock().NumberU64() diff --git a/light/lightchain.go b/light/lightchain.go index 2784615d35..a59535049d 100644 --- a/light/lightchain.go +++ b/light/lightchain.go @@ -344,7 +344,11 @@ func (self *LightChain) postChainEvents(events []interface{}) { // chain events when necessary. func (self *LightChain) InsertHeaderChain(chain []*types.Header, checkFreq int) (int, error) { 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 } diff --git a/miner/worker.go b/miner/worker.go index a5d5167fb4..41103c87af 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -552,7 +552,7 @@ func (self *worker) commitNewWork() { if atomic.LoadInt32(&self.mining) == 1 { 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) return }