diff --git a/core/blockchain.go b/core/blockchain.go index ed1fec909c7e..e287def23761 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1535,6 +1535,44 @@ func (bc *BlockChain) InsertChain(chain types.Blocks) (int, error) { return n, err } +// InsertChainWithoutSealVerification works exactly the same +// except for seal verification, seal verification is omitted +func (bc *BlockChain) InsertChainWithoutSealVerification(chain types.Blocks) (int, error) { + // Sanity check that we have something meaningful to import + if len(chain) == 0 { + return 0, nil + } + + bc.blockProcFeed.Send(true) + defer bc.blockProcFeed.Send(false) + + // Remove already known canon-blocks + var ( + block, prev *types.Block + ) + // Do a sanity check that the provided chain is actually ordered and linked + for i := 1; i < len(chain); i++ { + block = chain[i] + prev = chain[i-1] + if block.NumberU64() != prev.NumberU64()+1 || block.ParentHash() != prev.Hash() { + // Chain broke ancestry, log a message (programming error) and skip insertion + log.Error("Non contiguous block insert", "number", block.Number(), "hash", block.Hash(), + "parent", block.ParentHash(), "prevnumber", prev.Number(), "prevhash", prev.Hash()) + + return 0, fmt.Errorf("non contiguous insert: item %d is #%d [%x…], item %d is #%d [%x…] (parent [%x…])", i-1, prev.NumberU64(), + prev.Hash().Bytes()[:4], i, block.NumberU64(), block.Hash().Bytes()[:4], block.ParentHash().Bytes()[:4]) + } + } + // Pre-checks passed, start the full block imports + bc.wg.Add(1) + bc.chainmu.Lock() + n, err := bc.insertChain(chain, false) + bc.chainmu.Unlock() + bc.wg.Done() + + return n, err +} + // insertChain is the internal implementation of InsertChain, which assumes that // 1) chains are contiguous, and 2) The chain mutex is held. // diff --git a/eth/api.go b/eth/api.go index 6d346c22dfdf..7f93c47f29f8 100644 --- a/eth/api.go +++ b/eth/api.go @@ -389,9 +389,23 @@ func (api *Eth2API) makeEnv(parent *types.Block, header *types.Header) error { } func (api *Eth2API) ProduceBlock(parentHash common.Hash) ([]byte, error) { + log.Info("Produce block", "parentHash", parentHash) + bc := api.eth.BlockChain() parent := bc.GetBlockByHash(parentHash) pool := api.eth.TxPool() + + timestamp := time.Now().Unix() + if parent.Time() >= uint64(timestamp) { + timestamp = int64(parent.Time() + 1) + } + // this will ensure we're not going off too far in the future + if now := time.Now().Unix(); timestamp > now+1 { + wait := time.Duration(timestamp-now) * time.Second + log.Info("Producing block too far in the future", "wait", common.PrettyDuration(wait)) + time.Sleep(wait) + } + pending, err := pool.Pending() if err != nil { return nil, err @@ -403,7 +417,7 @@ func (api *Eth2API) ProduceBlock(parentHash common.Hash) ([]byte, error) { Number: num.Add(num, common.Big1), GasLimit: parent.GasLimit(), // Keep the gas limit constant in this prototype Extra: []byte{}, - Time: uint64(time.Now().UnixNano()), + Time: uint64(timestamp), } err = api.eth.Engine().Prepare(bc, header) if err != nil { @@ -486,13 +500,19 @@ func (api *Eth2API) InsertBlock(blockRLP []byte) error { return err } - _, err := api.eth.BlockChain().InsertChain(types.Blocks([]*types.Block{&block})) + _, err := api.eth.BlockChain().InsertChainWithoutSealVerification(types.Blocks([]*types.Block{&block})) return err } func (api *Eth2API) SetHead(newHead common.Hash) error { - oldBlock := api.eth.BlockChain().GetBlockByHash(api.head) + oldBlock := api.eth.BlockChain().CurrentBlock() + + if oldBlock.Hash() == newHead { + return nil + } + newBlock := api.eth.BlockChain().GetBlockByHash(newHead) + err := api.eth.BlockChain().Reorg(oldBlock, newBlock) if err != nil { return err