mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-17 17:33:47 +00:00
consensus, core: move CalcDifficulty to Engine interface
This commit is contained in:
parent
f6e818a818
commit
fdffaf31c4
6 changed files with 64 additions and 55 deletions
|
|
@ -510,7 +510,6 @@ func (c *Clique) Prepare(chain consensus.ChainReader, header *types.Header) erro
|
||||||
header.Nonce = types.BlockNonce{}
|
header.Nonce = types.BlockNonce{}
|
||||||
|
|
||||||
number := header.Number.Uint64()
|
number := header.Number.Uint64()
|
||||||
|
|
||||||
// Assemble the voting snapshot to check which votes make sense
|
// Assemble the voting snapshot to check which votes make sense
|
||||||
snap, err := c.snapshot(chain, number-1, header.ParentHash, nil)
|
snap, err := c.snapshot(chain, number-1, header.ParentHash, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -538,10 +537,8 @@ func (c *Clique) Prepare(chain consensus.ChainReader, header *types.Header) erro
|
||||||
c.lock.RUnlock()
|
c.lock.RUnlock()
|
||||||
}
|
}
|
||||||
// Set the correct difficulty
|
// Set the correct difficulty
|
||||||
header.Difficulty = diffNoTurn
|
header.Difficulty = CalcDifficulty(snap, c.signer)
|
||||||
if snap.inturn(header.Number.Uint64(), c.signer) {
|
|
||||||
header.Difficulty = diffInTurn
|
|
||||||
}
|
|
||||||
// Ensure the extra data has all it's components
|
// Ensure the extra data has all it's components
|
||||||
if len(header.Extra) < extraVanity {
|
if len(header.Extra) < extraVanity {
|
||||||
header.Extra = append(header.Extra, bytes.Repeat([]byte{0x00}, extraVanity-len(header.Extra))...)
|
header.Extra = append(header.Extra, bytes.Repeat([]byte{0x00}, extraVanity-len(header.Extra))...)
|
||||||
|
|
@ -655,6 +652,22 @@ func (c *Clique) Seal(chain consensus.ChainReader, block *types.Block, stop <-ch
|
||||||
return block.WithSeal(header), nil
|
return block.WithSeal(header), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CalcDifficulty is the difficulty adjustment algorithm. It returns the difficulty that a new block should have.
|
||||||
|
func (c *Clique) CalcDifficulty(chain consensus.ChainReader, time uint64, parent *types.Header) *big.Int {
|
||||||
|
snap, err := c.snapshot(chain, parent.Number.Uint64(), parent.Hash(), nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return CalcDifficulty(snap, c.signer)
|
||||||
|
}
|
||||||
|
|
||||||
|
func CalcDifficulty(snap *Snapshot, signer common.Address) *big.Int {
|
||||||
|
if snap.inturn(snap.Number+1, signer) {
|
||||||
|
return new(big.Int).Set(diffInTurn)
|
||||||
|
}
|
||||||
|
return new(big.Int).Set(diffNoTurn)
|
||||||
|
}
|
||||||
|
|
||||||
// APIs implements consensus.Engine, returning the user facing RPC API to allow
|
// APIs implements consensus.Engine, returning the user facing RPC API to allow
|
||||||
// controlling the signer voting.
|
// controlling the signer voting.
|
||||||
func (c *Clique) APIs(chain consensus.ChainReader) []rpc.API {
|
func (c *Clique) APIs(chain consensus.ChainReader) []rpc.API {
|
||||||
|
|
|
||||||
|
|
@ -89,6 +89,10 @@ type Engine interface {
|
||||||
// seal place on top.
|
// seal place on top.
|
||||||
Seal(chain ChainReader, block *types.Block, stop <-chan struct{}) (*types.Block, error)
|
Seal(chain ChainReader, block *types.Block, stop <-chan struct{}) (*types.Block, error)
|
||||||
|
|
||||||
|
// CalcDifficulty is the difficulty adjustment algorithm. It returns the difficulty
|
||||||
|
// that a new block should have.
|
||||||
|
CalcDifficulty(chain ChainReader, time uint64, parent *types.Header) *big.Int
|
||||||
|
|
||||||
// APIs returns the RPC APIs this consensus engine provides.
|
// APIs returns the RPC APIs this consensus engine provides.
|
||||||
APIs(chain ChainReader) []rpc.API
|
APIs(chain ChainReader) []rpc.API
|
||||||
}
|
}
|
||||||
|
|
@ -99,13 +103,4 @@ type PoW interface {
|
||||||
|
|
||||||
// Hashrate returns the current mining hashrate of a PoW consensus engine.
|
// Hashrate returns the current mining hashrate of a PoW consensus engine.
|
||||||
Hashrate() float64
|
Hashrate() float64
|
||||||
|
|
||||||
// CalcDifficulty returns the difficulty that a new block should have when created at time
|
|
||||||
// given the parent block's time and difficulty.
|
|
||||||
CalcDifficulty(*params.ChainConfig, uint64, *types.Header) *big.Int
|
|
||||||
|
|
||||||
// AccumulateRewards credits the coinbase of the given block with the mining
|
|
||||||
// reward. The total reward consists of the static block reward and rewards for
|
|
||||||
// included uncles. The coinbase of each uncle block is also rewarded.
|
|
||||||
AccumulateRewards(*params.ChainConfig, *state.StateDB, *types.Header, []*types.Header)
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -239,7 +239,8 @@ func (ethash *Ethash) verifyHeader(chain consensus.ChainReader, header, parent *
|
||||||
return errZeroBlockTime
|
return errZeroBlockTime
|
||||||
}
|
}
|
||||||
// Verify the block's difficulty based in it's timestamp and parent's difficulty
|
// Verify the block's difficulty based in it's timestamp and parent's difficulty
|
||||||
expected := ethash.CalcDifficulty(chain.Config(), header.Time.Uint64(), parent)
|
expected := ethash.CalcDifficulty(chain, header.Time.Uint64(), parent)
|
||||||
|
|
||||||
if expected.Cmp(header.Difficulty) != 0 {
|
if expected.Cmp(header.Difficulty) != 0 {
|
||||||
return fmt.Errorf("invalid difficulty: have %v, want %v", header.Difficulty, expected)
|
return fmt.Errorf("invalid difficulty: have %v, want %v", header.Difficulty, expected)
|
||||||
}
|
}
|
||||||
|
|
@ -286,7 +287,11 @@ func (ethash *Ethash) verifyHeader(chain consensus.ChainReader, header, parent *
|
||||||
// CalcDifficulty is the difficulty adjustment algorithm. It returns
|
// CalcDifficulty is the difficulty adjustment algorithm. It returns
|
||||||
// the difficulty that a new block should have when created at time
|
// the difficulty that a new block should have when created at time
|
||||||
// given the parent block's time and difficulty.
|
// given the parent block's time and difficulty.
|
||||||
func (ethash *Ethash) CalcDifficulty(config *params.ChainConfig, time uint64, parent *types.Header) *big.Int {
|
func (ethash *Ethash) CalcDifficulty(chain consensus.ChainReader, time uint64, parent *types.Header) *big.Int {
|
||||||
|
return CalcDifficulty(chain.Config(), time, parent)
|
||||||
|
}
|
||||||
|
|
||||||
|
func CalcDifficulty(config *params.ChainConfig, time uint64, parent *types.Header) *big.Int {
|
||||||
next := new(big.Int).Add(parent.Number, big1)
|
next := new(big.Int).Add(parent.Number, big1)
|
||||||
switch {
|
switch {
|
||||||
case config.IsByzantium(next):
|
case config.IsByzantium(next):
|
||||||
|
|
@ -500,8 +505,7 @@ func (ethash *Ethash) Prepare(chain consensus.ChainReader, header *types.Header)
|
||||||
if parent == nil {
|
if parent == nil {
|
||||||
return consensus.ErrUnknownAncestor
|
return consensus.ErrUnknownAncestor
|
||||||
}
|
}
|
||||||
header.Difficulty = ethash.CalcDifficulty(chain.Config(), header.Time.Uint64(), parent)
|
header.Difficulty = ethash.CalcDifficulty(chain, header.Time.Uint64(), parent)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -509,7 +513,7 @@ func (ethash *Ethash) Prepare(chain consensus.ChainReader, header *types.Header)
|
||||||
// setting the final state and assembling the block.
|
// setting the final state and assembling the block.
|
||||||
func (ethash *Ethash) Finalize(chain consensus.ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) {
|
func (ethash *Ethash) Finalize(chain consensus.ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) {
|
||||||
// Accumulate any block and uncle rewards and commit the final state root
|
// Accumulate any block and uncle rewards and commit the final state root
|
||||||
ethash.AccumulateRewards(chain.Config(), state, header, uncles)
|
accumulateRewards(chain.Config(), state, header, uncles)
|
||||||
header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
|
header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
|
||||||
|
|
||||||
// Header seems complete, assemble into a block and return
|
// Header seems complete, assemble into a block and return
|
||||||
|
|
@ -525,7 +529,7 @@ var (
|
||||||
// AccumulateRewards credits the coinbase of the given block with the mining
|
// AccumulateRewards credits the coinbase of the given block with the mining
|
||||||
// reward. The total reward consists of the static block reward and rewards for
|
// reward. The total reward consists of the static block reward and rewards for
|
||||||
// included uncles. The coinbase of each uncle block is also rewarded.
|
// included uncles. The coinbase of each uncle block is also rewarded.
|
||||||
func (ethash *Ethash) AccumulateRewards(config *params.ChainConfig, state *state.StateDB, header *types.Header, uncles []*types.Header) {
|
func accumulateRewards(config *params.ChainConfig, state *state.StateDB, header *types.Header, uncles []*types.Header) {
|
||||||
// Select the correct block reward based on chain progression
|
// Select the correct block reward based on chain progression
|
||||||
blockReward := frontierBlockReward
|
blockReward := frontierBlockReward
|
||||||
if config.IsByzantium(header.Number) {
|
if config.IsByzantium(header.Number) {
|
||||||
|
|
|
||||||
|
|
@ -71,9 +71,10 @@ func TestCalcDifficulty(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
config := ¶ms.ChainConfig{HomesteadBlock: big.NewInt(1150000)}
|
config := ¶ms.ChainConfig{HomesteadBlock: big.NewInt(1150000)}
|
||||||
|
|
||||||
for name, test := range tests {
|
for name, test := range tests {
|
||||||
number := new(big.Int).Sub(test.CurrentBlocknumber, big.NewInt(1))
|
number := new(big.Int).Sub(test.CurrentBlocknumber, big.NewInt(1))
|
||||||
diff := NewFaker().CalcDifficulty(config, test.CurrentTimestamp, &types.Header{
|
diff := CalcDifficulty(config, test.CurrentTimestamp, &types.Header{
|
||||||
Number: number,
|
Number: number,
|
||||||
Time: new(big.Int).SetUint64(test.ParentTimestamp),
|
Time: new(big.Int).SetUint64(test.ParentTimestamp),
|
||||||
Difficulty: test.ParentDifficulty,
|
Difficulty: test.ParentDifficulty,
|
||||||
|
|
|
||||||
|
|
@ -39,11 +39,12 @@ var (
|
||||||
// BlockGen creates blocks for testing.
|
// BlockGen creates blocks for testing.
|
||||||
// See GenerateChain for a detailed explanation.
|
// See GenerateChain for a detailed explanation.
|
||||||
type BlockGen struct {
|
type BlockGen struct {
|
||||||
i int
|
i int
|
||||||
parent *types.Block
|
parent *types.Block
|
||||||
chain []*types.Block
|
chain []*types.Block
|
||||||
header *types.Header
|
chainReader consensus.ChainReader
|
||||||
statedb *state.StateDB
|
header *types.Header
|
||||||
|
statedb *state.StateDB
|
||||||
|
|
||||||
gasPool *GasPool
|
gasPool *GasPool
|
||||||
txs []*types.Transaction
|
txs []*types.Transaction
|
||||||
|
|
@ -142,9 +143,7 @@ func (b *BlockGen) OffsetTime(seconds int64) {
|
||||||
if b.header.Time.Cmp(b.parent.Header().Time) <= 0 {
|
if b.header.Time.Cmp(b.parent.Header().Time) <= 0 {
|
||||||
panic("block time out of range")
|
panic("block time out of range")
|
||||||
}
|
}
|
||||||
if pow, ok := b.engine.(consensus.PoW); ok {
|
b.header.Difficulty = b.engine.CalcDifficulty(b.chainReader, b.header.Time.Uint64(), b.parent.Header())
|
||||||
b.header.Difficulty = pow.CalcDifficulty(b.config, b.header.Time.Uint64(), b.parent.Header())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenerateChain creates a chain of n blocks. The first block's
|
// GenerateChain creates a chain of n blocks. The first block's
|
||||||
|
|
@ -165,8 +164,10 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
|
||||||
}
|
}
|
||||||
blocks, receipts := make(types.Blocks, n), make([]types.Receipts, n)
|
blocks, receipts := make(types.Blocks, n), make([]types.Receipts, n)
|
||||||
genblock := func(i int, parent *types.Block, statedb *state.StateDB) (*types.Block, types.Receipts) {
|
genblock := func(i int, parent *types.Block, statedb *state.StateDB) (*types.Block, types.Receipts) {
|
||||||
b := &BlockGen{i: i, parent: parent, chain: blocks, statedb: statedb, config: config, engine: engine}
|
blockchain, _ := NewBlockChain(db, config, engine, vm.Config{})
|
||||||
b.header = makeHeader(config, parent, statedb, b.engine)
|
defer blockchain.Stop()
|
||||||
|
b := &BlockGen{i: i, parent: parent, chain: blocks, chainReader: blockchain, statedb: statedb, config: config, engine: engine}
|
||||||
|
b.header = makeHeader(b.chainReader, parent, statedb, b.engine)
|
||||||
|
|
||||||
// Mutate the state and block according to any hard-fork specs
|
// Mutate the state and block according to any hard-fork specs
|
||||||
if daoBlock := config.DAOForkBlock; daoBlock != nil {
|
if daoBlock := config.DAOForkBlock; daoBlock != nil {
|
||||||
|
|
@ -185,16 +186,16 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
|
||||||
gen(i, b)
|
gen(i, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
if pow, ok := b.engine.(consensus.PoW); ok {
|
if b.engine != nil {
|
||||||
pow.AccumulateRewards(config, statedb, b.header, b.uncles)
|
block, _ := b.engine.Finalize(b.chainReader, b.header, statedb, b.txs, b.uncles, b.receipts)
|
||||||
|
// Write state changes to db
|
||||||
|
_, err := statedb.CommitTo(db, config.IsEIP158(b.header.Number))
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("state write error: %v", err))
|
||||||
|
}
|
||||||
|
return block, b.receipts
|
||||||
}
|
}
|
||||||
|
return nil, nil
|
||||||
root, err := statedb.CommitTo(db, config.IsEIP158(b.header.Number))
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("state write error: %v", err))
|
|
||||||
}
|
|
||||||
b.header.Root = root
|
|
||||||
return types.NewBlock(b.header, b.txs, b.uncles, b.receipts), b.receipts
|
|
||||||
}
|
}
|
||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
statedb, err := state.New(parent.Root(), state.NewDatabase(db))
|
statedb, err := state.New(parent.Root(), state.NewDatabase(db))
|
||||||
|
|
@ -209,7 +210,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
|
||||||
return blocks, receipts
|
return blocks, receipts
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeHeader(config *params.ChainConfig, parent *types.Block, state *state.StateDB, engine consensus.Engine) *types.Header {
|
func makeHeader(chain consensus.ChainReader, parent *types.Block, state *state.StateDB, engine consensus.Engine) *types.Header {
|
||||||
var time *big.Int
|
var time *big.Int
|
||||||
if parent.Time() == nil {
|
if parent.Time() == nil {
|
||||||
time = big.NewInt(10)
|
time = big.NewInt(10)
|
||||||
|
|
@ -217,26 +218,21 @@ func makeHeader(config *params.ChainConfig, parent *types.Block, state *state.St
|
||||||
time = new(big.Int).Add(parent.Time(), big.NewInt(10)) // block time is fixed at 10 seconds
|
time = new(big.Int).Add(parent.Time(), big.NewInt(10)) // block time is fixed at 10 seconds
|
||||||
}
|
}
|
||||||
|
|
||||||
header := &types.Header{
|
return &types.Header{
|
||||||
Root: state.IntermediateRoot(config.IsEIP158(parent.Number())),
|
Root: state.IntermediateRoot(chain.Config().IsEIP158(parent.Number())),
|
||||||
ParentHash: parent.Hash(),
|
ParentHash: parent.Hash(),
|
||||||
Coinbase: parent.Coinbase(),
|
Coinbase: parent.Coinbase(),
|
||||||
GasLimit: CalcGasLimit(parent),
|
Difficulty: engine.CalcDifficulty(chain, time.Uint64(), &types.Header{
|
||||||
GasUsed: new(big.Int),
|
|
||||||
Number: new(big.Int).Add(parent.Number(), common.Big1),
|
|
||||||
Time: time,
|
|
||||||
}
|
|
||||||
|
|
||||||
if pow, ok := engine.(consensus.PoW); ok {
|
|
||||||
header.Difficulty = pow.CalcDifficulty(config, time.Uint64(), &types.Header{
|
|
||||||
Number: parent.Number(),
|
Number: parent.Number(),
|
||||||
Time: new(big.Int).Sub(time, big.NewInt(10)),
|
Time: new(big.Int).Sub(time, big.NewInt(10)),
|
||||||
Difficulty: parent.Difficulty(),
|
Difficulty: parent.Difficulty(),
|
||||||
UncleHash: parent.UncleHash(),
|
UncleHash: parent.UncleHash(),
|
||||||
})
|
}),
|
||||||
|
GasLimit: CalcGasLimit(parent),
|
||||||
|
GasUsed: new(big.Int),
|
||||||
|
Number: new(big.Int).Add(parent.Number(), common.Big1),
|
||||||
|
Time: time,
|
||||||
}
|
}
|
||||||
|
|
||||||
return header
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// newCanonical creates a chain database, and injects a deterministic canonical
|
// newCanonical creates a chain database, and injects a deterministic canonical
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ func (test *DifficultyTest) Run(config *params.ChainConfig) error {
|
||||||
UncleHash: test.UncleHash,
|
UncleHash: test.UncleHash,
|
||||||
}
|
}
|
||||||
|
|
||||||
actual := ethash.NewFaker().CalcDifficulty(config, test.CurrentTimestamp.Uint64(), parent)
|
actual := ethash.CalcDifficulty(config, test.CurrentTimestamp.Uint64(), parent)
|
||||||
exp := test.CurrentDifficulty
|
exp := test.CurrentDifficulty
|
||||||
|
|
||||||
if actual.Cmp(exp) != 0 {
|
if actual.Cmp(exp) != 0 {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue