From 71d32f54f70917c53fd3a691cface3bc73ffa1b7 Mon Sep 17 00:00:00 2001 From: Jeffrey Wilcke Date: Tue, 4 Aug 2015 23:46:38 +0200 Subject: core, miner: added difficulty bomb --- core/block_processor.go | 2 +- core/chain_makers.go | 2 +- core/chain_util.go | 20 ++++++++++--- core/chain_util_test.go | 77 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 95 insertions(+), 6 deletions(-) create mode 100644 core/chain_util_test.go (limited to 'core') 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) + } + } +} -- cgit v1.2.3