diff --git a/core/block_processor.go b/core/block_processor.go index 6687cd000..5a2ad8377 100644 --- a/core/block_processor.go +++ b/core/block_processor.go @@ -386,7 +386,7 @@ func ValidateHeader(pow pow.PoW, block *types.Header, parent *types.Block, check return BlockEqualTSErr } - expd := CalcDifficulty(block.Time, parent.Time(), parent.Difficulty()) + expd := CalcDifficulty(block.Time, parent.Time(), parent.Number(), parent.Difficulty()) if expd.Cmp(block.Difficulty) != 0 { return fmt.Errorf("Difficulty check failed for block %v, %v", block.Difficulty, expd) } diff --git a/core/chain_makers.go b/core/chain_makers.go index 283653d9a..85a6175dc 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -171,7 +171,7 @@ func makeHeader(parent *types.Block, state *state.StateDB) *types.Header { Root: state.Root(), ParentHash: parent.Hash(), Coinbase: parent.Coinbase(), - Difficulty: CalcDifficulty(time, parent.Time(), parent.Difficulty()), + Difficulty: CalcDifficulty(time, parent.Time(), parent.Number(), parent.Difficulty()), GasLimit: CalcGasLimit(parent), GasUsed: new(big.Int), Number: new(big.Int).Add(parent.Number(), common.Big1), diff --git a/core/chain_util.go b/core/chain_util.go index 104670195..34f6c8d0a 100644 --- a/core/chain_util.go +++ b/core/chain_util.go @@ -30,14 +30,15 @@ import ( ) var ( - blockHashPre = []byte("block-hash-") - blockNumPre = []byte("block-num-") + blockHashPre = []byte("block-hash-") + blockNumPre = []byte("block-num-") + expDiffPeriod = big.NewInt(100000) ) // CalcDifficulty is the difficulty adjustment algorithm. It returns // the difficulty that a new block b should have when created at time // given the parent block's time and difficulty. -func CalcDifficulty(time, parentTime uint64, parentDiff *big.Int) *big.Int { +func CalcDifficulty(time, parentTime uint64, parentNumber, parentDiff *big.Int) *big.Int { diff := new(big.Int) adjust := new(big.Int).Div(parentDiff, params.DifficultyBoundDivisor) bigTime := new(big.Int) @@ -52,8 +53,19 @@ func CalcDifficulty(time, parentTime uint64, parentDiff *big.Int) *big.Int { diff.Sub(parentDiff, adjust) } if diff.Cmp(params.MinimumDifficulty) < 0 { - return params.MinimumDifficulty + diff = params.MinimumDifficulty } + + periodCount := new(big.Int).Add(parentNumber, common.Big1) + periodCount.Div(periodCount, expDiffPeriod) + if periodCount.Cmp(common.Big1) > 0 { + // diff = diff + 2^(periodCount - 2) + expDiff := periodCount.Sub(periodCount, common.Big2) + expDiff.Exp(common.Big2, expDiff, nil) + diff.Add(diff, expDiff) + diff = common.BigMax(diff, params.MinimumDifficulty) + } + return diff } diff --git a/core/chain_util_test.go b/core/chain_util_test.go new file mode 100644 index 000000000..4bbe81194 --- /dev/null +++ b/core/chain_util_test.go @@ -0,0 +1,77 @@ +// Copyright 2015 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package core + +import ( + "encoding/json" + "math/big" + "os" + "testing" + + "github.com/ethereum/go-ethereum/common" +) + +type diffTest struct { + ParentTimestamp uint64 + ParentDifficulty *big.Int + CurrentTimestamp uint64 + CurrentBlocknumber *big.Int + CurrentDifficulty *big.Int +} + +func (d *diffTest) UnmarshalJSON(b []byte) (err error) { + var ext struct { + ParentTimestamp string + ParentDifficulty string + CurrentTimestamp string + CurrentBlocknumber string + CurrentDifficulty string + } + if err := json.Unmarshal(b, &ext); err != nil { + return err + } + + d.ParentTimestamp = common.String2Big(ext.ParentTimestamp).Uint64() + d.ParentDifficulty = common.String2Big(ext.ParentDifficulty) + d.CurrentTimestamp = common.String2Big(ext.CurrentTimestamp).Uint64() + d.CurrentBlocknumber = common.String2Big(ext.CurrentBlocknumber) + d.CurrentDifficulty = common.String2Big(ext.CurrentDifficulty) + + return nil +} + +func TestDifficulty(t *testing.T) { + file, err := os.Open("../tests/files/BasicTests/difficulty.json") + if err != nil { + t.Fatal(err) + } + defer file.Close() + + tests := make(map[string]diffTest) + err = json.NewDecoder(file).Decode(&tests) + if err != nil { + t.Fatal(err) + } + + for name, test := range tests { + number := new(big.Int).Sub(test.CurrentBlocknumber, big.NewInt(1)) + diff := CalcDifficulty(test.CurrentTimestamp, test.ParentTimestamp, number, test.ParentDifficulty) + if diff.Cmp(test.CurrentDifficulty) != 0 { + t.Error(name, "failed. Expected", test.CurrentDifficulty, "and calculated", diff) + } + } +} diff --git a/miner/worker.go b/miner/worker.go index 7fb40af78..d6d96601e 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -444,7 +444,7 @@ func (self *worker) commitNewWork() { header := &types.Header{ ParentHash: parent.Hash(), Number: num.Add(num, common.Big1), - Difficulty: core.CalcDifficulty(uint64(tstamp), parent.Time(), parent.Difficulty()), + Difficulty: core.CalcDifficulty(uint64(tstamp), parent.Time(), parent.Number(), parent.Difficulty()), GasLimit: core.CalcGasLimit(parent), GasUsed: new(big.Int), Coinbase: self.coinbase, diff --git a/tests/files/BasicTests/difficulty.json b/tests/files/BasicTests/difficulty.json new file mode 100644 index 000000000..44beac5f5 --- /dev/null +++ b/tests/files/BasicTests/difficulty.json @@ -0,0 +1,100 @@ +{ + "preExpDiffIncrease" : { + "parentTimestamp" : "42", + "parentDifficulty" : "1000000", + "currentTimestamp" : "43", + "currentBlockNumber" : "42", + "currentDifficulty" : "1000488" + }, + "preExpDiffDecrease" : { + "parentTimestamp" : "42", + "parentDifficulty" : "1000000", + "currentTimestamp" : "60", + "currentBlockNumber" : "42", + "currentDifficulty" : "999512" + }, + "ExpDiffAtBlock200000Increase" : { + "parentTimestamp" : "42", + "parentDifficulty" : "1000000", + "currentTimestamp" : "43", + "currentBlockNumber" : "200000", + "currentDifficulty" : "1000489" + }, + "ExpDiffAtBlock200000Decrease" : { + "parentTimestamp" : "42", + "parentDifficulty" : "1000000", + "currentTimestamp" : "60", + "currentBlockNumber" : "200000", + "currentDifficulty" : "999513" + }, + "ExpDiffPostBlock200000Increase" : { + "parentTimestamp" : "42", + "parentDifficulty" : "1000000", + "currentTimestamp" : "43", + "currentBlockNumber" : "200001", + "currentDifficulty" : "1000489" + }, + "ExpDiffPostBlock200000Decrease" : { + "parentTimestamp" : "42", + "parentDifficulty" : "1000000", + "currentTimestamp" : "60", + "currentBlockNumber" : "200001", + "currentDifficulty" : "999513" + }, + "ExpDiffPreBlock300000Increase" : { + "parentTimestamp" : "42", + "parentDifficulty" : "1000000", + "currentTimestamp" : "43", + "currentBlockNumber" : "299999", + "currentDifficulty" : "1000489" + }, + "ExpDiffPreBlock300000Decrease" : { + "parentTimestamp" : "42", + "parentDifficulty" : "1000000", + "currentTimestamp" : "60", + "currentBlockNumber" : "299999", + "currentDifficulty" : "999513" + }, + "ExpDiffAtBlock300000Increase" : { + "parentTimestamp" : "42", + "parentDifficulty" : "1000000", + "currentTimestamp" : "43", + "currentBlockNumber" : "300000", + "currentDifficulty" : "1000490" + }, + "ExpDiffAtBlock300000Decrease" : { + "parentTimestamp" : "42", + "parentDifficulty" : "1000000", + "currentTimestamp" : "60", + "currentBlockNumber" : "300000", + "currentDifficulty" : "999514" + }, + "ExpDiffPostBlock300000Increase" : { + "parentTimestamp" : "42", + "parentDifficulty" : "1000000", + "currentTimestamp" : "43", + "currentBlockNumber" : "300001", + "currentDifficulty" : "1000490" + }, + "ExpDiffPostBlock300000Decrease" : { + "parentTimestamp" : "42", + "parentDifficulty" : "1000000", + "currentTimestamp" : "60", + "currentBlockNumber" : "300001", + "currentDifficulty" : "999514" + }, + "ExpDiffInAYearIncrease" : { + "parentTimestamp" : "42", + "parentDifficulty" : "1000000", + "currentTimestamp" : "43", + "currentBlockNumber" : "2302400", + "currentDifficulty" : "3097640" + }, + "ExpDiffInAYearDecrease" : { + "parentTimestamp" : "42", + "parentDifficulty" : "1000000", + "currentTimestamp" : "60", + "currentBlockNumber" : "2302400", + "currentDifficulty" : "3096664" + } +}