From 4e2c1c4c6e1559b9dcd408d4dfe64b047eca6126 Mon Sep 17 00:00:00 2001 From: "Mr. Is" Date: Fri, 5 May 2017 16:30:00 -0500 Subject: [PATCH 01/18] discovers where its at --- core/chain_manager.go | 2 +- core/state_processor.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/chain_manager.go b/core/chain_manager.go index 2d520ca7b..e19a29b27 100644 --- a/core/chain_manager.go +++ b/core/chain_manager.go @@ -227,7 +227,7 @@ func GenerateChain(config *ChainConfig, parent *types.Block, db ethdb.Database, // Mutate the state and block according to any hard-fork specs if config == nil { - config = MakeChainConfig() + config = DefaultConfig // MakeChainConfig() } // Execute any user modifications to the block and finalize it if gen != nil { diff --git a/core/state_processor.go b/core/state_processor.go index e10b6785c..3e5708320 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -29,7 +29,7 @@ import ( ) var ( - BlockReward = big.NewInt(5e+18) + BlockReward = big.NewInt(5e+18) // that's shiny 5 ether big8 = big.NewInt(8) big32 = big.NewInt(32) ) From 2aa535c4bc34fc0bf562763f0917caf328f9eb2e Mon Sep 17 00:00:00 2001 From: "Mr. Is" Date: Mon, 8 May 2017 05:07:08 -0500 Subject: [PATCH 02/18] takes math equation notes and changes name of variable --- core/state_processor.go | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/core/state_processor.go b/core/state_processor.go index 3e5708320..4daaa6592 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -29,9 +29,9 @@ import ( ) var ( - BlockReward = big.NewInt(5e+18) // that's shiny 5 ether - big8 = big.NewInt(8) - big32 = big.NewInt(32) + MaximumBlockReward = big.NewInt(5e+18) // that's shiny 5 ether + big8 = big.NewInt(8) + big32 = big.NewInt(32) ) // StateProcessor is a basic Processor, which takes care of transitioning @@ -129,16 +129,18 @@ func ApplyTransaction(config *ChainConfig, bc *BlockChain, gp *GasPool, statedb // and rewards for included uncles. The coinbase of each uncle block is // also rewarded. func AccumulateRewards(statedb *state.StateDB, header *types.Header, uncles []*types.Header) { - reward := new(big.Int).Set(BlockReward) + reward := new(big.Int).Set(MaximumBlockReward) r := new(big.Int) + // An uncle is a block that would be considered an orphan because its not on the longest chain (it's an alternative block at the same height as your parent). + // https://www.reddit.com/r/ethereum/comments/3c9jbf/wtf_are_uncles_and_why_do_they_matter/ for _, uncle := range uncles { - r.Add(uncle.Number, big8) - r.Sub(r, header.Number) - r.Mul(r, BlockReward) - r.Div(r, big8) + r.Add(uncle.Number, big8) // 2,534,999 + 8 + r.Sub(r, header.Number) // 2,535,007 - 2,535,008 + r.Mul(r, MaximumBlockReward) // -1 * 5e+18 + r.Div(r, big8) // -5e+18 / 8 statedb.AddBalance(uncle.Coinbase, r) - r.Div(BlockReward, big32) + r.Div(MaximumBlockReward, big32) reward.Add(reward, r) } statedb.AddBalance(header.Coinbase, reward) From 1d41b43139e012651de7267f9696069b9f4d8440 Mon Sep 17 00:00:00 2001 From: "Mr. Is" Date: Mon, 8 May 2017 06:09:33 -0500 Subject: [PATCH 03/18] test: getBlockEra in state_processor --- core/state_processor.go | 31 ++++++++++++++++++++++--------- core/state_processor_test.go | 31 +++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 9 deletions(-) create mode 100644 core/state_processor_test.go diff --git a/core/state_processor.go b/core/state_processor.go index 4daaa6592..c94e6ad53 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -26,6 +26,7 @@ import ( "github.com/ethereumproject/go-ethereum/crypto" "github.com/ethereumproject/go-ethereum/logger" "github.com/ethereumproject/go-ethereum/logger/glog" + "github.com/ethereumproject/go-ethereum/common" ) var ( @@ -133,15 +134,27 @@ func AccumulateRewards(statedb *state.StateDB, header *types.Header, uncles []*t r := new(big.Int) // An uncle is a block that would be considered an orphan because its not on the longest chain (it's an alternative block at the same height as your parent). // https://www.reddit.com/r/ethereum/comments/3c9jbf/wtf_are_uncles_and_why_do_they_matter/ + + // uncle.Number = 2,535,998 // assuming "latest" uncle... + // block.Number = 2,534,999 // uncles are at same height (?) + // ... as uncles get older (within validation), reward drops + for _, uncle := range uncles { - r.Add(uncle.Number, big8) // 2,534,999 + 8 - r.Sub(r, header.Number) // 2,535,007 - 2,535,008 - r.Mul(r, MaximumBlockReward) // -1 * 5e+18 - r.Div(r, big8) // -5e+18 / 8 - statedb.AddBalance(uncle.Coinbase, r) - - r.Div(MaximumBlockReward, big32) - reward.Add(reward, r) + r.Add(uncle.Number, big8) // 2,534,998 + 8 = 2,535,006 + r.Sub(r, header.Number) // 2,535,006 - 2,534,999 = 7 + r.Mul(r, MaximumBlockReward) // 7 * 5e+18 = 35e+18 + r.Div(r, big8) // 35e+18 / 8 = 7/8 * 5e+18 + statedb.AddBalance(uncle.Coinbase, r) // $$ + + r.Div(MaximumBlockReward, big32) // 5e+18 / 32 + reward.Add(reward, r) // 5e+18 + (1/32*5e+18) } - statedb.AddBalance(header.Coinbase, reward) + statedb.AddBalance(header.Coinbase, reward) // $$ => 5e+18 + (1/32*5e+18) } + + +// getBlockEra gets which "era" a given block is within, given era length (ecip-1017 -> era=5,000,000 blocks) +func getBlockEra(blockNum, eraLength *big.Int) *big.Int { + _, m := big.NewInt(0).DivMod(blockNum, eraLength, big.NewInt(0)) + return big.NewInt(0).Add(m, common.Big1) +} \ No newline at end of file diff --git a/core/state_processor_test.go b/core/state_processor_test.go new file mode 100644 index 000000000..f0a05a1ee --- /dev/null +++ b/core/state_processor_test.go @@ -0,0 +1,31 @@ +package core + +import ( + "testing" + "math/big" + "github.com/ethereumproject/go-ethereum/common" +) + +func TestgetBlockEra(t *testing.T) { + cases := map[*big.Int]*big.Int{ + common.Big1: common.Big1, + big.NewInt(4999999): common.Big1, + big.NewInt(5000000): common.Big2, + big.NewInt(5000001): common.Big2, + big.NewInt(9999999): common.Big2, + big.NewInt(10000000): common.Big3, + big.NewInt(10000001): common.Big3, + big.NewInt(14999999): common.Big3, + big.NewInt(15000000): big.NewInt(4), + big.NewInt(15000001): big.NewInt(4), + big.NewInt(100000001): big.NewInt(26), + } + eraLength := big.NewInt(5000000) + + for bn, expectedEra := range cases { + gotEra := getBlockEra(bn, eraLength) + if gotEra.Cmp(expectedEra) == 0 { + t.Errorf("got: %v, want: %v", gotEra, expectedEra) + } + } +} \ No newline at end of file From 31edfe8049b824bbd36976d340dc8e0ea368b366 Mon Sep 17 00:00:00 2001 From: "Mr. Is" Date: Mon, 8 May 2017 07:07:53 -0500 Subject: [PATCH 04/18] implement: getblockera and getrewardbyera functions with tests --- core/state_processor.go | 22 ++++++++++--- core/state_processor_test.go | 63 +++++++++++++++++++++++++----------- 2 files changed, 63 insertions(+), 22 deletions(-) diff --git a/core/state_processor.go b/core/state_processor.go index c94e6ad53..0463d3934 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -26,13 +26,14 @@ import ( "github.com/ethereumproject/go-ethereum/crypto" "github.com/ethereumproject/go-ethereum/logger" "github.com/ethereumproject/go-ethereum/logger/glog" - "github.com/ethereumproject/go-ethereum/common" ) var ( MaximumBlockReward = big.NewInt(5e+18) // that's shiny 5 ether big8 = big.NewInt(8) big32 = big.NewInt(32) + DisinflationRate = big.NewInt(0).Div(big.NewInt(4), big.NewInt(5)) + EraLength = big.NewInt(5000000) ) // StateProcessor is a basic Processor, which takes care of transitioning @@ -152,9 +153,22 @@ func AccumulateRewards(statedb *state.StateDB, header *types.Header, uncles []*t statedb.AddBalance(header.Coinbase, reward) // $$ => 5e+18 + (1/32*5e+18) } +func GetRewardByEra(maxReward, disinflationRate, era *big.Int) *big.Int { + if era.Cmp(big.NewInt(0)) == 0 { return maxReward } + multiplier := big.NewInt(0).Exp(disinflationRate, era,nil) // %m ignored for m == nil||0 + return big.NewInt(0).Mul(maxReward, multiplier) +} + // getBlockEra gets which "era" a given block is within, given era length (ecip-1017 -> era=5,000,000 blocks) -func getBlockEra(blockNum, eraLength *big.Int) *big.Int { - _, m := big.NewInt(0).DivMod(blockNum, eraLength, big.NewInt(0)) - return big.NewInt(0).Add(m, common.Big1) +func GetBlockEra(blockNum, eraLength *big.Int) *big.Int { + if blockNum.Cmp(big.NewInt(0)) <= 0 { return big.NewInt(0) } + + remainder := big.NewInt(0).Mod(big.NewInt(0).Sub(blockNum, big.NewInt(1)), eraLength) + base := big.NewInt(0).Sub(blockNum, remainder) + + d := big.NewInt(0).Div(base, eraLength) + dremainder := big.NewInt(0).Mod(d, big.NewInt(1)) + + return big.NewInt(0).Sub(d, dremainder) } \ No newline at end of file diff --git a/core/state_processor_test.go b/core/state_processor_test.go index f0a05a1ee..23e2c62ab 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -1,31 +1,58 @@ package core import ( - "testing" "math/big" - "github.com/ethereumproject/go-ethereum/common" + "testing" ) -func TestgetBlockEra(t *testing.T) { +func TestGetBlockEra(t *testing.T) { cases := map[*big.Int]*big.Int{ - common.Big1: common.Big1, - big.NewInt(4999999): common.Big1, - big.NewInt(5000000): common.Big2, - big.NewInt(5000001): common.Big2, - big.NewInt(9999999): common.Big2, - big.NewInt(10000000): common.Big3, - big.NewInt(10000001): common.Big3, - big.NewInt(14999999): common.Big3, - big.NewInt(15000000): big.NewInt(4), - big.NewInt(15000001): big.NewInt(4), - big.NewInt(100000001): big.NewInt(26), + big.NewInt(0): big.NewInt(0), + big.NewInt(1): big.NewInt(0), + big.NewInt(4999999): big.NewInt(0), + big.NewInt(5000000): big.NewInt(0), + big.NewInt(5000001): big.NewInt(1), + big.NewInt(9999999): big.NewInt(1), + big.NewInt(10000000): big.NewInt(1), + big.NewInt(10000001): big.NewInt(2), + big.NewInt(14999999): big.NewInt(2), + big.NewInt(15000000): big.NewInt(2), + big.NewInt(15000001): big.NewInt(3), + big.NewInt(100000001): big.NewInt(20), + big.NewInt(123456789): big.NewInt(24), } - eraLength := big.NewInt(5000000) for bn, expectedEra := range cases { - gotEra := getBlockEra(bn, eraLength) - if gotEra.Cmp(expectedEra) == 0 { + gotEra := GetBlockEra(bn, EraLength) + if gotEra.Cmp(expectedEra) != 0 { t.Errorf("got: %v, want: %v", gotEra, expectedEra) } } -} \ No newline at end of file +} + +func TestGetRewardByEra(t *testing.T) { + + cases := map[*big.Int]*big.Int{ + big.NewInt(0): MaximumBlockReward, + big.NewInt(1): MaximumBlockReward, + big.NewInt(4999999): MaximumBlockReward, + big.NewInt(5000000): MaximumBlockReward, + big.NewInt(5000001): big.NewInt(0).Mul(MaximumBlockReward, big.NewInt(0).Exp(DisinflationRate, big.NewInt(1), nil)), + big.NewInt(9999999): big.NewInt(0).Mul(MaximumBlockReward, big.NewInt(0).Exp(DisinflationRate, big.NewInt(1), nil)), + big.NewInt(10000000): big.NewInt(0).Mul(MaximumBlockReward, big.NewInt(0).Exp(DisinflationRate, big.NewInt(1), nil)), + big.NewInt(10000001): big.NewInt(0).Mul(MaximumBlockReward, big.NewInt(0).Exp(DisinflationRate, big.NewInt(2), nil)), + big.NewInt(14999999): big.NewInt(0).Mul(MaximumBlockReward, big.NewInt(0).Exp(DisinflationRate, big.NewInt(2), nil)), + big.NewInt(15000000): big.NewInt(0).Mul(MaximumBlockReward, big.NewInt(0).Exp(DisinflationRate, big.NewInt(2), nil)), + big.NewInt(15000001): big.NewInt(0).Mul(MaximumBlockReward, big.NewInt(0).Exp(DisinflationRate, big.NewInt(3), nil)), + big.NewInt(100000001): big.NewInt(0).Mul(MaximumBlockReward, big.NewInt(0).Exp(DisinflationRate, big.NewInt(20), nil)), + big.NewInt(123456789): big.NewInt(0).Mul(MaximumBlockReward, big.NewInt(0).Exp(DisinflationRate, big.NewInt(24), nil)), + } + + for bn, expectedReward := range cases { + gotReward := GetRewardByEra(MaximumBlockReward, DisinflationRate, GetBlockEra(bn, EraLength)) + if gotReward.Cmp(expectedReward) != 0 { + t.Errorf("got: %v, want: %v", gotReward, expectedReward) + } + } + +} From 1588e73278ad84d4fd1e82d252d27b85bc29903e Mon Sep 17 00:00:00 2001 From: "Mr. Is" Date: Mon, 8 May 2017 09:10:05 -0500 Subject: [PATCH 05/18] use better disinflation block reward math --- core/state_processor.go | 21 ++++++++++++++++----- core/state_processor_test.go | 34 +++++++++++++++++++--------------- 2 files changed, 35 insertions(+), 20 deletions(-) diff --git a/core/state_processor.go b/core/state_processor.go index 0463d3934..e8f71430c 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -32,7 +32,8 @@ var ( MaximumBlockReward = big.NewInt(5e+18) // that's shiny 5 ether big8 = big.NewInt(8) big32 = big.NewInt(32) - DisinflationRate = big.NewInt(0).Div(big.NewInt(4), big.NewInt(5)) + DisinflationRateQuotient = big.NewInt(4) + DisinflationRateDivisor = big.NewInt(5) EraLength = big.NewInt(5000000) ) @@ -153,10 +154,20 @@ func AccumulateRewards(statedb *state.StateDB, header *types.Header, uncles []*t statedb.AddBalance(header.Coinbase, reward) // $$ => 5e+18 + (1/32*5e+18) } -func GetRewardByEra(maxReward, disinflationRate, era *big.Int) *big.Int { - if era.Cmp(big.NewInt(0)) == 0 { return maxReward } - multiplier := big.NewInt(0).Exp(disinflationRate, era,nil) // %m ignored for m == nil||0 - return big.NewInt(0).Mul(maxReward, multiplier) +// GetRewardByEra gets a block reward at disinflation rate. +// Constants MaxBlockReward, DisinflationRateQuotient, and DisinflationRateDivisor assumed. +func GetRewardByEra(era *big.Int) *big.Int { + if era.Cmp(big.NewInt(0)) == 0 { return MaximumBlockReward } + + var q, d, r *big.Int = new(big.Int), new(big.Int), new(big.Int) + + q.Exp(DisinflationRateQuotient, era, nil) + d.Exp(DisinflationRateDivisor, era, nil) + + r.Mul(MaximumBlockReward, q) + r.Div(r, d) + + return r } diff --git a/core/state_processor_test.go b/core/state_processor_test.go index 23e2c62ab..c4f01ade5 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -33,25 +33,29 @@ func TestGetBlockEra(t *testing.T) { func TestGetRewardByEra(t *testing.T) { cases := map[*big.Int]*big.Int{ - big.NewInt(0): MaximumBlockReward, - big.NewInt(1): MaximumBlockReward, - big.NewInt(4999999): MaximumBlockReward, - big.NewInt(5000000): MaximumBlockReward, - big.NewInt(5000001): big.NewInt(0).Mul(MaximumBlockReward, big.NewInt(0).Exp(DisinflationRate, big.NewInt(1), nil)), - big.NewInt(9999999): big.NewInt(0).Mul(MaximumBlockReward, big.NewInt(0).Exp(DisinflationRate, big.NewInt(1), nil)), - big.NewInt(10000000): big.NewInt(0).Mul(MaximumBlockReward, big.NewInt(0).Exp(DisinflationRate, big.NewInt(1), nil)), - big.NewInt(10000001): big.NewInt(0).Mul(MaximumBlockReward, big.NewInt(0).Exp(DisinflationRate, big.NewInt(2), nil)), - big.NewInt(14999999): big.NewInt(0).Mul(MaximumBlockReward, big.NewInt(0).Exp(DisinflationRate, big.NewInt(2), nil)), - big.NewInt(15000000): big.NewInt(0).Mul(MaximumBlockReward, big.NewInt(0).Exp(DisinflationRate, big.NewInt(2), nil)), - big.NewInt(15000001): big.NewInt(0).Mul(MaximumBlockReward, big.NewInt(0).Exp(DisinflationRate, big.NewInt(3), nil)), - big.NewInt(100000001): big.NewInt(0).Mul(MaximumBlockReward, big.NewInt(0).Exp(DisinflationRate, big.NewInt(20), nil)), - big.NewInt(123456789): big.NewInt(0).Mul(MaximumBlockReward, big.NewInt(0).Exp(DisinflationRate, big.NewInt(24), nil)), + big.NewInt(0): MaximumBlockReward, + big.NewInt(1): MaximumBlockReward, + big.NewInt(4999999): MaximumBlockReward, + big.NewInt(5000000): MaximumBlockReward, + big.NewInt(5000001): big.NewInt(4e+18), + big.NewInt(9999999): big.NewInt(4e+18), + big.NewInt(10000000): big.NewInt(4e+18), + big.NewInt(10000001): big.NewInt(3.2e+18), + big.NewInt(14999999): big.NewInt(3.2e+18), + big.NewInt(15000000): big.NewInt(3.2e+18), + big.NewInt(15000001): big.NewInt(2.56e+18), } for bn, expectedReward := range cases { - gotReward := GetRewardByEra(MaximumBlockReward, DisinflationRate, GetBlockEra(bn, EraLength)) + gotReward := GetRewardByEra(GetBlockEra(bn, EraLength)) if gotReward.Cmp(expectedReward) != 0 { - t.Errorf("got: %v, want: %v", gotReward, expectedReward) + t.Errorf("@ %v, got: %v, want: %v", bn, gotReward, expectedReward) + } + if gotReward.Cmp(big.NewInt(0)) <= 0 { + t.Errorf("@ %v, got: %v, want: %v", bn, gotReward, expectedReward) + } + if gotReward.Cmp(MaximumBlockReward) > 0 { + t.Errorf("@ %v, got: %v, want %v", bn, gotReward, expectedReward) } } From 6d1fa0e0f43d65bb99788446053abb8a68e076ff Mon Sep 17 00:00:00 2001 From: "Mr. Is" Date: Mon, 8 May 2017 13:04:00 -0500 Subject: [PATCH 06/18] problem: ecip1017 - begin implementation solution: implement with tests :x: TestAccumulateRewards not passing; consistently 1/32 too high --- core/chain_manager.go | 2 +- core/data_chainconfig.go | 7 ++ core/state_processor.go | 110 ++++++++++++++++---- core/state_processor_test.go | 191 ++++++++++++++++++++++++++++++++++- miner/worker.go | 2 +- 5 files changed, 289 insertions(+), 23 deletions(-) diff --git a/core/chain_manager.go b/core/chain_manager.go index e19a29b27..83fa2dd1f 100644 --- a/core/chain_manager.go +++ b/core/chain_manager.go @@ -233,7 +233,7 @@ func GenerateChain(config *ChainConfig, parent *types.Block, db ethdb.Database, if gen != nil { gen(i, b) } - AccumulateRewards(statedb, h, b.uncles) + AccumulateRewards(config, statedb, h, b.uncles) root, err := statedb.Commit() if err != nil { panic(fmt.Sprintf("state write error: %v", err)) diff --git a/core/data_chainconfig.go b/core/data_chainconfig.go index 1c0324137..0272c4300 100644 --- a/core/data_chainconfig.go +++ b/core/data_chainconfig.go @@ -176,6 +176,13 @@ var TestConfig = &ChainConfig{ "length": 2000000, }, }, + { + ID: "reward", + Options: ChainFeatureConfigOptions{ + "type": "ecip1017", + "era": 5000000, + }, + }, }, }, }, diff --git a/core/state_processor.go b/core/state_processor.go index e8f71430c..4e6b645c3 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -26,15 +26,18 @@ import ( "github.com/ethereumproject/go-ethereum/crypto" "github.com/ethereumproject/go-ethereum/logger" "github.com/ethereumproject/go-ethereum/logger/glog" + "errors" ) var ( - MaximumBlockReward = big.NewInt(5e+18) // that's shiny 5 ether - big8 = big.NewInt(8) - big32 = big.NewInt(32) + MaximumBlockReward = big.NewInt(5e+18) // that's shiny 5 ether + big8 = big.NewInt(8) + big32 = big.NewInt(32) DisinflationRateQuotient = big.NewInt(4) - DisinflationRateDivisor = big.NewInt(5) - EraLength = big.NewInt(5000000) + DisinflationRateDivisor = big.NewInt(5) + DefaultEraLength = big.NewInt(5000000) // Convenient for testing. + + ErrConfiguration = errors.New("invalid configuration") ) // StateProcessor is a basic Processor, which takes care of transitioning @@ -90,7 +93,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB) (ty receipts = append(receipts, receipt) allLogs = append(allLogs, logs...) } - AccumulateRewards(statedb, header, block.Uncles()) + AccumulateRewards(p.config, statedb, header, block.Uncles()) return receipts, allLogs, totalUsedGas, err } @@ -131,9 +134,8 @@ func ApplyTransaction(config *ChainConfig, bc *BlockChain, gp *GasPool, statedb // 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. -func AccumulateRewards(statedb *state.StateDB, header *types.Header, uncles []*types.Header) { - reward := new(big.Int).Set(MaximumBlockReward) - r := new(big.Int) +func AccumulateRewards(config *ChainConfig, statedb *state.StateDB, header *types.Header, uncles []*types.Header) { + // An uncle is a block that would be considered an orphan because its not on the longest chain (it's an alternative block at the same height as your parent). // https://www.reddit.com/r/ethereum/comments/3c9jbf/wtf_are_uncles_and_why_do_they_matter/ @@ -141,22 +143,93 @@ func AccumulateRewards(statedb *state.StateDB, header *types.Header, uncles []*t // block.Number = 2,534,999 // uncles are at same height (?) // ... as uncles get older (within validation), reward drops - for _, uncle := range uncles { - r.Add(uncle.Number, big8) // 2,534,998 + 8 = 2,535,006 - r.Sub(r, header.Number) // 2,535,006 - 2,534,999 = 7 + feat, _, configured := config.GetFeature(header.Number, "reward") + if !configured { + reward := new(big.Int).Set(MaximumBlockReward) + r := new(big.Int) + + for _, uncle := range uncles { + r.Add(uncle.Number, big8) // 2,534,998 + 8 = 2,535,006 + r.Sub(r, header.Number) // 2,535,006 - 2,534,999 = 7 + r.Mul(r, MaximumBlockReward) // 7 * 5e+18 = 35e+18 + r.Div(r, big8) // 35e+18 / 8 = 7/8 * 5e+18 + + statedb.AddBalance(uncle.Coinbase, r) // $$ + + r.Div(MaximumBlockReward, big32) // 5e+18 / 32 + reward.Add(reward, r) // 5e+18 + (1/32*5e+18) + } + statedb.AddBalance(header.Coinbase, reward) // $$ => 5e+18 + (1/32*5e+18) + } else { + // Check that configuration specifies ECIP1017. + val, ok := feat.GetString("type") + if !ok || val != "ecip1017" { + panic(ErrConfiguration) + } + + // Ensure value 'era' is configured. + eraVal, ok := feat.GetBigInt("era") + if !ok || eraVal.Cmp(big.NewInt(0)) <= 0 { + panic(ErrConfiguration) + } + + era := GetBlockEra(header.Number, eraVal) + + wr := GetBlockWinnerRewardByEra(era) // wr "winner reward". 5, 4, 3.2, 2.56, ... + wurs := GetBlockWinnerRewardForUnclesByEra(era, uncles) // wurs "winner uncle rewards" + wr.Add(wr, wurs) + + statedb.AddBalance(header.Coinbase, wr) // $$ + + // Reward uncle miners. + for _, uncle := range uncles { + ur := GetBlockUncleRewardByEra(era, header, uncle) + statedb.AddBalance(uncle.Coinbase, ur) // $$ + } + } +} + +// As of "Era 2", uncle miners and winners are rewarded equally for each included block. +// So they share this function. +func getEraUncleBlockReward(era *big.Int) *big.Int { + + r := new(big.Int) + r.Add(r, GetBlockWinnerRewardByEra(era)) + r.Div(r, big.NewInt(32)) + + return r +} + +// GetBlockUncleRewardByEra gets called _for each uncle miner_ associated with a winner block's uncles. +func GetBlockUncleRewardByEra(era *big.Int, header, uncle *types.Header) *big.Int { + // Era 1 (index 0): + // An extra reward to the winning miner for including uncles as part of the block, in the form of an extra 1/32 (0.15625ETC) per uncle included, up to a maximum of two (2) uncles. + if era.Cmp(big.NewInt(0)) == 0 { + r := new(big.Int) + r.Add(uncle.Number, big8) // 2,534,998 + 8 = 2,535,006 + r.Sub(r, header.Number) // 2,535,006 - 2,534,999 = 7 r.Mul(r, MaximumBlockReward) // 7 * 5e+18 = 35e+18 - r.Div(r, big8) // 35e+18 / 8 = 7/8 * 5e+18 - statedb.AddBalance(uncle.Coinbase, r) // $$ + r.Div(r, big8) // 35e+18 / 8 = 7/8 * 5e+18 - r.Div(MaximumBlockReward, big32) // 5e+18 / 32 - reward.Add(reward, r) // 5e+18 + (1/32*5e+18) + return r } - statedb.AddBalance(header.Coinbase, reward) // $$ => 5e+18 + (1/32*5e+18) + + return getEraUncleBlockReward(era) +} + +// GetBlockWinnerRewardForUnclesByEra gets called _per winner_, and accumulates rewards for each included uncle. +func GetBlockWinnerRewardForUnclesByEra(era *big.Int, uncles []*types.Header) *big.Int { + r := new(big.Int) + + for range uncles { + r.Add(r, getEraUncleBlockReward(era)) // can reuse this, since 1/32 for winner's uncles remain unchanged from "Era 1" + } + return r } // GetRewardByEra gets a block reward at disinflation rate. // Constants MaxBlockReward, DisinflationRateQuotient, and DisinflationRateDivisor assumed. -func GetRewardByEra(era *big.Int) *big.Int { +func GetBlockWinnerRewardByEra(era *big.Int) *big.Int { if era.Cmp(big.NewInt(0)) == 0 { return MaximumBlockReward } var q, d, r *big.Int = new(big.Int), new(big.Int), new(big.Int) @@ -172,6 +245,7 @@ func GetRewardByEra(era *big.Int) *big.Int { // getBlockEra gets which "era" a given block is within, given era length (ecip-1017 -> era=5,000,000 blocks) +// Returns a zero-index era number, so "Era 1" -> 0, "Era 2" -> 1,... func GetBlockEra(blockNum, eraLength *big.Int) *big.Int { if blockNum.Cmp(big.NewInt(0)) <= 0 { return big.NewInt(0) } diff --git a/core/state_processor_test.go b/core/state_processor_test.go index c4f01ade5..7b4ff82e6 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -3,6 +3,14 @@ package core import ( "math/big" "testing" + + "math/rand" + "time" + + "github.com/ethereumproject/go-ethereum/common" + "github.com/ethereumproject/go-ethereum/core/state" + "github.com/ethereumproject/go-ethereum/core/types" + "github.com/ethereumproject/go-ethereum/ethdb" ) func TestGetBlockEra(t *testing.T) { @@ -23,14 +31,14 @@ func TestGetBlockEra(t *testing.T) { } for bn, expectedEra := range cases { - gotEra := GetBlockEra(bn, EraLength) + gotEra := GetBlockEra(bn, DefaultEraLength) if gotEra.Cmp(expectedEra) != 0 { t.Errorf("got: %v, want: %v", gotEra, expectedEra) } } } -func TestGetRewardByEra(t *testing.T) { +func TestGetBlockWinnerRewardByEra(t *testing.T) { cases := map[*big.Int]*big.Int{ big.NewInt(0): MaximumBlockReward, @@ -47,7 +55,7 @@ func TestGetRewardByEra(t *testing.T) { } for bn, expectedReward := range cases { - gotReward := GetRewardByEra(GetBlockEra(bn, EraLength)) + gotReward := GetBlockWinnerRewardByEra(GetBlockEra(bn, DefaultEraLength)) if gotReward.Cmp(expectedReward) != 0 { t.Errorf("@ %v, got: %v, want: %v", bn, gotReward, expectedReward) } @@ -60,3 +68,180 @@ func TestGetRewardByEra(t *testing.T) { } } + +func TestGetBlockUncleRewardByEra(t *testing.T) { + + var we1, we2, we3, we4 *big.Int = new(big.Int), new(big.Int), new(big.Int), new(big.Int) + + we2.Div(GetBlockWinnerRewardByEra(big.NewInt(1)), big.NewInt(32)) + we3.Div(GetBlockWinnerRewardByEra(big.NewInt(2)), big.NewInt(32)) + we4.Div(GetBlockWinnerRewardByEra(big.NewInt(3)), big.NewInt(32)) + + cases := map[*big.Int]*big.Int{ + big.NewInt(0): nil, + big.NewInt(1): nil, + big.NewInt(4999999): nil, + big.NewInt(5000000): nil, + big.NewInt(5000001): we2, + big.NewInt(9999999): we2, + big.NewInt(10000000): we2, + big.NewInt(10000001): we3, + big.NewInt(14999999): we3, + big.NewInt(15000000): we3, + big.NewInt(15000001): we4, + } + + for bn, want := range cases { + + era := GetBlockEra(bn, DefaultEraLength) + + var header, uncle *types.Header = &types.Header{}, &types.Header{} + header.Number = bn + + rand.Seed(time.Now().UTC().UnixNano()) + uncle.Number = big.NewInt(0).Sub(header.Number, big.NewInt(int64(rand.Int31n(int32(7))))) + + got := GetBlockUncleRewardByEra(era, header, uncle) + + // "Era 1" + if want == nil { + we1.Add(uncle.Number, big8) // 2,534,998 + 8 = 2,535,006 + we1.Sub(we1, header.Number) // 2,535,006 - 2,534,999 = 7 + we1.Mul(we1, MaximumBlockReward) // 7 * 5e+18 = 35e+18 + we1.Div(we1, big8) // 35e+18 / 8 = 7/8 * 5e+18 + + if got.Cmp(we1) != 0 { + t.Errorf("@ %v, want: %v, got: %v", bn, we1, got) + } + } else { + if got.Cmp(want) != 0 { + t.Errorf("@ %v, want: %v, got: %v", bn, want, got) + } + } + } +} + +func TestGetBlockWinnerRewardForUnclesByEra(t *testing.T) { + + // "want era 1", "want era 2", ... + var we1, we2, we3, we4 *big.Int = new(big.Int), new(big.Int), new(big.Int), new(big.Int) + we1.Div(MaximumBlockReward, big.NewInt(32)) + we2.Div(GetBlockWinnerRewardByEra(big.NewInt(1)), big.NewInt(32)) + we3.Div(GetBlockWinnerRewardByEra(big.NewInt(2)), big.NewInt(32)) + we4.Div(GetBlockWinnerRewardByEra(big.NewInt(3)), big.NewInt(32)) + + cases := map[*big.Int]*big.Int{ + big.NewInt(0): we1, + big.NewInt(1): we1, + big.NewInt(4999999): we1, + big.NewInt(5000000): we1, + big.NewInt(5000001): we2, + big.NewInt(9999999): we2, + big.NewInt(10000000): we2, + big.NewInt(10000001): we3, + big.NewInt(14999999): we3, + big.NewInt(15000000): we3, + big.NewInt(15000001): we4, + } + + var uncleSingle, uncleDouble []*types.Header = []*types.Header{{}}, []*types.Header{{}, {}} + + for bn, want := range cases { + // test single uncle + got := GetBlockWinnerRewardForUnclesByEra(GetBlockEra(bn, DefaultEraLength), uncleSingle) + if got.Cmp(want) != 0 { + t.Errorf("@ %v: want: %v, got: %v", bn, want, got) + } + + // test double uncle + got = GetBlockWinnerRewardForUnclesByEra(GetBlockEra(bn, DefaultEraLength), uncleDouble) + dub := new(big.Int) + if got.Cmp(dub.Mul(want, big.NewInt(2))) != 0 { + t.Errorf("@ %v: want: %v, got: %v", bn, want, got) + } + } + +} + +func TestAccumulateRewards(t *testing.T) { + configs := []*ChainConfig{DefaultConfig, TestConfig} + for i, config := range configs { + db, _ := ethdb.NewMemDatabase() + defer db.Close() + stateDB, err := state.New(common.Hash{}, db) + if err != nil { + t.Fatalf("could not open statedb: %v", err) + } + + var header *types.Header = &types.Header{} + var uncles []*types.Header = []*types.Header{{}, {}} + + header.Coinbase = common.StringToAddress("0000000000000000000000000000000000000001") + uncles[0].Coinbase = common.StringToAddress("0000000000000000000000000000000000000002") + uncles[1].Coinbase = common.StringToAddress("0000000000000000000000000000000000000003") + + // Manual tallies for reward accumulation. + winnerB, totalB := new(big.Int), new(big.Int) + unclesB := []*big.Int{new(big.Int), new(big.Int)} + + winnerB = stateDB.GetBalance(header.Coinbase) + unclesB[0] = stateDB.GetBalance(uncles[0].Coinbase) + unclesB[1] = stateDB.GetBalance(uncles[1].Coinbase) + + cases := []*big.Int{ + //big.NewInt(0), + big.NewInt(1), + big.NewInt(4999999), + big.NewInt(5000000), + big.NewInt(5000001), + big.NewInt(9999999), + big.NewInt(10000000), + big.NewInt(10000001), + big.NewInt(14999999), + big.NewInt(15000000), + big.NewInt(15000001), + } + + for _, bn := range cases { + era := GetBlockEra(bn, DefaultEraLength) + + header.Number = bn + + for i, uncle := range uncles { + //rand.Seed(time.Now().UTC().UnixNano()) + // TODO: is it ok to reuse same uncle numbers? it could happen... + //uncle.Number.Sub(header.Number, big.NewInt(int64(rand.Int31n(int32(7))))) + + uncle.Number = big.NewInt(0).Sub(header.Number, big.NewInt(1)) + + ur := GetBlockUncleRewardByEra(era, header, uncle) + unclesB[i].Add(unclesB[i], ur) + + totalB.Add(totalB, ur) + } + + wr := GetBlockWinnerRewardByEra(era) + wr.Add(wr, GetBlockWinnerRewardForUnclesByEra(era, uncles)) + winnerB.Add(winnerB, wr) + + totalB.Add(totalB, winnerB) + + AccumulateRewards(config, stateDB, header, uncles) + + // Check balances. + if wb := stateDB.GetBalance(header.Coinbase); wb.Cmp(winnerB) != 0 { + t.Errorf("winner balance @ %v, want: %v, got: %v (config: %v)", bn, winnerB, wb, i) + } + if uB0 := stateDB.GetBalance(uncles[0].Coinbase); unclesB[0].Cmp(uB0) != 0 { + t.Errorf("uncle1 balance @ %v, want: %v, got: %v (config: %v)", bn, unclesB[0], uB0, i) + } + if uB1 := stateDB.GetBalance(uncles[1].Coinbase); unclesB[1].Cmp(uB1) != 0 { + t.Errorf("uncle2 balance @ %v, want: %v, got: %v (config: %v)", bn, unclesB[1], uB1, i) + } + // overflows int64 + //if bn.Cmp(big.NewInt(1)) == 0 && totalB.Cmp(big.NewInt(14.0625e+18)) != 0 { + // t.Errorf("total balance @ 1, want: %v, got: %v", bn, big.NewInt(14.0625e+18), totalB) + //} + } + } +} diff --git a/miner/worker.go b/miner/worker.go index 88ed2d163..1d0033cb2 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -540,7 +540,7 @@ func (self *worker) commitNewWork() { if atomic.LoadInt32(&self.mining) == 1 { // commit state root after all state transitions. - core.AccumulateRewards(work.state, header, uncles) + core.AccumulateRewards(work.config, work.state, header, uncles) header.Root = work.state.IntermediateRoot() } From 2e8892c525fb20ea1679d4c68433f3af53c5101d Mon Sep 17 00:00:00 2001 From: "Mr. Is" Date: Mon, 8 May 2017 17:53:48 -0500 Subject: [PATCH 07/18] :floppy_disk: still buggin --- core/state_processor.go | 18 +- core/state_processor_test.go | 474 ++++++++++++++++++++++++++++++++++- 2 files changed, 468 insertions(+), 24 deletions(-) diff --git a/core/state_processor.go b/core/state_processor.go index 4e6b645c3..158ad1023 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -168,14 +168,15 @@ func AccumulateRewards(config *ChainConfig, statedb *state.StateDB, header *type } // Ensure value 'era' is configured. - eraVal, ok := feat.GetBigInt("era") - if !ok || eraVal.Cmp(big.NewInt(0)) <= 0 { + eraLen, ok := feat.GetBigInt("era") + if !ok || eraLen.Cmp(big.NewInt(0)) <= 0 { panic(ErrConfiguration) } - era := GetBlockEra(header.Number, eraVal) + era := GetBlockEra(header.Number, eraLen) wr := GetBlockWinnerRewardByEra(era) // wr "winner reward". 5, 4, 3.2, 2.56, ... + wurs := GetBlockWinnerRewardForUnclesByEra(era, uncles) // wurs "winner uncle rewards" wr.Add(wr, wurs) @@ -192,12 +193,7 @@ func AccumulateRewards(config *ChainConfig, statedb *state.StateDB, header *type // As of "Era 2", uncle miners and winners are rewarded equally for each included block. // So they share this function. func getEraUncleBlockReward(era *big.Int) *big.Int { - - r := new(big.Int) - r.Add(r, GetBlockWinnerRewardByEra(era)) - r.Div(r, big.NewInt(32)) - - return r + return new(big.Int).Div(GetBlockWinnerRewardByEra(era), big32) } // GetBlockUncleRewardByEra gets called _for each uncle miner_ associated with a winner block's uncles. @@ -219,7 +215,7 @@ func GetBlockUncleRewardByEra(era *big.Int, header, uncle *types.Header) *big.In // GetBlockWinnerRewardForUnclesByEra gets called _per winner_, and accumulates rewards for each included uncle. func GetBlockWinnerRewardForUnclesByEra(era *big.Int, uncles []*types.Header) *big.Int { - r := new(big.Int) + r := big.NewInt(0) for range uncles { r.Add(r, getEraUncleBlockReward(era)) // can reuse this, since 1/32 for winner's uncles remain unchanged from "Era 1" @@ -255,5 +251,5 @@ func GetBlockEra(blockNum, eraLength *big.Int) *big.Int { d := big.NewInt(0).Div(base, eraLength) dremainder := big.NewInt(0).Mod(d, big.NewInt(1)) - return big.NewInt(0).Sub(d, dremainder) + return new(big.Int).Sub(d, dremainder) } \ No newline at end of file diff --git a/core/state_processor_test.go b/core/state_processor_test.go index 7b4ff82e6..2a9cc4166 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -73,9 +73,10 @@ func TestGetBlockUncleRewardByEra(t *testing.T) { var we1, we2, we3, we4 *big.Int = new(big.Int), new(big.Int), new(big.Int), new(big.Int) - we2.Div(GetBlockWinnerRewardByEra(big.NewInt(1)), big.NewInt(32)) - we3.Div(GetBlockWinnerRewardByEra(big.NewInt(2)), big.NewInt(32)) - we4.Div(GetBlockWinnerRewardByEra(big.NewInt(3)), big.NewInt(32)) + // manually divide maxblockreward/32 to compare to got + we2.Div(GetBlockWinnerRewardByEra(GetBlockEra(big.NewInt(5000001), DefaultEraLength)), big.NewInt(32)) + we3.Div(GetBlockWinnerRewardByEra(GetBlockEra(big.NewInt(10000001), DefaultEraLength)), big.NewInt(32)) + we4.Div(GetBlockWinnerRewardByEra(GetBlockEra(big.NewInt(15000001), DefaultEraLength)), big.NewInt(32)) cases := map[*big.Int]*big.Int{ big.NewInt(0): nil, @@ -163,11 +164,315 @@ func TestGetBlockWinnerRewardForUnclesByEra(t *testing.T) { } -func TestAccumulateRewards(t *testing.T) { +func fakeAccumulateRewards(config *ChainConfig, states map[common.Address]*big.Int, header *types.Header, uncles []*types.Header) { + feat, _, configured := config.GetFeature(header.Number, "reward") + if !configured { + reward := new(big.Int).Set(MaximumBlockReward) + r := new(big.Int) + + for _, uncle := range uncles { + r.Add(uncle.Number, big8) // 2,534,998 + 8 = 2,535,006 + r.Sub(r, header.Number) // 2,535,006 - 2,534,999 = 7 + r.Mul(r, MaximumBlockReward) // 7 * 5e+18 = 35e+18 + r.Div(r, big8) // 35e+18 / 8 = 7/8 * 5e+18 + + prevBal := states[uncle.Coinbase] + states[uncle.Coinbase] = new(big.Int).Add(prevBal, r) + //statedb.AddBalance(uncle.Coinbase, r) // $$ + + r.Div(MaximumBlockReward, big32) // 5e+18 / 32 + reward.Add(reward, r) // 5e+18 + (1/32*5e+18) + } + prevBal := states[header.Coinbase] + states[header.Coinbase] = new(big.Int).Add(prevBal, reward) + //states.AddBalance(header.Coinbase, reward) // $$ => 5e+18 + (1/32*5e+18) + } else { + // Check that configuration specifies ECIP1017. + val, ok := feat.GetString("type") + if !ok || val != "ecip1017" { + panic(ErrConfiguration) + } + + // Ensure value 'era' is configured. + eraLen, ok := feat.GetBigInt("era") + if !ok || eraLen.Cmp(big.NewInt(0)) <= 0 { + panic(ErrConfiguration) + } + + era := GetBlockEra(header.Number, eraLen) + + wr := GetBlockWinnerRewardByEra(era) // wr "winner reward". 5, 4, 3.2, 2.56, ... + wurs := GetBlockWinnerRewardForUnclesByEra(era, uncles) // wurs "winner uncle rewards" + wr.Add(wr, wurs) + + prevBal := states[header.Coinbase] + states[header.Coinbase] = new(big.Int).Add(prevBal, wr) + //states.AddBalance(header.Coinbase, wr) // $$ + + // Reward uncle miners. + for _, uncle := range uncles { + ur := GetBlockUncleRewardByEra(era, header, uncle) + prevBal := states[uncle.Coinbase] + states[uncle.Coinbase] = new(big.Int).Add(prevBal, ur) + //states.AddBalance(uncle.Coinbase, ur) // $$ + } + } +} + +// Accruing over block cases simulates compounding longevity of an account. +func TestAccumulateRewards0(t *testing.T) { + configs := []*ChainConfig{DefaultConfig, TestConfig} + for i, config := range configs { + dbTeston, _ := ethdb.NewMemDatabase() + dbTestwith, _ := ethdb.NewMemDatabase() + + //dumps := []*GenesisDump{DefaultGenesis, TestNetGenesis} + //genHead, e := dumps[i].Header() + //if e != nil { + // t.Fatalf("unexpected: %v", e) + //} + + //stateDB, err := state.New(genHead.Hash(), db) + stateDBTeston, err := state.New(common.Hash{}, dbTeston) + if err != nil { + t.Fatalf("could not open statedb: %v", err) + } + + stateDBTestwith, err := state.New(common.Hash{}, dbTestwith) + if err != nil { + t.Fatalf("could not open statedb: %v", err) + } + + var header *types.Header = &types.Header{} + var uncles []*types.Header = []*types.Header{{}, {}} + + if i == 0 { + header.Coinbase = common.StringToAddress("000d836201318ec6899a67540690382780743280") + uncles[0].Coinbase = common.StringToAddress("001762430ea9c3a26e5749afdb70da5f78ddbb8c") + uncles[1].Coinbase = common.StringToAddress("001d14804b399c6ef80e64576f657660804fec0b") + } else { + header.Coinbase = common.StringToAddress("0000000000000000000000000000000000000001") + uncles[0].Coinbase = common.StringToAddress("0000000000000000000000000000000000000002") + uncles[1].Coinbase = common.StringToAddress("0000000000000000000000000000000000000003") + } + + // Manual tallies for reward accumulation. + winnerB, totalB := new(big.Int), new(big.Int) + unclesB := []*big.Int{new(big.Int), new(big.Int)} + + winnerB = stateDBTeston.GetBalance(header.Coinbase) + unclesB[0] = stateDBTeston.GetBalance(uncles[0].Coinbase) + unclesB[1] = stateDBTeston.GetBalance(uncles[1].Coinbase) + + totalB.Add(totalB, winnerB) + totalB.Add(totalB, unclesB[0]) + totalB.Add(totalB, unclesB[1]) + + if totalB.Cmp(big.NewInt(0)) != 0 { + t.Errorf("unexpected: %v", totalB) + } + + // Manual tallies for reward accumulation. + winnerB, totalB = new(big.Int), new(big.Int) + unclesB = []*big.Int{new(big.Int), new(big.Int)} + + winnerB = stateDBTestwith.GetBalance(header.Coinbase) + unclesB[0] = stateDBTestwith.GetBalance(uncles[0].Coinbase) + unclesB[1] = stateDBTestwith.GetBalance(uncles[1].Coinbase) + + totalB.Add(totalB, winnerB) + totalB.Add(totalB, unclesB[0]) + totalB.Add(totalB, unclesB[1]) + + if totalB.Cmp(big.NewInt(0)) != 0 { + t.Errorf("unexpected: %v", totalB) + } + + cases := []*big.Int{ + //big.NewInt(0), + big.NewInt(13), + big.NewInt(4999999), + big.NewInt(5000000), + big.NewInt(5000001), + big.NewInt(9999999), + big.NewInt(10000000), + big.NewInt(10000000), + big.NewInt(10000001), + big.NewInt(14999999), + big.NewInt(15000000), + big.NewInt(15000001), + } + + for _, bn := range cases { + era := GetBlockEra(bn, DefaultEraLength) + t.Logf("era: %v", era) + + header.Number = bn + + for i, uncle := range uncles { + // rand.Seed(time.Now().UTC().UnixNano()) + // uncle.Number = new(big.Int).Sub(header.Number, big.NewInt(int64(rand.Int31n(int32(7))))) + uncle.Number = new(big.Int).Sub(header.Number, big.NewInt(int64(1))) // +i + + ur := GetBlockUncleRewardByEra(era, header, uncle) + t.Logf("ur: %v", ur) + unclesB[i].Add(unclesB[i], ur) + stateDBTestwith.AddBalance(uncles[i].Coinbase, ur) + + totalB.Add(totalB, ur) + } + + wr := GetBlockWinnerRewardByEra(era) + wr.Add(wr, GetBlockWinnerRewardForUnclesByEra(era, uncles)) + t.Logf("wr: %v", wr) + winnerB.Add(winnerB, wr) + stateDBTestwith.AddBalance(header.Coinbase, wr) + + totalB.Add(totalB, winnerB) + + AccumulateRewards(config, stateDBTeston, header, uncles) + + // Check balances. + if wb := stateDBTeston.GetBalance(header.Coinbase); wb.Cmp(stateDBTestwith.GetBalance(header.Coinbase)) != 0 { + t.Errorf("winner balance @ %v, want: %v, got: %v (config: %v)", bn, stateDBTestwith.GetBalance(header.Coinbase), wb, i) + } + if uB0 := stateDBTeston.GetBalance(uncles[0].Coinbase); unclesB[0].Cmp(stateDBTestwith.GetBalance(uncles[0].Coinbase)) != 0 { + t.Errorf("uncle1 balance @ %v, want: %v, got: %v (config: %v)", bn, stateDBTestwith.GetBalance(uncles[0].Coinbase), uB0, i) + } + if uB1 := stateDBTeston.GetBalance(uncles[1].Coinbase); unclesB[1].Cmp(stateDBTestwith.GetBalance(uncles[1].Coinbase)) != 0 { + t.Errorf("uncle2 balance @ %v, want: %v, got: %v (config: %v)", bn, stateDBTestwith.GetBalance(uncles[1].Coinbase), uB1, i) + } + // overflows int64 + //if bn.Cmp(big.NewInt(1)) == 0 && totalB.Cmp(big.NewInt(14.0625e+18)) != 0 { + // t.Errorf("total balance @ 1, want: %v, got: %v", bn, big.NewInt(14.0625e+18), totalB) + //} + } + dbTeston.Close() + dbTestwith.Close() + } +} + +// Accruing over block cases simulates compounding longevity of an account. +func TestAccumulateRewards1(t *testing.T) { + configs := []*ChainConfig{DefaultConfig, TestConfig} + for i, config := range configs { + db, _ := ethdb.NewMemDatabase() + + //dumps := []*GenesisDump{DefaultGenesis, TestNetGenesis} + //genHead, e := dumps[i].Header() + //if e != nil { + // t.Fatalf("unexpected: %v", e) + //} + + //stateDB, err := state.New(genHead.Hash(), db) + stateDB, err := state.New(common.Hash{}, db) + if err != nil { + t.Fatalf("could not open statedb: %v", err) + } + + var header *types.Header = &types.Header{} + var uncles []*types.Header = []*types.Header{{}, {}} + + if i == 0 { + header.Coinbase = common.StringToAddress("000d836201318ec6899a67540690382780743280") + uncles[0].Coinbase = common.StringToAddress("001762430ea9c3a26e5749afdb70da5f78ddbb8c") + uncles[1].Coinbase = common.StringToAddress("001d14804b399c6ef80e64576f657660804fec0b") + } else { + header.Coinbase = common.StringToAddress("0000000000000000000000000000000000000001") + uncles[0].Coinbase = common.StringToAddress("0000000000000000000000000000000000000002") + uncles[1].Coinbase = common.StringToAddress("0000000000000000000000000000000000000003") + } + + // Manual tallies for reward accumulation. + winnerB, totalB := new(big.Int), new(big.Int) + unclesB := []*big.Int{new(big.Int), new(big.Int)} + + winnerB = stateDB.GetBalance(header.Coinbase) + unclesB[0] = stateDB.GetBalance(uncles[0].Coinbase) + unclesB[1] = stateDB.GetBalance(uncles[1].Coinbase) + + totalB.Add(totalB, winnerB) + totalB.Add(totalB, unclesB[0]) + totalB.Add(totalB, unclesB[1]) + + if totalB.Cmp(big.NewInt(0)) != 0 { + t.Errorf("unexpected: %v", totalB) + } + + cases := []*big.Int{ + //big.NewInt(0), + big.NewInt(13), + big.NewInt(4999999), + big.NewInt(5000000), + big.NewInt(5000001), + big.NewInt(9999999), + big.NewInt(10000000), + big.NewInt(10000000), + big.NewInt(10000001), + big.NewInt(14999999), + big.NewInt(15000000), + big.NewInt(15000001), + } + + for _, bn := range cases { + era := GetBlockEra(bn, DefaultEraLength) + t.Logf("era: %v", era) + + header.Number = bn + + for i, uncle := range uncles { + // rand.Seed(time.Now().UTC().UnixNano()) + // uncle.Number = new(big.Int).Sub(header.Number, big.NewInt(int64(rand.Int31n(int32(7))))) + uncle.Number = new(big.Int).Sub(header.Number, big.NewInt(int64(1))) // +i + + ur := GetBlockUncleRewardByEra(era, header, uncle) + t.Logf("ur: %v", ur) + unclesB[i].Add(unclesB[i], ur) + + totalB.Add(totalB, ur) + } + + wr := GetBlockWinnerRewardByEra(era) + wr.Add(wr, GetBlockWinnerRewardForUnclesByEra(era, uncles)) + t.Logf("wr: %v", wr) + winnerB.Add(winnerB, wr) + + totalB.Add(totalB, winnerB) + + AccumulateRewards(config, stateDB, header, uncles) + + // Check balances. + if wb := stateDB.GetBalance(header.Coinbase); wb.Cmp(winnerB) != 0 { + t.Errorf("winner balance @ %v, want: %v, got: %v (config: %v)", bn, winnerB, wb, i) + } + if uB0 := stateDB.GetBalance(uncles[0].Coinbase); unclesB[0].Cmp(uB0) != 0 { + t.Errorf("uncle1 balance @ %v, want: %v, got: %v (config: %v)", bn, unclesB[0], uB0, i) + } + if uB1 := stateDB.GetBalance(uncles[1].Coinbase); unclesB[1].Cmp(uB1) != 0 { + t.Errorf("uncle2 balance @ %v, want: %v, got: %v (config: %v)", bn, unclesB[1], uB1, i) + } + // overflows int64 + //if bn.Cmp(big.NewInt(1)) == 0 && totalB.Cmp(big.NewInt(14.0625e+18)) != 0 { + // t.Errorf("total balance @ 1, want: %v, got: %v", bn, big.NewInt(14.0625e+18), totalB) + //} + } + db.Close() + } +} + +// Accruing over block cases simulates compounding longevity of an account. +func TestAccumulateRewards1_Fake(t *testing.T) { configs := []*ChainConfig{DefaultConfig, TestConfig} for i, config := range configs { db, _ := ethdb.NewMemDatabase() - defer db.Close() + + //dumps := []*GenesisDump{DefaultGenesis, TestNetGenesis} + //genHead, e := dumps[i].Header() + //if e != nil { + // t.Fatalf("unexpected: %v", e) + //} + + //stateDB, err := state.New(genHead.Hash(), db) stateDB, err := state.New(common.Hash{}, db) if err != nil { t.Fatalf("could not open statedb: %v", err) @@ -175,10 +480,20 @@ func TestAccumulateRewards(t *testing.T) { var header *types.Header = &types.Header{} var uncles []*types.Header = []*types.Header{{}, {}} + states := make(map[common.Address]*big.Int) - header.Coinbase = common.StringToAddress("0000000000000000000000000000000000000001") - uncles[0].Coinbase = common.StringToAddress("0000000000000000000000000000000000000002") - uncles[1].Coinbase = common.StringToAddress("0000000000000000000000000000000000000003") + if i == 0 { + header.Coinbase = common.StringToAddress("000d836201318ec6899a67540690382780743280") + uncles[0].Coinbase = common.StringToAddress("001762430ea9c3a26e5749afdb70da5f78ddbb8c") + uncles[1].Coinbase = common.StringToAddress("001d14804b399c6ef80e64576f657660804fec0b") + } else { + header.Coinbase = common.StringToAddress("0000000000000000000000000000000000000001") + uncles[0].Coinbase = common.StringToAddress("0000000000000000000000000000000000000002") + uncles[1].Coinbase = common.StringToAddress("0000000000000000000000000000000000000003") + } + states[header.Coinbase] = big.NewInt(0) + states[uncles[0].Coinbase] = big.NewInt(0) + states[uncles[1].Coinbase] = big.NewInt(0) // Manual tallies for reward accumulation. winnerB, totalB := new(big.Int), new(big.Int) @@ -188,14 +503,23 @@ func TestAccumulateRewards(t *testing.T) { unclesB[0] = stateDB.GetBalance(uncles[0].Coinbase) unclesB[1] = stateDB.GetBalance(uncles[1].Coinbase) + totalB.Add(totalB, winnerB) + totalB.Add(totalB, unclesB[0]) + totalB.Add(totalB, unclesB[1]) + + if totalB.Cmp(big.NewInt(0)) != 0 { + t.Errorf("unexpected: %v", totalB) + } + cases := []*big.Int{ //big.NewInt(0), - big.NewInt(1), + big.NewInt(13), big.NewInt(4999999), big.NewInt(5000000), big.NewInt(5000001), big.NewInt(9999999), big.NewInt(10000000), + big.NewInt(10000000), big.NewInt(10000001), big.NewInt(14999999), big.NewInt(15000000), @@ -204,17 +528,139 @@ func TestAccumulateRewards(t *testing.T) { for _, bn := range cases { era := GetBlockEra(bn, DefaultEraLength) + t.Logf("era: %v", era) header.Number = bn for i, uncle := range uncles { - //rand.Seed(time.Now().UTC().UnixNano()) - // TODO: is it ok to reuse same uncle numbers? it could happen... - //uncle.Number.Sub(header.Number, big.NewInt(int64(rand.Int31n(int32(7))))) + // rand.Seed(time.Now().UTC().UnixNano()) + // uncle.Number = new(big.Int).Sub(header.Number, big.NewInt(int64(rand.Int31n(int32(7))))) + uncle.Number = new(big.Int).Sub(header.Number, big.NewInt(int64(1))) // +i + + ur := GetBlockUncleRewardByEra(era, header, uncle) + t.Logf("ur: %v", ur) + unclesB[i].Add(unclesB[i], ur) + + totalB.Add(totalB, ur) + } + + wr := GetBlockWinnerRewardByEra(era) + wr.Add(wr, GetBlockWinnerRewardForUnclesByEra(era, uncles)) + t.Logf("wr: %v", wr) + winnerB.Add(winnerB, wr) + + totalB.Add(totalB, winnerB) + + fakeAccumulateRewards(config, states, header, uncles) + //AccumulateRewards(config, stateDB, header, uncles) + + // Check balances. + if wb := states[header.Coinbase]; wb.Cmp(winnerB) != 0 { + t.Errorf("winner balance @ %v, want: %v, got: %v (config: %v)", bn, winnerB, wb, i) + } + if uB0 := states[uncles[0].Coinbase]; unclesB[0].Cmp(uB0) != 0 { + t.Errorf("uncle1 balance @ %v, want: %v, got: %v (config: %v)", bn, unclesB[0], uB0, i) + } + if uB1 := states[uncles[1].Coinbase]; unclesB[1].Cmp(uB1) != 0 { + t.Errorf("uncle2 balance @ %v, want: %v, got: %v (config: %v)", bn, unclesB[1], uB1, i) + } + //if wb := stateDB.GetBalance(header.Coinbase); wb.Cmp(winnerB) != 0 { + // t.Errorf("winner balance @ %v, want: %v, got: %v (config: %v)", bn, winnerB, wb, i) + //} + //if uB0 := stateDB.GetBalance(uncles[0].Coinbase); unclesB[0].Cmp(uB0) != 0 { + // t.Errorf("uncle1 balance @ %v, want: %v, got: %v (config: %v)", bn, unclesB[0], uB0, i) + //} + //if uB1 := stateDB.GetBalance(uncles[1].Coinbase); unclesB[1].Cmp(uB1) != 0 { + // t.Errorf("uncle2 balance @ %v, want: %v, got: %v (config: %v)", bn, unclesB[1], uB1, i) + //} + // overflows int64 + //if bn.Cmp(big.NewInt(1)) == 0 && totalB.Cmp(big.NewInt(14.0625e+18)) != 0 { + // t.Errorf("total balance @ 1, want: %v, got: %v", bn, big.NewInt(14.0625e+18), totalB) + //} + } + db.Close() + } +} + +// Non-accruing over block cases simulates instance. +func TestAccumulateRewards2(t *testing.T) { + configs := []*ChainConfig{DefaultConfig, TestConfig} + for i, config := range configs { - uncle.Number = big.NewInt(0).Sub(header.Number, big.NewInt(1)) + cases := []*big.Int{ + //big.NewInt(0), + big.NewInt(13), + big.NewInt(4999999), + big.NewInt(5000000), + big.NewInt(5000001), + big.NewInt(9999999), + big.NewInt(10000000), + big.NewInt(10000001), + big.NewInt(14999999), + big.NewInt(15000000), + big.NewInt(15000001), + } + + for _, bn := range cases { + + db, _ := ethdb.NewMemDatabase() + + //dumps := []*GenesisDump{DefaultGenesis, TestNetGenesis} + //genHead, e := dumps[i].Header() + //if e != nil { + // t.Fatalf("unexpected: %v", e) + //} + + //stateDB, err := state.New(genHead.Hash(), db) + stateDB, err := state.New(common.Hash{}, db) + if err != nil { + t.Fatalf("could not open statedb: %v", err) + } + if err != nil { + t.Fatalf("could not open statedb: %v", err) + } + + var header *types.Header = &types.Header{} + var uncles []*types.Header = []*types.Header{{}, {}} + + if i == 0 { + header.Coinbase = common.StringToAddress("000d836201318ec6899a67540690382780743280") + uncles[0].Coinbase = common.StringToAddress("001762430ea9c3a26e5749afdb70da5f78ddbb8c") + uncles[1].Coinbase = common.StringToAddress("001d14804b399c6ef80e64576f657660804fec0b") + } else { + header.Coinbase = common.StringToAddress("0000000000000000000000000000000000000001") + uncles[0].Coinbase = common.StringToAddress("0000000000000000000000000000000000000002") + uncles[1].Coinbase = common.StringToAddress("0000000000000000000000000000000000000003") + } + + // Manual tallies for reward accumulation. + winnerB, totalB := new(big.Int), new(big.Int) + unclesB := []*big.Int{new(big.Int), new(big.Int)} + + winnerB = stateDB.GetBalance(header.Coinbase) + unclesB[0] = stateDB.GetBalance(uncles[0].Coinbase) + unclesB[1] = stateDB.GetBalance(uncles[1].Coinbase) + + totalB.Add(totalB, winnerB) + totalB.Add(totalB, unclesB[0]) + totalB.Add(totalB, unclesB[1]) + + if totalB.Cmp(big.NewInt(0)) != 0 { + t.Errorf("unexpected: %v", totalB) + } + + era := GetBlockEra(bn, DefaultEraLength) + t.Logf("era: %v", era) + + header.Number = bn + + for i, uncle := range uncles { + // rand.Seed(time.Now().UTC().UnixNano()) + // uncle.Number = new(big.Int).Sub(header.Number, big.NewInt(int64(rand.Int31n(int32(7))))) + uncle.Number = new(big.Int).Sub(header.Number, big.NewInt(int64(1))) // +i ur := GetBlockUncleRewardByEra(era, header, uncle) + t.Logf("ur: %v", ur) unclesB[i].Add(unclesB[i], ur) totalB.Add(totalB, ur) @@ -222,6 +668,7 @@ func TestAccumulateRewards(t *testing.T) { wr := GetBlockWinnerRewardByEra(era) wr.Add(wr, GetBlockWinnerRewardForUnclesByEra(era, uncles)) + t.Logf("wr: %v", wr) winnerB.Add(winnerB, wr) totalB.Add(totalB, winnerB) @@ -242,6 +689,7 @@ func TestAccumulateRewards(t *testing.T) { //if bn.Cmp(big.NewInt(1)) == 0 && totalB.Cmp(big.NewInt(14.0625e+18)) != 0 { // t.Errorf("total balance @ 1, want: %v, got: %v", bn, big.NewInt(14.0625e+18), totalB) //} + db.Close() } } } From 127d0efe4c78272ebdad5ecae59b861caabd8b0e Mon Sep 17 00:00:00 2001 From: "Mr. Is" Date: Tue, 9 May 2017 06:04:55 -0500 Subject: [PATCH 08/18] tests working for AccumulateRewards except era0 --- core/config.go | 19 + core/state_processor.go | 3 +- core/state_processor_test.go | 1191 +++++++++++++++++++--------------- 3 files changed, 706 insertions(+), 507 deletions(-) diff --git a/core/config.go b/core/config.go index f5bc91f6b..4bc3b51d1 100644 --- a/core/config.go +++ b/core/config.go @@ -312,6 +312,25 @@ func (c *ChainConfig) GetFeature(num *big.Int, id string) (*ForkFeature, *Fork, return okForkFeature, okFork, found } +// HasFeature looks up if fork feature exists _on any fork at any block_ in the configuration. +func (c *ChainConfig) HasFeature(id string) (*ForkFeature, *Fork, bool) { + var okForkFeature = &ForkFeature{} + var okFork = &Fork{} + var found = false + if id != "" { + for _, f := range c.Forks { + for _, ff := range f.Features { + if ff.ID == id { + okForkFeature = ff + okFork = f + found = true + } + } + } + } + return okForkFeature, okFork, found +} + func (c *ChainConfig) HeaderCheck(h *types.Header) error { for _, fork := range c.Forks { if fork.Block.Cmp(h.Number) != 0 { diff --git a/core/state_processor.go b/core/state_processor.go index 158ad1023..ba279477f 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -143,7 +143,7 @@ func AccumulateRewards(config *ChainConfig, statedb *state.StateDB, header *type // block.Number = 2,534,999 // uncles are at same height (?) // ... as uncles get older (within validation), reward drops - feat, _, configured := config.GetFeature(header.Number, "reward") + feat, _, configured := config.HasFeature("reward") if !configured { reward := new(big.Int).Set(MaximumBlockReward) r := new(big.Int) @@ -183,6 +183,7 @@ func AccumulateRewards(config *ChainConfig, statedb *state.StateDB, header *type statedb.AddBalance(header.Coinbase, wr) // $$ // Reward uncle miners. + for _, uncle := range uncles { ur := GetBlockUncleRewardByEra(era, header, uncle) statedb.AddBalance(uncle.Coinbase, ur) // $$ diff --git a/core/state_processor_test.go b/core/state_processor_test.go index 2a9cc4166..06e9aba84 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -17,6 +17,9 @@ func TestGetBlockEra(t *testing.T) { cases := map[*big.Int]*big.Int{ big.NewInt(0): big.NewInt(0), big.NewInt(1): big.NewInt(0), + big.NewInt(1914999): big.NewInt(0), + big.NewInt(1915000): big.NewInt(0), + big.NewInt(1915001): big.NewInt(0), big.NewInt(4999999): big.NewInt(0), big.NewInt(5000000): big.NewInt(0), big.NewInt(5000001): big.NewInt(1), @@ -164,532 +167,708 @@ func TestGetBlockWinnerRewardForUnclesByEra(t *testing.T) { } -func fakeAccumulateRewards(config *ChainConfig, states map[common.Address]*big.Int, header *types.Header, uncles []*types.Header) { - feat, _, configured := config.GetFeature(header.Number, "reward") - if !configured { - reward := new(big.Int).Set(MaximumBlockReward) - r := new(big.Int) - - for _, uncle := range uncles { - r.Add(uncle.Number, big8) // 2,534,998 + 8 = 2,535,006 - r.Sub(r, header.Number) // 2,535,006 - 2,534,999 = 7 - r.Mul(r, MaximumBlockReward) // 7 * 5e+18 = 35e+18 - r.Div(r, big8) // 35e+18 / 8 = 7/8 * 5e+18 - - prevBal := states[uncle.Coinbase] - states[uncle.Coinbase] = new(big.Int).Add(prevBal, r) - //statedb.AddBalance(uncle.Coinbase, r) // $$ - - r.Div(MaximumBlockReward, big32) // 5e+18 / 32 - reward.Add(reward, r) // 5e+18 + (1/32*5e+18) - } - prevBal := states[header.Coinbase] - states[header.Coinbase] = new(big.Int).Add(prevBal, reward) - //states.AddBalance(header.Coinbase, reward) // $$ => 5e+18 + (1/32*5e+18) - } else { - // Check that configuration specifies ECIP1017. - val, ok := feat.GetString("type") - if !ok || val != "ecip1017" { - panic(ErrConfiguration) - } - - // Ensure value 'era' is configured. - eraLen, ok := feat.GetBigInt("era") - if !ok || eraLen.Cmp(big.NewInt(0)) <= 0 { - panic(ErrConfiguration) - } - - era := GetBlockEra(header.Number, eraLen) - - wr := GetBlockWinnerRewardByEra(era) // wr "winner reward". 5, 4, 3.2, 2.56, ... - wurs := GetBlockWinnerRewardForUnclesByEra(era, uncles) // wurs "winner uncle rewards" - wr.Add(wr, wurs) - - prevBal := states[header.Coinbase] - states[header.Coinbase] = new(big.Int).Add(prevBal, wr) - //states.AddBalance(header.Coinbase, wr) // $$ +// +//func fakeAccumulateRewards(config *ChainConfig, states map[common.Address]*big.Int, header *types.Header, uncles []*types.Header) { +// feat, _, configured := config.GetFeature(header.Number, "reward") +// if !configured { +// reward := new(big.Int).Set(MaximumBlockReward) +// r := new(big.Int) +// +// for _, uncle := range uncles { +// r.Add(uncle.Number, big8) // 2,534,998 + 8 = 2,535,006 +// r.Sub(r, header.Number) // 2,535,006 - 2,534,999 = 7 +// r.Mul(r, MaximumBlockReward) // 7 * 5e+18 = 35e+18 +// r.Div(r, big8) // 35e+18 / 8 = 7/8 * 5e+18 +// +// prevBal := states[uncle.Coinbase] +// states[uncle.Coinbase] = new(big.Int).Add(prevBal, r) +// //statedb.AddBalance(uncle.Coinbase, r) // $$ +// +// r.Div(MaximumBlockReward, big32) // 5e+18 / 32 +// reward.Add(reward, r) // 5e+18 + (1/32*5e+18) +// } +// prevBal := states[header.Coinbase] +// states[header.Coinbase] = new(big.Int).Add(prevBal, reward) +// //states.AddBalance(header.Coinbase, reward) // $$ => 5e+18 + (1/32*5e+18) +// } else { +// // Check that configuration specifies ECIP1017. +// val, ok := feat.GetString("type") +// if !ok || val != "ecip1017" { +// panic(ErrConfiguration) +// } +// +// // Ensure value 'era' is configured. +// eraLen, ok := feat.GetBigInt("era") +// if !ok || eraLen.Cmp(big.NewInt(0)) <= 0 { +// panic(ErrConfiguration) +// } +// +// era := GetBlockEra(header.Number, eraLen) +// +// wr := GetBlockWinnerRewardByEra(era) // wr "winner reward". 5, 4, 3.2, 2.56, ... +// wurs := GetBlockWinnerRewardForUnclesByEra(era, uncles) // wurs "winner uncle rewards" +// wr.Add(wr, wurs) +// +// prevBal := states[header.Coinbase] +// states[header.Coinbase] = new(big.Int).Add(prevBal, wr) +// //states.AddBalance(header.Coinbase, wr) // $$ +// +// // Reward uncle miners. +// for _, uncle := range uncles { +// ur := GetBlockUncleRewardByEra(era, header, uncle) +// prevBal := states[uncle.Coinbase] +// states[uncle.Coinbase] = new(big.Int).Add(prevBal, ur) +// //states.AddBalance(uncle.Coinbase, ur) // $$ +// } +// } +//} +// +//// Accruing over block cases simulates compounding longevity of an account. +//// Uses two statedbs to maintain separate ledgers, with the 'testwith'db calling +//// AddBalance at tally points (instead of testing strictly through delegation to AccumulateRewards). +//// Ensures problem is not behind-the-scenes of statedb. +//func TestAccumulateRewards0(t *testing.T) { +// configs := []*ChainConfig{DefaultConfig, TestConfig} +// for i, config := range configs { +// dbTeston, _ := ethdb.NewMemDatabase() +// dbTestwith, _ := ethdb.NewMemDatabase() +// +// //dumps := []*GenesisDump{DefaultGenesis, TestNetGenesis} +// //genHead, e := dumps[i].Header() +// //if e != nil { +// // t.Fatalf("unexpected: %v", e) +// //} +// +// //stateDB, err := state.New(genHead.Hash(), db) +// stateDBTeston, err := state.New(common.Hash{}, dbTeston) +// if err != nil { +// t.Fatalf("could not open statedb: %v", err) +// } +// +// stateDBTestwith, err := state.New(common.Hash{}, dbTestwith) +// if err != nil { +// t.Fatalf("could not open statedb: %v", err) +// } +// +// var header *types.Header = &types.Header{} +// var uncles []*types.Header = []*types.Header{{}, {}} +// +// if i == 0 { +// header.Coinbase = common.StringToAddress("000d836201318ec6899a67540690382780743280") +// uncles[0].Coinbase = common.StringToAddress("001762430ea9c3a26e5749afdb70da5f78ddbb8c") +// uncles[1].Coinbase = common.StringToAddress("001d14804b399c6ef80e64576f657660804fec0b") +// } else { +// header.Coinbase = common.StringToAddress("0000000000000000000000000000000000000001") +// uncles[0].Coinbase = common.StringToAddress("0000000000000000000000000000000000000002") +// uncles[1].Coinbase = common.StringToAddress("0000000000000000000000000000000000000003") +// } +// +// // Manual tallies for reward accumulation. +// winnerB, totalB := new(big.Int), new(big.Int) +// unclesB := []*big.Int{new(big.Int), new(big.Int)} +// +// winnerB = stateDBTeston.GetBalance(header.Coinbase) +// unclesB[0] = stateDBTeston.GetBalance(uncles[0].Coinbase) +// unclesB[1] = stateDBTeston.GetBalance(uncles[1].Coinbase) +// +// totalB.Add(totalB, winnerB) +// totalB.Add(totalB, unclesB[0]) +// totalB.Add(totalB, unclesB[1]) +// +// if totalB.Cmp(big.NewInt(0)) != 0 { +// t.Errorf("unexpected: %v", totalB) +// } +// +// // Manual tallies for reward accumulation. +// winnerB, totalB = new(big.Int), new(big.Int) +// unclesB = []*big.Int{new(big.Int), new(big.Int)} +// +// winnerB = stateDBTestwith.GetBalance(header.Coinbase) +// unclesB[0] = stateDBTestwith.GetBalance(uncles[0].Coinbase) +// unclesB[1] = stateDBTestwith.GetBalance(uncles[1].Coinbase) +// +// totalB.Add(totalB, winnerB) +// totalB.Add(totalB, unclesB[0]) +// totalB.Add(totalB, unclesB[1]) +// +// if totalB.Cmp(big.NewInt(0)) != 0 { +// t.Errorf("unexpected: %v", totalB) +// } +// +// cases := []*big.Int{ +// //big.NewInt(0), +// big.NewInt(13), +// big.NewInt(4999999), +// big.NewInt(5000000), +// big.NewInt(5000001), +// big.NewInt(9999999), +// big.NewInt(10000000), +// big.NewInt(10000000), +// big.NewInt(10000001), +// big.NewInt(14999999), +// big.NewInt(15000000), +// big.NewInt(15000001), +// } +// +// for _, bn := range cases { +// era := GetBlockEra(bn, DefaultEraLength) +// t.Logf("era: %v", era) +// +// header.Number = bn +// +// for i, uncle := range uncles { +// // rand.Seed(time.Now().UTC().UnixNano()) +// // uncle.Number = new(big.Int).Sub(header.Number, big.NewInt(int64(rand.Int31n(int32(7))))) +// uncle.Number = new(big.Int).Sub(header.Number, big.NewInt(int64(1))) // +i +// +// ur := GetBlockUncleRewardByEra(era, header, uncle) +// t.Logf("ur: %v", ur) +// unclesB[i].Add(unclesB[i], ur) +// stateDBTestwith.AddBalance(uncles[i].Coinbase, ur) +// +// totalB.Add(totalB, ur) +// } +// +// wr := GetBlockWinnerRewardByEra(era) +// wr.Add(wr, GetBlockWinnerRewardForUnclesByEra(era, uncles)) +// t.Logf("wr: %v", wr) +// winnerB.Add(winnerB, wr) +// stateDBTestwith.AddBalance(header.Coinbase, wr) +// +// totalB.Add(totalB, winnerB) +// +// AccumulateRewards(config, stateDBTeston, header, uncles) +// +// // Check balances. +// if wb := stateDBTeston.GetBalance(header.Coinbase); wb.Cmp(stateDBTestwith.GetBalance(header.Coinbase)) != 0 { +// t.Errorf("winner balance @ %v, want: %v, got: %v (config: %v)", bn, stateDBTestwith.GetBalance(header.Coinbase), wb, i) +// } +// if uB0 := stateDBTeston.GetBalance(uncles[0].Coinbase); unclesB[0].Cmp(stateDBTestwith.GetBalance(uncles[0].Coinbase)) != 0 { +// t.Errorf("uncle1 balance @ %v, want: %v, got: %v (config: %v)", bn, stateDBTestwith.GetBalance(uncles[0].Coinbase), uB0, i) +// } +// if uB1 := stateDBTeston.GetBalance(uncles[1].Coinbase); unclesB[1].Cmp(stateDBTestwith.GetBalance(uncles[1].Coinbase)) != 0 { +// t.Errorf("uncle2 balance @ %v, want: %v, got: %v (config: %v)", bn, stateDBTestwith.GetBalance(uncles[1].Coinbase), uB1, i) +// } +// // overflows int64 +// //if bn.Cmp(big.NewInt(1)) == 0 && totalB.Cmp(big.NewInt(14.0625e+18)) != 0 { +// // t.Errorf("total balance @ 1, want: %v, got: %v", bn, big.NewInt(14.0625e+18), totalB) +// //} +// } +// dbTeston.Close() +// dbTestwith.Close() +// } +//} +// +//// Accruing over block cases simulates compounding longevity of an account. +//// Tests using maps of running sums for winner & 2 uncles, to keep tally. +//func TestAccumulateRewards1(t *testing.T) { +// configs := []*ChainConfig{DefaultConfig, TestConfig} +// for i, config := range configs { +// db, _ := ethdb.NewMemDatabase() +// +// //dumps := []*GenesisDump{DefaultGenesis, TestNetGenesis} +// //genHead, e := dumps[i].Header() +// //if e != nil { +// // t.Fatalf("unexpected: %v", e) +// //} +// +// //stateDB, err := state.New(genHead.Hash(), db) +// stateDB, err := state.New(common.Hash{}, db) +// if err != nil { +// t.Fatalf("could not open statedb: %v", err) +// } +// +// var header *types.Header = &types.Header{} +// var uncles []*types.Header = []*types.Header{{}, {}} +// +// if i == 0 { +// header.Coinbase = common.StringToAddress("000d836201318ec6899a67540690382780743280") +// uncles[0].Coinbase = common.StringToAddress("001762430ea9c3a26e5749afdb70da5f78ddbb8c") +// uncles[1].Coinbase = common.StringToAddress("001d14804b399c6ef80e64576f657660804fec0b") +// } else { +// header.Coinbase = common.StringToAddress("0000000000000000000000000000000000000001") +// uncles[0].Coinbase = common.StringToAddress("0000000000000000000000000000000000000002") +// uncles[1].Coinbase = common.StringToAddress("0000000000000000000000000000000000000003") +// } +// +// // Manual tallies for reward accumulation. +// winnerB, totalB := new(big.Int), new(big.Int) +// unclesB := []*big.Int{new(big.Int), new(big.Int)} +// +// winnerB = stateDB.GetBalance(header.Coinbase) +// unclesB[0] = stateDB.GetBalance(uncles[0].Coinbase) +// unclesB[1] = stateDB.GetBalance(uncles[1].Coinbase) +// +// totalB.Add(totalB, winnerB) +// totalB.Add(totalB, unclesB[0]) +// totalB.Add(totalB, unclesB[1]) +// +// if totalB.Cmp(big.NewInt(0)) != 0 { +// t.Errorf("unexpected: %v", totalB) +// } +// +// cases := []*big.Int{ +// //big.NewInt(0), +// big.NewInt(13), +// big.NewInt(4999999), +// big.NewInt(5000000), +// big.NewInt(5000001), +// big.NewInt(9999999), +// big.NewInt(10000000), +// big.NewInt(10000000), +// big.NewInt(10000001), +// big.NewInt(14999999), +// big.NewInt(15000000), +// big.NewInt(15000001), +// } +// +// for _, bn := range cases { +// era := GetBlockEra(bn, DefaultEraLength) +// t.Logf("era: %v", era) +// +// header.Number = bn +// +// for i, uncle := range uncles { +// // rand.Seed(time.Now().UTC().UnixNano()) +// // uncle.Number = new(big.Int).Sub(header.Number, big.NewInt(int64(rand.Int31n(int32(7))))) +// uncle.Number = new(big.Int).Sub(header.Number, big.NewInt(int64(1))) // +i +// +// ur := GetBlockUncleRewardByEra(era, header, uncle) +// t.Logf("ur: %v", ur) +// unclesB[i].Add(unclesB[i], ur) +// +// totalB.Add(totalB, ur) +// } +// +// wr := GetBlockWinnerRewardByEra(era) +// wr.Add(wr, GetBlockWinnerRewardForUnclesByEra(era, uncles)) +// t.Logf("wr: %v", wr) +// winnerB.Add(winnerB, wr) +// +// totalB.Add(totalB, winnerB) +// +// AccumulateRewards(config, stateDB, header, uncles) +// +// // Check balances. +// if wb := stateDB.GetBalance(header.Coinbase); wb.Cmp(winnerB) != 0 { +// t.Errorf("winner balance @ %v, want: %v, got: %v (config: %v)", bn, winnerB, wb, i) +// } +// if uB0 := stateDB.GetBalance(uncles[0].Coinbase); unclesB[0].Cmp(uB0) != 0 { +// t.Errorf("uncle1 balance @ %v, want: %v, got: %v (config: %v)", bn, unclesB[0], uB0, i) +// } +// if uB1 := stateDB.GetBalance(uncles[1].Coinbase); unclesB[1].Cmp(uB1) != 0 { +// t.Errorf("uncle2 balance @ %v, want: %v, got: %v (config: %v)", bn, unclesB[1], uB1, i) +// } +// // overflows int64 +// //if bn.Cmp(big.NewInt(1)) == 0 && totalB.Cmp(big.NewInt(14.0625e+18)) != 0 { +// // t.Errorf("total balance @ 1, want: %v, got: %v", bn, big.NewInt(14.0625e+18), totalB) +// //} +// } +// db.Close() +// } +//} +// +//// Tests a fake test, as found above. +//// The fake test does actually call statedb.AddBalance, but tallies sum +//// in a given map 'states'. +//// Accruing over block cases simulates compounding longevity of an account. +//func TestAccumulateRewards1_Fake(t *testing.T) { +// configs := []*ChainConfig{DefaultConfig, TestConfig} +// for i, config := range configs { +// db, _ := ethdb.NewMemDatabase() +// +// //dumps := []*GenesisDump{DefaultGenesis, TestNetGenesis} +// //genHead, e := dumps[i].Header() +// //if e != nil { +// // t.Fatalf("unexpected: %v", e) +// //} +// +// //stateDB, err := state.New(genHead.Hash(), db) +// stateDB, err := state.New(common.Hash{}, db) +// if err != nil { +// t.Fatalf("could not open statedb: %v", err) +// } +// +// var header *types.Header = &types.Header{} +// var uncles []*types.Header = []*types.Header{{}, {}} +// states := make(map[common.Address]*big.Int) +// +// if i == 0 { +// header.Coinbase = common.StringToAddress("000d836201318ec6899a67540690382780743280") +// uncles[0].Coinbase = common.StringToAddress("001762430ea9c3a26e5749afdb70da5f78ddbb8c") +// uncles[1].Coinbase = common.StringToAddress("001d14804b399c6ef80e64576f657660804fec0b") +// } else { +// header.Coinbase = common.StringToAddress("0000000000000000000000000000000000000001") +// uncles[0].Coinbase = common.StringToAddress("0000000000000000000000000000000000000002") +// uncles[1].Coinbase = common.StringToAddress("0000000000000000000000000000000000000003") +// } +// states[header.Coinbase] = big.NewInt(0) +// states[uncles[0].Coinbase] = big.NewInt(0) +// states[uncles[1].Coinbase] = big.NewInt(0) +// +// // Manual tallies for reward accumulation. +// winnerB, totalB := new(big.Int), new(big.Int) +// unclesB := []*big.Int{new(big.Int), new(big.Int)} +// +// winnerB = stateDB.GetBalance(header.Coinbase) +// unclesB[0] = stateDB.GetBalance(uncles[0].Coinbase) +// unclesB[1] = stateDB.GetBalance(uncles[1].Coinbase) +// +// totalB.Add(totalB, winnerB) +// totalB.Add(totalB, unclesB[0]) +// totalB.Add(totalB, unclesB[1]) +// +// if totalB.Cmp(big.NewInt(0)) != 0 { +// t.Errorf("unexpected: %v", totalB) +// } +// +// cases := []*big.Int{ +// //big.NewInt(0), +// big.NewInt(13), +// big.NewInt(4999999), +// big.NewInt(5000000), +// big.NewInt(5000001), +// big.NewInt(9999999), +// big.NewInt(10000000), +// big.NewInt(10000000), +// big.NewInt(10000001), +// big.NewInt(14999999), +// big.NewInt(15000000), +// big.NewInt(15000001), +// } +// +// for _, bn := range cases { +// era := GetBlockEra(bn, DefaultEraLength) +// t.Logf("era: %v", era) +// +// header.Number = bn +// +// for i, uncle := range uncles { +// // rand.Seed(time.Now().UTC().UnixNano()) +// // uncle.Number = new(big.Int).Sub(header.Number, big.NewInt(int64(rand.Int31n(int32(7))))) +// uncle.Number = new(big.Int).Sub(header.Number, big.NewInt(int64(1))) // +i +// +// ur := GetBlockUncleRewardByEra(era, header, uncle) +// t.Logf("ur: %v", ur) +// unclesB[i].Add(unclesB[i], ur) +// +// totalB.Add(totalB, ur) +// } +// +// wr := GetBlockWinnerRewardByEra(era) +// wr.Add(wr, GetBlockWinnerRewardForUnclesByEra(era, uncles)) +// t.Logf("wr: %v", wr) +// winnerB.Add(winnerB, wr) +// +// totalB.Add(totalB, winnerB) +// +// fakeAccumulateRewards(config, states, header, uncles) +// //AccumulateRewards(config, stateDB, header, uncles) +// +// // Check balances. +// if wb := states[header.Coinbase]; wb.Cmp(winnerB) != 0 { +// t.Errorf("winner balance @ %v, want: %v, got: %v (config: %v)", bn, winnerB, wb, i) +// } +// if uB0 := states[uncles[0].Coinbase]; unclesB[0].Cmp(uB0) != 0 { +// t.Errorf("uncle1 balance @ %v, want: %v, got: %v (config: %v)", bn, unclesB[0], uB0, i) +// } +// if uB1 := states[uncles[1].Coinbase]; unclesB[1].Cmp(uB1) != 0 { +// t.Errorf("uncle2 balance @ %v, want: %v, got: %v (config: %v)", bn, unclesB[1], uB1, i) +// } +// //if wb := stateDB.GetBalance(header.Coinbase); wb.Cmp(winnerB) != 0 { +// // t.Errorf("winner balance @ %v, want: %v, got: %v (config: %v)", bn, winnerB, wb, i) +// //} +// //if uB0 := stateDB.GetBalance(uncles[0].Coinbase); unclesB[0].Cmp(uB0) != 0 { +// // t.Errorf("uncle1 balance @ %v, want: %v, got: %v (config: %v)", bn, unclesB[0], uB0, i) +// //} +// //if uB1 := stateDB.GetBalance(uncles[1].Coinbase); unclesB[1].Cmp(uB1) != 0 { +// // t.Errorf("uncle2 balance @ %v, want: %v, got: %v (config: %v)", bn, unclesB[1], uB1, i) +// //} +// // overflows int64 +// //if bn.Cmp(big.NewInt(1)) == 0 && totalB.Cmp(big.NewInt(14.0625e+18)) != 0 { +// // t.Errorf("total balance @ 1, want: %v, got: %v", bn, big.NewInt(14.0625e+18), totalB) +// //} +// } +// db.Close() +// } +//} +// +//// Non-accruing over block cases simulates instance. +//func TestAccumulateRewards2(t *testing.T) { +// configs := []*ChainConfig{DefaultConfig, TestConfig} +// for i, config := range configs { +// +// cases := []*big.Int{ +// //big.NewInt(0), +// big.NewInt(13), +// big.NewInt(4999999), +// big.NewInt(5000000), +// big.NewInt(5000001), +// big.NewInt(9999999), +// big.NewInt(10000000), +// big.NewInt(10000001), +// big.NewInt(14999999), +// big.NewInt(15000000), +// big.NewInt(15000001), +// } +// +// for _, bn := range cases { +// +// db, _ := ethdb.NewMemDatabase() +// +// //dumps := []*GenesisDump{DefaultGenesis, TestNetGenesis} +// //genHead, e := dumps[i].Header() +// //if e != nil { +// // t.Fatalf("unexpected: %v", e) +// //} +// +// //stateDB, err := state.New(genHead.Hash(), db) +// stateDB, err := state.New(common.Hash{}, db) +// if err != nil { +// t.Fatalf("could not open statedb: %v", err) +// } +// if err != nil { +// t.Fatalf("could not open statedb: %v", err) +// } +// +// var header *types.Header = &types.Header{} +// var uncles []*types.Header = []*types.Header{{}, {}} +// +// if i == 0 { +// header.Coinbase = common.StringToAddress("000d836201318ec6899a67540690382780743280") +// uncles[0].Coinbase = common.StringToAddress("001762430ea9c3a26e5749afdb70da5f78ddbb8c") +// uncles[1].Coinbase = common.StringToAddress("001d14804b399c6ef80e64576f657660804fec0b") +// } else { +// header.Coinbase = common.StringToAddress("0000000000000000000000000000000000000001") +// uncles[0].Coinbase = common.StringToAddress("0000000000000000000000000000000000000002") +// uncles[1].Coinbase = common.StringToAddress("0000000000000000000000000000000000000003") +// } +// +// // Manual tallies for reward accumulation. +// winnerB, totalB := new(big.Int), new(big.Int) +// unclesB := []*big.Int{new(big.Int), new(big.Int)} +// +// winnerB = stateDB.GetBalance(header.Coinbase) +// unclesB[0] = stateDB.GetBalance(uncles[0].Coinbase) +// unclesB[1] = stateDB.GetBalance(uncles[1].Coinbase) +// +// totalB.Add(totalB, winnerB) +// totalB.Add(totalB, unclesB[0]) +// totalB.Add(totalB, unclesB[1]) +// +// if totalB.Cmp(big.NewInt(0)) != 0 { +// t.Errorf("unexpected: %v", totalB) +// } +// +// era := GetBlockEra(bn, DefaultEraLength) +// t.Logf("era: %v", era) +// +// header.Number = bn +// +// for i, uncle := range uncles { +// // rand.Seed(time.Now().UTC().UnixNano()) +// // uncle.Number = new(big.Int).Sub(header.Number, big.NewInt(int64(rand.Int31n(int32(7))))) +// uncle.Number = new(big.Int).Sub(header.Number, big.NewInt(int64(1))) // +i +// +// ur := GetBlockUncleRewardByEra(era, header, uncle) +// t.Logf("ur: %v", ur) +// unclesB[i].Add(unclesB[i], ur) +// +// totalB.Add(totalB, ur) +// } +// +// wr := GetBlockWinnerRewardByEra(era) +// wr.Add(wr, GetBlockWinnerRewardForUnclesByEra(era, uncles)) +// t.Logf("wr: %v", wr) +// winnerB.Add(winnerB, wr) +// +// totalB.Add(totalB, winnerB) +// +// AccumulateRewards(config, stateDB, header, uncles) +// +// // Check balances. +// if wb := stateDB.GetBalance(header.Coinbase); wb.Cmp(winnerB) != 0 { +// t.Errorf("winner balance @ %v, want: %v, got: %v (config: %v)", bn, winnerB, wb, i) +// } +// if uB0 := stateDB.GetBalance(uncles[0].Coinbase); unclesB[0].Cmp(uB0) != 0 { +// t.Errorf("uncle1 balance @ %v, want: %v, got: %v (config: %v)", bn, unclesB[0], uB0, i) +// } +// if uB1 := stateDB.GetBalance(uncles[1].Coinbase); unclesB[1].Cmp(uB1) != 0 { +// t.Errorf("uncle2 balance @ %v, want: %v, got: %v (config: %v)", bn, unclesB[1], uB1, i) +// } +// // overflows int64 +// //if bn.Cmp(big.NewInt(1)) == 0 && totalB.Cmp(big.NewInt(14.0625e+18)) != 0 { +// // t.Errorf("total balance @ 1, want: %v, got: %v", bn, big.NewInt(14.0625e+18), totalB) +// //} +// db.Close() +// } +// } +//} + +var ( + WinnerCoinbase = common.StringToAddress("0000000000000000000000000000000000000001") + Uncle1Coinbase = common.StringToAddress("0000000000000000000000000000000000000002") + Uncle2Coinbase = common.StringToAddress("0000000000000000000000000000000000000003") + + Era1WinnerReward = big.NewInt(5e+18) + Era1WinnerUncleReward = big.NewInt(156250000000000000) + Era1UncleReward = big.NewInt(4375000000000000000) + + Era2WinnerReward = big.NewInt(4e+18) + Era2WinnerUncleReward = new(big.Int).Div(big.NewInt(4e+18), big32) + Era2UncleReward = new(big.Int).Div(big.NewInt(4e+18), big32) + + Era3WinnerReward = new(big.Int).Mul(new(big.Int).Div(big.NewInt(4e+18), big.NewInt(5)), big.NewInt(4)) + Era3WinnerUncleReward = new(big.Int).Div(new(big.Int).Mul(new(big.Int).Div(big.NewInt(4e+18), big.NewInt(5)), big.NewInt(4)), big32) + Era3UncleReward = new(big.Int).Div(new(big.Int).Mul(new(big.Int).Div(big.NewInt(4e+18), big.NewInt(5)), big.NewInt(4)), big32) +) - // Reward uncle miners. - for _, uncle := range uncles { - ur := GetBlockUncleRewardByEra(era, header, uncle) - prevBal := states[uncle.Coinbase] - states[uncle.Coinbase] = new(big.Int).Add(prevBal, ur) - //states.AddBalance(uncle.Coinbase, ur) // $$ - } +// Non-accruing over block cases simulates instance. +func TestAccumulateRewards3_Testnet(t *testing.T) { + + type rewards map[common.Address]*big.Int + + cases := []struct { + block *big.Int + rewards rewards + }{ + //{ + // block: big.NewInt(13), + // rewards: rewards{ + // WinnerCoinbase: new(big.Int).Add(Era1WinnerReward, new(big.Int).Mul(Era1WinnerUncleReward, common.Big2)), + // Uncle1Coinbase: Era1UncleReward, + // Uncle2Coinbase: Era1UncleReward, + // }, + //}, + //{ + // block: big.NewInt(1914999), + // rewards: rewards{ + // WinnerCoinbase: new(big.Int).Add(Era1WinnerReward, new(big.Int).Mul(Era1WinnerUncleReward, common.Big2)), + // Uncle1Coinbase: Era1UncleReward, + // Uncle2Coinbase: Era1UncleReward, + // }, + //}, + //{ + // block: big.NewInt(1915000), + // rewards: rewards{ + // WinnerCoinbase: new(big.Int).Add(Era1WinnerReward, new(big.Int).Mul(Era1WinnerUncleReward, common.Big2)), + // Uncle1Coinbase: Era1UncleReward, + // Uncle2Coinbase: Era1UncleReward, + // }, + //}, + //{ + // block: big.NewInt(1915001), + // rewards: rewards{ + // WinnerCoinbase: new(big.Int).Add(Era1WinnerReward, new(big.Int).Mul(Era1WinnerUncleReward, common.Big2)), + // Uncle1Coinbase: Era1UncleReward, + // Uncle2Coinbase: Era1UncleReward, + // }, + //}, + //{ + // block: big.NewInt(4999999), + // rewards: rewards{ + // WinnerCoinbase: new(big.Int).Add(Era1WinnerReward, new(big.Int).Mul(Era1WinnerUncleReward, common.Big2)), + // Uncle1Coinbase: Era1UncleReward, + // Uncle2Coinbase: Era1UncleReward, + // }, + //}, + { + block: big.NewInt(5000001), + rewards: rewards{ + WinnerCoinbase: new(big.Int).Add(Era2WinnerReward, new(big.Int).Mul(Era2WinnerUncleReward, common.Big2)), + Uncle1Coinbase: Era2UncleReward, + Uncle2Coinbase: Era2UncleReward, + }, + }, + { + block: big.NewInt(5000010), + rewards: rewards{ + WinnerCoinbase: new(big.Int).Add(Era2WinnerReward, new(big.Int).Mul(Era2WinnerUncleReward, common.Big2)), + Uncle1Coinbase: Era2UncleReward, + Uncle2Coinbase: Era2UncleReward, + }, + }, + { + block: big.NewInt(10000000), + rewards: rewards{ + WinnerCoinbase: new(big.Int).Add(Era2WinnerReward, new(big.Int).Mul(Era2WinnerUncleReward, common.Big2)), + Uncle1Coinbase: Era2UncleReward, + Uncle2Coinbase: Era2UncleReward, + }, + }, + { + block: big.NewInt(10000001), + rewards: rewards{ + WinnerCoinbase: new(big.Int).Add(Era3WinnerReward, new(big.Int).Mul(Era3WinnerUncleReward, common.Big2)), + Uncle1Coinbase: Era3UncleReward, + Uncle2Coinbase: Era3UncleReward, + }, + }, + { + block: big.NewInt(15000000), + rewards: rewards{ + WinnerCoinbase: new(big.Int).Add(Era3WinnerReward, new(big.Int).Mul(Era3WinnerUncleReward, common.Big2)), + Uncle1Coinbase: Era3UncleReward, + Uncle2Coinbase: Era3UncleReward, + }, + }, } -} - -// Accruing over block cases simulates compounding longevity of an account. -func TestAccumulateRewards0(t *testing.T) { - configs := []*ChainConfig{DefaultConfig, TestConfig} - for i, config := range configs { - dbTeston, _ := ethdb.NewMemDatabase() - dbTestwith, _ := ethdb.NewMemDatabase() - - //dumps := []*GenesisDump{DefaultGenesis, TestNetGenesis} - //genHead, e := dumps[i].Header() - //if e != nil { - // t.Fatalf("unexpected: %v", e) - //} - - //stateDB, err := state.New(genHead.Hash(), db) - stateDBTeston, err := state.New(common.Hash{}, dbTeston) - if err != nil { - t.Fatalf("could not open statedb: %v", err) - } - - stateDBTestwith, err := state.New(common.Hash{}, dbTestwith) - if err != nil { - t.Fatalf("could not open statedb: %v", err) - } - - var header *types.Header = &types.Header{} - var uncles []*types.Header = []*types.Header{{}, {}} - - if i == 0 { - header.Coinbase = common.StringToAddress("000d836201318ec6899a67540690382780743280") - uncles[0].Coinbase = common.StringToAddress("001762430ea9c3a26e5749afdb70da5f78ddbb8c") - uncles[1].Coinbase = common.StringToAddress("001d14804b399c6ef80e64576f657660804fec0b") - } else { - header.Coinbase = common.StringToAddress("0000000000000000000000000000000000000001") - uncles[0].Coinbase = common.StringToAddress("0000000000000000000000000000000000000002") - uncles[1].Coinbase = common.StringToAddress("0000000000000000000000000000000000000003") - } - - // Manual tallies for reward accumulation. - winnerB, totalB := new(big.Int), new(big.Int) - unclesB := []*big.Int{new(big.Int), new(big.Int)} - - winnerB = stateDBTeston.GetBalance(header.Coinbase) - unclesB[0] = stateDBTeston.GetBalance(uncles[0].Coinbase) - unclesB[1] = stateDBTeston.GetBalance(uncles[1].Coinbase) - totalB.Add(totalB, winnerB) - totalB.Add(totalB, unclesB[0]) - totalB.Add(totalB, unclesB[1]) - - if totalB.Cmp(big.NewInt(0)) != 0 { - t.Errorf("unexpected: %v", totalB) - } + for _, c := range cases { - // Manual tallies for reward accumulation. - winnerB, totalB = new(big.Int), new(big.Int) - unclesB = []*big.Int{new(big.Int), new(big.Int)} - - winnerB = stateDBTestwith.GetBalance(header.Coinbase) - unclesB[0] = stateDBTestwith.GetBalance(uncles[0].Coinbase) - unclesB[1] = stateDBTestwith.GetBalance(uncles[1].Coinbase) - - totalB.Add(totalB, winnerB) - totalB.Add(totalB, unclesB[0]) - totalB.Add(totalB, unclesB[1]) - - if totalB.Cmp(big.NewInt(0)) != 0 { - t.Errorf("unexpected: %v", totalB) - } - - cases := []*big.Int{ - //big.NewInt(0), - big.NewInt(13), - big.NewInt(4999999), - big.NewInt(5000000), - big.NewInt(5000001), - big.NewInt(9999999), - big.NewInt(10000000), - big.NewInt(10000000), - big.NewInt(10000001), - big.NewInt(14999999), - big.NewInt(15000000), - big.NewInt(15000001), - } - - for _, bn := range cases { - era := GetBlockEra(bn, DefaultEraLength) - t.Logf("era: %v", era) - - header.Number = bn - - for i, uncle := range uncles { - // rand.Seed(time.Now().UTC().UnixNano()) - // uncle.Number = new(big.Int).Sub(header.Number, big.NewInt(int64(rand.Int31n(int32(7))))) - uncle.Number = new(big.Int).Sub(header.Number, big.NewInt(int64(1))) // +i - - ur := GetBlockUncleRewardByEra(era, header, uncle) - t.Logf("ur: %v", ur) - unclesB[i].Add(unclesB[i], ur) - stateDBTestwith.AddBalance(uncles[i].Coinbase, ur) - - totalB.Add(totalB, ur) - } - - wr := GetBlockWinnerRewardByEra(era) - wr.Add(wr, GetBlockWinnerRewardForUnclesByEra(era, uncles)) - t.Logf("wr: %v", wr) - winnerB.Add(winnerB, wr) - stateDBTestwith.AddBalance(header.Coinbase, wr) - - totalB.Add(totalB, winnerB) - - AccumulateRewards(config, stateDBTeston, header, uncles) - - // Check balances. - if wb := stateDBTeston.GetBalance(header.Coinbase); wb.Cmp(stateDBTestwith.GetBalance(header.Coinbase)) != 0 { - t.Errorf("winner balance @ %v, want: %v, got: %v (config: %v)", bn, stateDBTestwith.GetBalance(header.Coinbase), wb, i) - } - if uB0 := stateDBTeston.GetBalance(uncles[0].Coinbase); unclesB[0].Cmp(stateDBTestwith.GetBalance(uncles[0].Coinbase)) != 0 { - t.Errorf("uncle1 balance @ %v, want: %v, got: %v (config: %v)", bn, stateDBTestwith.GetBalance(uncles[0].Coinbase), uB0, i) - } - if uB1 := stateDBTeston.GetBalance(uncles[1].Coinbase); unclesB[1].Cmp(stateDBTestwith.GetBalance(uncles[1].Coinbase)) != 0 { - t.Errorf("uncle2 balance @ %v, want: %v, got: %v (config: %v)", bn, stateDBTestwith.GetBalance(uncles[1].Coinbase), uB1, i) - } - // overflows int64 - //if bn.Cmp(big.NewInt(1)) == 0 && totalB.Cmp(big.NewInt(14.0625e+18)) != 0 { - // t.Errorf("total balance @ 1, want: %v, got: %v", bn, big.NewInt(14.0625e+18), totalB) - //} - } - dbTeston.Close() - dbTestwith.Close() - } -} - -// Accruing over block cases simulates compounding longevity of an account. -func TestAccumulateRewards1(t *testing.T) { - configs := []*ChainConfig{DefaultConfig, TestConfig} - for i, config := range configs { db, _ := ethdb.NewMemDatabase() - - //dumps := []*GenesisDump{DefaultGenesis, TestNetGenesis} - //genHead, e := dumps[i].Header() - //if e != nil { - // t.Fatalf("unexpected: %v", e) - //} - - //stateDB, err := state.New(genHead.Hash(), db) stateDB, err := state.New(common.Hash{}, db) if err != nil { t.Fatalf("could not open statedb: %v", err) } - var header *types.Header = &types.Header{} - var uncles []*types.Header = []*types.Header{{}, {}} - - if i == 0 { - header.Coinbase = common.StringToAddress("000d836201318ec6899a67540690382780743280") - uncles[0].Coinbase = common.StringToAddress("001762430ea9c3a26e5749afdb70da5f78ddbb8c") - uncles[1].Coinbase = common.StringToAddress("001d14804b399c6ef80e64576f657660804fec0b") - } else { - header.Coinbase = common.StringToAddress("0000000000000000000000000000000000000001") - uncles[0].Coinbase = common.StringToAddress("0000000000000000000000000000000000000002") - uncles[1].Coinbase = common.StringToAddress("0000000000000000000000000000000000000003") + var winner *types.Header = &types.Header{ + Number: c.block, + Coinbase: WinnerCoinbase, } - - // Manual tallies for reward accumulation. - winnerB, totalB := new(big.Int), new(big.Int) - unclesB := []*big.Int{new(big.Int), new(big.Int)} - - winnerB = stateDB.GetBalance(header.Coinbase) - unclesB[0] = stateDB.GetBalance(uncles[0].Coinbase) - unclesB[1] = stateDB.GetBalance(uncles[1].Coinbase) - - totalB.Add(totalB, winnerB) - totalB.Add(totalB, unclesB[0]) - totalB.Add(totalB, unclesB[1]) - - if totalB.Cmp(big.NewInt(0)) != 0 { - t.Errorf("unexpected: %v", totalB) - } - - cases := []*big.Int{ - //big.NewInt(0), - big.NewInt(13), - big.NewInt(4999999), - big.NewInt(5000000), - big.NewInt(5000001), - big.NewInt(9999999), - big.NewInt(10000000), - big.NewInt(10000000), - big.NewInt(10000001), - big.NewInt(14999999), - big.NewInt(15000000), - big.NewInt(15000001), - } - - for _, bn := range cases { - era := GetBlockEra(bn, DefaultEraLength) - t.Logf("era: %v", era) - - header.Number = bn - - for i, uncle := range uncles { - // rand.Seed(time.Now().UTC().UnixNano()) - // uncle.Number = new(big.Int).Sub(header.Number, big.NewInt(int64(rand.Int31n(int32(7))))) - uncle.Number = new(big.Int).Sub(header.Number, big.NewInt(int64(1))) // +i - - ur := GetBlockUncleRewardByEra(era, header, uncle) - t.Logf("ur: %v", ur) - unclesB[i].Add(unclesB[i], ur) - - totalB.Add(totalB, ur) - } - - wr := GetBlockWinnerRewardByEra(era) - wr.Add(wr, GetBlockWinnerRewardForUnclesByEra(era, uncles)) - t.Logf("wr: %v", wr) - winnerB.Add(winnerB, wr) - - totalB.Add(totalB, winnerB) - - AccumulateRewards(config, stateDB, header, uncles) - - // Check balances. - if wb := stateDB.GetBalance(header.Coinbase); wb.Cmp(winnerB) != 0 { - t.Errorf("winner balance @ %v, want: %v, got: %v (config: %v)", bn, winnerB, wb, i) - } - if uB0 := stateDB.GetBalance(uncles[0].Coinbase); unclesB[0].Cmp(uB0) != 0 { - t.Errorf("uncle1 balance @ %v, want: %v, got: %v (config: %v)", bn, unclesB[0], uB0, i) - } - if uB1 := stateDB.GetBalance(uncles[1].Coinbase); unclesB[1].Cmp(uB1) != 0 { - t.Errorf("uncle2 balance @ %v, want: %v, got: %v (config: %v)", bn, unclesB[1], uB1, i) - } - // overflows int64 - //if bn.Cmp(big.NewInt(1)) == 0 && totalB.Cmp(big.NewInt(14.0625e+18)) != 0 { - // t.Errorf("total balance @ 1, want: %v, got: %v", bn, big.NewInt(14.0625e+18), totalB) - //} + var uncles []*types.Header = []*types.Header{{ + Number: new(big.Int).Sub(c.block, common.Big1), + Coinbase: Uncle1Coinbase, + }, { + Number: new(big.Int).Sub(c.block, common.Big1), + Coinbase: Uncle2Coinbase, + }} + + gotWinnerBalance := stateDB.GetBalance(winner.Coinbase) + gotUncle1Balance := stateDB.GetBalance(Uncle1Coinbase) + gotUncle2Balance := stateDB.GetBalance(Uncle2Coinbase) + r := new(big.Int) + r.Add(gotWinnerBalance, gotUncle1Balance) + r.Add(r, gotUncle2Balance) + if r.Cmp(big.NewInt(0)) != 0 { + t.Errorf("unexpected: %v", r) } - db.Close() - } -} - -// Accruing over block cases simulates compounding longevity of an account. -func TestAccumulateRewards1_Fake(t *testing.T) { - configs := []*ChainConfig{DefaultConfig, TestConfig} - for i, config := range configs { - db, _ := ethdb.NewMemDatabase() - //dumps := []*GenesisDump{DefaultGenesis, TestNetGenesis} - //genHead, e := dumps[i].Header() - //if e != nil { - // t.Fatalf("unexpected: %v", e) - //} + AccumulateRewards(TestConfig, stateDB, winner, uncles) + gotWinnerBalance = stateDB.GetBalance(winner.Coinbase) + gotUncle1Balance = stateDB.GetBalance(Uncle1Coinbase) + gotUncle2Balance = stateDB.GetBalance(Uncle2Coinbase) - //stateDB, err := state.New(genHead.Hash(), db) - stateDB, err := state.New(common.Hash{}, db) - if err != nil { - t.Fatalf("could not open statedb: %v", err) + feat, _, configured := TestConfig.HasFeature("reward") + if !configured { + t.Error("unexpected reward feature not configured") } - - var header *types.Header = &types.Header{} - var uncles []*types.Header = []*types.Header{{}, {}} - states := make(map[common.Address]*big.Int) - - if i == 0 { - header.Coinbase = common.StringToAddress("000d836201318ec6899a67540690382780743280") - uncles[0].Coinbase = common.StringToAddress("001762430ea9c3a26e5749afdb70da5f78ddbb8c") - uncles[1].Coinbase = common.StringToAddress("001d14804b399c6ef80e64576f657660804fec0b") - } else { - header.Coinbase = common.StringToAddress("0000000000000000000000000000000000000001") - uncles[0].Coinbase = common.StringToAddress("0000000000000000000000000000000000000002") - uncles[1].Coinbase = common.StringToAddress("0000000000000000000000000000000000000003") + eraLen, ok := feat.GetBigInt("era") + if !ok { + t.Error("unexpected reward length not configured") } - states[header.Coinbase] = big.NewInt(0) - states[uncles[0].Coinbase] = big.NewInt(0) - states[uncles[1].Coinbase] = big.NewInt(0) - - // Manual tallies for reward accumulation. - winnerB, totalB := new(big.Int), new(big.Int) - unclesB := []*big.Int{new(big.Int), new(big.Int)} - - winnerB = stateDB.GetBalance(header.Coinbase) - unclesB[0] = stateDB.GetBalance(uncles[0].Coinbase) - unclesB[1] = stateDB.GetBalance(uncles[1].Coinbase) + era := GetBlockEra(c.block, eraLen) - totalB.Add(totalB, winnerB) - totalB.Add(totalB, unclesB[0]) - totalB.Add(totalB, unclesB[1]) - - if totalB.Cmp(big.NewInt(0)) != 0 { - t.Errorf("unexpected: %v", totalB) + // Check balances. + if gotWinnerBalance.Cmp(c.rewards[WinnerCoinbase]) != 0 { + t.Errorf("Era %v: winner balance @ %v, want: %v, got: %v, \n-> diff: %v", era, c.block, c.rewards[WinnerCoinbase], gotWinnerBalance, new(big.Int).Sub(gotWinnerBalance, c.rewards[WinnerCoinbase])) } - - cases := []*big.Int{ - //big.NewInt(0), - big.NewInt(13), - big.NewInt(4999999), - big.NewInt(5000000), - big.NewInt(5000001), - big.NewInt(9999999), - big.NewInt(10000000), - big.NewInt(10000000), - big.NewInt(10000001), - big.NewInt(14999999), - big.NewInt(15000000), - big.NewInt(15000001), + if gotUncle1Balance.Cmp(c.rewards[Uncle1Coinbase]) != 0 { + t.Errorf("Era %v: uncle1 balance @ %v, want: %v, got: %v, \n-> diff: %v", era, c.block, c.rewards[Uncle1Coinbase], gotUncle1Balance, new(big.Int).Sub(gotUncle1Balance, c.rewards[Uncle1Coinbase])) } - - for _, bn := range cases { - era := GetBlockEra(bn, DefaultEraLength) - t.Logf("era: %v", era) - - header.Number = bn - - for i, uncle := range uncles { - // rand.Seed(time.Now().UTC().UnixNano()) - // uncle.Number = new(big.Int).Sub(header.Number, big.NewInt(int64(rand.Int31n(int32(7))))) - uncle.Number = new(big.Int).Sub(header.Number, big.NewInt(int64(1))) // +i - - ur := GetBlockUncleRewardByEra(era, header, uncle) - t.Logf("ur: %v", ur) - unclesB[i].Add(unclesB[i], ur) - - totalB.Add(totalB, ur) - } - - wr := GetBlockWinnerRewardByEra(era) - wr.Add(wr, GetBlockWinnerRewardForUnclesByEra(era, uncles)) - t.Logf("wr: %v", wr) - winnerB.Add(winnerB, wr) - - totalB.Add(totalB, winnerB) - - fakeAccumulateRewards(config, states, header, uncles) - //AccumulateRewards(config, stateDB, header, uncles) - - // Check balances. - if wb := states[header.Coinbase]; wb.Cmp(winnerB) != 0 { - t.Errorf("winner balance @ %v, want: %v, got: %v (config: %v)", bn, winnerB, wb, i) - } - if uB0 := states[uncles[0].Coinbase]; unclesB[0].Cmp(uB0) != 0 { - t.Errorf("uncle1 balance @ %v, want: %v, got: %v (config: %v)", bn, unclesB[0], uB0, i) - } - if uB1 := states[uncles[1].Coinbase]; unclesB[1].Cmp(uB1) != 0 { - t.Errorf("uncle2 balance @ %v, want: %v, got: %v (config: %v)", bn, unclesB[1], uB1, i) - } - //if wb := stateDB.GetBalance(header.Coinbase); wb.Cmp(winnerB) != 0 { - // t.Errorf("winner balance @ %v, want: %v, got: %v (config: %v)", bn, winnerB, wb, i) - //} - //if uB0 := stateDB.GetBalance(uncles[0].Coinbase); unclesB[0].Cmp(uB0) != 0 { - // t.Errorf("uncle1 balance @ %v, want: %v, got: %v (config: %v)", bn, unclesB[0], uB0, i) - //} - //if uB1 := stateDB.GetBalance(uncles[1].Coinbase); unclesB[1].Cmp(uB1) != 0 { - // t.Errorf("uncle2 balance @ %v, want: %v, got: %v (config: %v)", bn, unclesB[1], uB1, i) - //} - // overflows int64 - //if bn.Cmp(big.NewInt(1)) == 0 && totalB.Cmp(big.NewInt(14.0625e+18)) != 0 { - // t.Errorf("total balance @ 1, want: %v, got: %v", bn, big.NewInt(14.0625e+18), totalB) - //} + if gotUncle2Balance.Cmp(c.rewards[Uncle2Coinbase]) != 0 { + t.Errorf("Era %v: uncle2 balance @ %v, want: %v, got: %v, \n-> diff: %v", era, c.block, c.rewards[Uncle2Coinbase], gotUncle2Balance, new(big.Int).Sub(gotUncle2Balance, c.rewards[Uncle2Coinbase])) } db.Close() } } - -// Non-accruing over block cases simulates instance. -func TestAccumulateRewards2(t *testing.T) { - configs := []*ChainConfig{DefaultConfig, TestConfig} - for i, config := range configs { - - cases := []*big.Int{ - //big.NewInt(0), - big.NewInt(13), - big.NewInt(4999999), - big.NewInt(5000000), - big.NewInt(5000001), - big.NewInt(9999999), - big.NewInt(10000000), - big.NewInt(10000001), - big.NewInt(14999999), - big.NewInt(15000000), - big.NewInt(15000001), - } - - for _, bn := range cases { - - db, _ := ethdb.NewMemDatabase() - - //dumps := []*GenesisDump{DefaultGenesis, TestNetGenesis} - //genHead, e := dumps[i].Header() - //if e != nil { - // t.Fatalf("unexpected: %v", e) - //} - - //stateDB, err := state.New(genHead.Hash(), db) - stateDB, err := state.New(common.Hash{}, db) - if err != nil { - t.Fatalf("could not open statedb: %v", err) - } - if err != nil { - t.Fatalf("could not open statedb: %v", err) - } - - var header *types.Header = &types.Header{} - var uncles []*types.Header = []*types.Header{{}, {}} - - if i == 0 { - header.Coinbase = common.StringToAddress("000d836201318ec6899a67540690382780743280") - uncles[0].Coinbase = common.StringToAddress("001762430ea9c3a26e5749afdb70da5f78ddbb8c") - uncles[1].Coinbase = common.StringToAddress("001d14804b399c6ef80e64576f657660804fec0b") - } else { - header.Coinbase = common.StringToAddress("0000000000000000000000000000000000000001") - uncles[0].Coinbase = common.StringToAddress("0000000000000000000000000000000000000002") - uncles[1].Coinbase = common.StringToAddress("0000000000000000000000000000000000000003") - } - - // Manual tallies for reward accumulation. - winnerB, totalB := new(big.Int), new(big.Int) - unclesB := []*big.Int{new(big.Int), new(big.Int)} - - winnerB = stateDB.GetBalance(header.Coinbase) - unclesB[0] = stateDB.GetBalance(uncles[0].Coinbase) - unclesB[1] = stateDB.GetBalance(uncles[1].Coinbase) - - totalB.Add(totalB, winnerB) - totalB.Add(totalB, unclesB[0]) - totalB.Add(totalB, unclesB[1]) - - if totalB.Cmp(big.NewInt(0)) != 0 { - t.Errorf("unexpected: %v", totalB) - } - - era := GetBlockEra(bn, DefaultEraLength) - t.Logf("era: %v", era) - - header.Number = bn - - for i, uncle := range uncles { - // rand.Seed(time.Now().UTC().UnixNano()) - // uncle.Number = new(big.Int).Sub(header.Number, big.NewInt(int64(rand.Int31n(int32(7))))) - uncle.Number = new(big.Int).Sub(header.Number, big.NewInt(int64(1))) // +i - - ur := GetBlockUncleRewardByEra(era, header, uncle) - t.Logf("ur: %v", ur) - unclesB[i].Add(unclesB[i], ur) - - totalB.Add(totalB, ur) - } - - wr := GetBlockWinnerRewardByEra(era) - wr.Add(wr, GetBlockWinnerRewardForUnclesByEra(era, uncles)) - t.Logf("wr: %v", wr) - winnerB.Add(winnerB, wr) - - totalB.Add(totalB, winnerB) - - AccumulateRewards(config, stateDB, header, uncles) - - // Check balances. - if wb := stateDB.GetBalance(header.Coinbase); wb.Cmp(winnerB) != 0 { - t.Errorf("winner balance @ %v, want: %v, got: %v (config: %v)", bn, winnerB, wb, i) - } - if uB0 := stateDB.GetBalance(uncles[0].Coinbase); unclesB[0].Cmp(uB0) != 0 { - t.Errorf("uncle1 balance @ %v, want: %v, got: %v (config: %v)", bn, unclesB[0], uB0, i) - } - if uB1 := stateDB.GetBalance(uncles[1].Coinbase); unclesB[1].Cmp(uB1) != 0 { - t.Errorf("uncle2 balance @ %v, want: %v, got: %v (config: %v)", bn, unclesB[1], uB1, i) - } - // overflows int64 - //if bn.Cmp(big.NewInt(1)) == 0 && totalB.Cmp(big.NewInt(14.0625e+18)) != 0 { - // t.Errorf("total balance @ 1, want: %v, got: %v", bn, big.NewInt(14.0625e+18), totalB) - //} - db.Close() - } - } -} From 1a55aed7d4c13e6410c407ab63b67e2a6862a481 Mon Sep 17 00:00:00 2001 From: "Mr. Is" Date: Tue, 9 May 2017 06:13:00 -0500 Subject: [PATCH 09/18] tests: all passing state_processor --- core/state_processor.go | 23 ++++---- core/state_processor_test.go | 106 +++++++++++++++++++++-------------- 2 files changed, 76 insertions(+), 53 deletions(-) diff --git a/core/state_processor.go b/core/state_processor.go index ba279477f..782224dc7 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -19,14 +19,15 @@ package core import ( "math/big" + "errors" "fmt" + "github.com/ethereumproject/go-ethereum/core/state" "github.com/ethereumproject/go-ethereum/core/types" "github.com/ethereumproject/go-ethereum/core/vm" "github.com/ethereumproject/go-ethereum/crypto" "github.com/ethereumproject/go-ethereum/logger" "github.com/ethereumproject/go-ethereum/logger/glog" - "errors" ) var ( @@ -149,15 +150,15 @@ func AccumulateRewards(config *ChainConfig, statedb *state.StateDB, header *type r := new(big.Int) for _, uncle := range uncles { - r.Add(uncle.Number, big8) // 2,534,998 + 8 = 2,535,006 - r.Sub(r, header.Number) // 2,535,006 - 2,534,999 = 7 + r.Add(uncle.Number, big8) // 2,534,998 + 8 = 2,535,006 + r.Sub(r, header.Number) // 2,535,006 - 2,534,999 = 7 r.Mul(r, MaximumBlockReward) // 7 * 5e+18 = 35e+18 - r.Div(r, big8) // 35e+18 / 8 = 7/8 * 5e+18 + r.Div(r, big8) // 35e+18 / 8 = 7/8 * 5e+18 statedb.AddBalance(uncle.Coinbase, r) // $$ r.Div(MaximumBlockReward, big32) // 5e+18 / 32 - reward.Add(reward, r) // 5e+18 + (1/32*5e+18) + reward.Add(reward, r) // 5e+18 + (1/32*5e+18) } statedb.AddBalance(header.Coinbase, reward) // $$ => 5e+18 + (1/32*5e+18) } else { @@ -210,7 +211,6 @@ func GetBlockUncleRewardByEra(era *big.Int, header, uncle *types.Header) *big.In return r } - return getEraUncleBlockReward(era) } @@ -227,7 +227,9 @@ func GetBlockWinnerRewardForUnclesByEra(era *big.Int, uncles []*types.Header) *b // GetRewardByEra gets a block reward at disinflation rate. // Constants MaxBlockReward, DisinflationRateQuotient, and DisinflationRateDivisor assumed. func GetBlockWinnerRewardByEra(era *big.Int) *big.Int { - if era.Cmp(big.NewInt(0)) == 0 { return MaximumBlockReward } + if era.Cmp(big.NewInt(0)) == 0 { + return new(big.Int).Set(MaximumBlockReward) + } var q, d, r *big.Int = new(big.Int), new(big.Int), new(big.Int) @@ -240,11 +242,12 @@ func GetBlockWinnerRewardByEra(era *big.Int) *big.Int { return r } - // getBlockEra gets which "era" a given block is within, given era length (ecip-1017 -> era=5,000,000 blocks) // Returns a zero-index era number, so "Era 1" -> 0, "Era 2" -> 1,... func GetBlockEra(blockNum, eraLength *big.Int) *big.Int { - if blockNum.Cmp(big.NewInt(0)) <= 0 { return big.NewInt(0) } + if blockNum.Cmp(big.NewInt(0)) <= 0 { + return big.NewInt(0) + } remainder := big.NewInt(0).Mod(big.NewInt(0).Sub(blockNum, big.NewInt(1)), eraLength) base := big.NewInt(0).Sub(blockNum, remainder) @@ -253,4 +256,4 @@ func GetBlockEra(blockNum, eraLength *big.Int) *big.Int { dremainder := big.NewInt(0).Mod(d, big.NewInt(1)) return new(big.Int).Sub(d, dremainder) -} \ No newline at end of file +} diff --git a/core/state_processor_test.go b/core/state_processor_test.go index 06e9aba84..c177785d9 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -718,9 +718,13 @@ var ( Era2WinnerUncleReward = new(big.Int).Div(big.NewInt(4e+18), big32) Era2UncleReward = new(big.Int).Div(big.NewInt(4e+18), big32) - Era3WinnerReward = new(big.Int).Mul(new(big.Int).Div(big.NewInt(4e+18), big.NewInt(5)), big.NewInt(4)) - Era3WinnerUncleReward = new(big.Int).Div(new(big.Int).Mul(new(big.Int).Div(big.NewInt(4e+18), big.NewInt(5)), big.NewInt(4)), big32) - Era3UncleReward = new(big.Int).Div(new(big.Int).Mul(new(big.Int).Div(big.NewInt(4e+18), big.NewInt(5)), big.NewInt(4)), big32) + Era3WinnerReward = new(big.Int).Mul(new(big.Int).Div(Era2WinnerReward, big.NewInt(5)), big.NewInt(4)) + Era3WinnerUncleReward = new(big.Int).Div(new(big.Int).Mul(new(big.Int).Div(Era2WinnerReward, big.NewInt(5)), big.NewInt(4)), big32) + Era3UncleReward = new(big.Int).Div(new(big.Int).Mul(new(big.Int).Div(Era2WinnerReward, big.NewInt(5)), big.NewInt(4)), big32) + + Era4WinnerReward = new(big.Int).Mul(new(big.Int).Div(Era3WinnerReward, big.NewInt(5)), big.NewInt(4)) + Era4WinnerUncleReward = new(big.Int).Div(new(big.Int).Mul(new(big.Int).Div(Era3WinnerReward, big.NewInt(5)), big.NewInt(4)), big32) + Era4UncleReward = new(big.Int).Div(new(big.Int).Mul(new(big.Int).Div(Era3WinnerReward, big.NewInt(5)), big.NewInt(4)), big32) ) // Non-accruing over block cases simulates instance. @@ -732,46 +736,46 @@ func TestAccumulateRewards3_Testnet(t *testing.T) { block *big.Int rewards rewards }{ - //{ - // block: big.NewInt(13), - // rewards: rewards{ - // WinnerCoinbase: new(big.Int).Add(Era1WinnerReward, new(big.Int).Mul(Era1WinnerUncleReward, common.Big2)), - // Uncle1Coinbase: Era1UncleReward, - // Uncle2Coinbase: Era1UncleReward, - // }, - //}, - //{ - // block: big.NewInt(1914999), - // rewards: rewards{ - // WinnerCoinbase: new(big.Int).Add(Era1WinnerReward, new(big.Int).Mul(Era1WinnerUncleReward, common.Big2)), - // Uncle1Coinbase: Era1UncleReward, - // Uncle2Coinbase: Era1UncleReward, - // }, - //}, - //{ - // block: big.NewInt(1915000), - // rewards: rewards{ - // WinnerCoinbase: new(big.Int).Add(Era1WinnerReward, new(big.Int).Mul(Era1WinnerUncleReward, common.Big2)), - // Uncle1Coinbase: Era1UncleReward, - // Uncle2Coinbase: Era1UncleReward, - // }, - //}, - //{ - // block: big.NewInt(1915001), - // rewards: rewards{ - // WinnerCoinbase: new(big.Int).Add(Era1WinnerReward, new(big.Int).Mul(Era1WinnerUncleReward, common.Big2)), - // Uncle1Coinbase: Era1UncleReward, - // Uncle2Coinbase: Era1UncleReward, - // }, - //}, - //{ - // block: big.NewInt(4999999), - // rewards: rewards{ - // WinnerCoinbase: new(big.Int).Add(Era1WinnerReward, new(big.Int).Mul(Era1WinnerUncleReward, common.Big2)), - // Uncle1Coinbase: Era1UncleReward, - // Uncle2Coinbase: Era1UncleReward, - // }, - //}, + { + block: big.NewInt(13), + rewards: rewards{ + WinnerCoinbase: new(big.Int).Add(Era1WinnerReward, new(big.Int).Mul(Era1WinnerUncleReward, common.Big2)), + Uncle1Coinbase: Era1UncleReward, + Uncle2Coinbase: Era1UncleReward, + }, + }, + { + block: big.NewInt(1914999), + rewards: rewards{ + WinnerCoinbase: new(big.Int).Add(Era1WinnerReward, new(big.Int).Mul(Era1WinnerUncleReward, common.Big2)), + Uncle1Coinbase: Era1UncleReward, + Uncle2Coinbase: Era1UncleReward, + }, + }, + { + block: big.NewInt(1915000), + rewards: rewards{ + WinnerCoinbase: new(big.Int).Add(Era1WinnerReward, new(big.Int).Mul(Era1WinnerUncleReward, common.Big2)), + Uncle1Coinbase: Era1UncleReward, + Uncle2Coinbase: Era1UncleReward, + }, + }, + { + block: big.NewInt(1915001), + rewards: rewards{ + WinnerCoinbase: new(big.Int).Add(Era1WinnerReward, new(big.Int).Mul(Era1WinnerUncleReward, common.Big2)), + Uncle1Coinbase: Era1UncleReward, + Uncle2Coinbase: Era1UncleReward, + }, + }, + { + block: big.NewInt(4999999), + rewards: rewards{ + WinnerCoinbase: new(big.Int).Add(Era1WinnerReward, new(big.Int).Mul(Era1WinnerUncleReward, common.Big2)), + Uncle1Coinbase: Era1UncleReward, + Uncle2Coinbase: Era1UncleReward, + }, + }, { block: big.NewInt(5000001), rewards: rewards{ @@ -812,6 +816,22 @@ func TestAccumulateRewards3_Testnet(t *testing.T) { Uncle2Coinbase: Era3UncleReward, }, }, + { + block: big.NewInt(15000001), + rewards: rewards{ + WinnerCoinbase: new(big.Int).Add(Era4WinnerReward, new(big.Int).Mul(Era4WinnerUncleReward, common.Big2)), + Uncle1Coinbase: Era4UncleReward, + Uncle2Coinbase: Era4UncleReward, + }, + }, + { + block: big.NewInt(20000000), + rewards: rewards{ + WinnerCoinbase: new(big.Int).Add(Era4WinnerReward, new(big.Int).Mul(Era4WinnerUncleReward, common.Big2)), + Uncle1Coinbase: Era4UncleReward, + Uncle2Coinbase: Era4UncleReward, + }, + }, } for _, c := range cases { From e4e4250ec1ecf7b9fe9fab67efcad44c7dc32c84 Mon Sep 17 00:00:00 2001 From: "Mr. Is" Date: Tue, 9 May 2017 06:52:37 -0500 Subject: [PATCH 10/18] problem: finish implementing and testing ecip1017 solution: tests passing --- core/config_test.go | 60 ++- core/state_processor.go | 3 +- core/state_processor_test.go | 797 +++++++++-------------------------- 3 files changed, 247 insertions(+), 613 deletions(-) diff --git a/core/config_test.go b/core/config_test.go index fd3fe026b..71f9b869c 100644 --- a/core/config_test.go +++ b/core/config_test.go @@ -189,15 +189,30 @@ func TestMakeGenesisDump(t *testing.T) { db.Close() } -func makeTestChainConfig() *ChainConfig { +func getDefaultChainConfigSorted() *ChainConfig { return DefaultConfig.SortForks() } // Unit-y tests. +func TestChainConfig_HasFeature(t *testing.T) { + c := TestConfig.SortForks() + for _, id := range allAvailableTestnetConfigKeys { + if _, _, ok := c.HasFeature(id); !ok { + t.Errorf("feature not found: %v", id) + } + } + c = getDefaultChainConfigSorted() + for _, id := range allAvailableDefaultConfigKeys { + if _, _, ok := c.HasFeature(id); !ok { + t.Errorf("feature not found: %v", id) + } + } +} + // TestChainConfig_GetFeature should be able to get all features described in DefaultConfig. func TestChainConfig_GetFeature(t *testing.T) { - c := makeTestChainConfig() + c := getDefaultChainConfigSorted() var dict = make(map[*big.Int][]string) for _, fork := range c.Forks { for _, feat := range fork.Features { @@ -214,40 +229,45 @@ func TestChainConfig_GetFeature(t *testing.T) { } } -var allAvailableConfigKeys = []string{ +var allAvailableDefaultConfigKeys = []string{ "difficulty", "gastable", "eip155", } +var allAvailableTestnetConfigKeys = []string{ + "difficulty", + "gastable", + "eip155", + "reward", +} +var unavailableConfigKeys = []string{ + "foo", + "bar", + "monkey", +} // TestChainConfig_EventuallyGetAllPossibleFeatures should aggregate all available features from previous branches func TestChainConfig_GetFeature2_EventuallyGetAllPossibleFeatures(t *testing.T) { - c := makeTestChainConfig() - for _, id := range allAvailableConfigKeys { - if _, _, ok := c.GetFeature(big.NewInt(5000000), id); !ok { + c := getDefaultChainConfigSorted() + for _, id := range allAvailableDefaultConfigKeys { + if _, _, ok := c.GetFeature(big.NewInt(50000000), id); !ok { t.Errorf("could not get feature with id: %v, at block: %v", id, big.NewInt(5000000)) } } } -var unavailableConfigKeys = []string{ - "foo", - "bar", - "monkey", -} - // TestChainConfig_NeverGetNonexistantFeatures should never eventually collect features that don't exist func TestChainConfig_GetFeature3_NeverGetNonexistantFeatures(t *testing.T) { - c := makeTestChainConfig() + c := getDefaultChainConfigSorted() for _, id := range unavailableConfigKeys { - if feat, _, ok := c.GetFeature(big.NewInt(5000000), id); ok { + if feat, _, ok := c.GetFeature(big.NewInt(50000000), id); ok { t.Errorf("found unexpected feature: %v, for name: %v, at block: %v", feat, id, big.NewInt(5000000)) } } } func TestChainConfig_GetFeature4_WorkForHighNumbers(t *testing.T) { - c := makeTestChainConfig() + c := getDefaultChainConfigSorted() highBlock := big.NewInt(99999999999999999) if _, _, ok := c.GetFeature(highBlock, "difficulty"); !ok { t.Errorf("unexpected unfound difficulty feature for far-future block: %v", highBlock) @@ -260,7 +280,7 @@ func TestChainConfig_GetFeature4_WorkForHighNumbers(t *testing.T) { // TestChainConfig_GetFeature_DefaultEIP155 should get the eip155 feature for (only and above) its default implemented block. func TestChainConfig_GetFeature5_DefaultEIP155(t *testing.T) { - c := makeTestChainConfig() + c := getDefaultChainConfigSorted() var tables = map[*big.Int]*big.Int{ big.NewInt(0).Sub(DefaultConfig.ForkByName("Homestead").Block, big.NewInt(1)): nil, DefaultConfig.ForkByName("Homestead").Block: nil, @@ -297,7 +317,7 @@ func TestChainConfig_GetFeature5_DefaultEIP155(t *testing.T) { // TestChainConfig_GetFeature_DefaultGasTables sets that GetFeatures gets expected feature values for default fork configs. func TestChainConfig_GetFeature6_DefaultGasTables(t *testing.T) { - c := makeTestChainConfig() + c := getDefaultChainConfigSorted() var tables = map[*big.Int]string{ big.NewInt(0).Sub(DefaultConfig.ForkByName("Homestead").Block, big.NewInt(1)): "", DefaultConfig.ForkByName("Homestead").Block: "homestead", @@ -334,7 +354,7 @@ func TestChainConfig_GetFeature6_DefaultGasTables(t *testing.T) { // TestChainConfig_GetFeature_DefaultGasTables sets that GetFeatures gets expected feature values for default fork configs. func TestChainConfig_GetFeature7_DefaultDifficulty(t *testing.T) { - c := makeTestChainConfig() + c := getDefaultChainConfigSorted() var tables = map[*big.Int]string{ big.NewInt(0).Sub(DefaultConfig.ForkByName("Homestead").Block, big.NewInt(1)): "", DefaultConfig.ForkByName("Homestead").Block: "homestead", @@ -371,7 +391,7 @@ func TestChainConfig_GetFeature7_DefaultDifficulty(t *testing.T) { func TestChainConfig_SortForks(t *testing.T) { // check code data default - c := makeTestChainConfig() + c := getDefaultChainConfigSorted() n := big.NewInt(0) for _, fork := range c.Forks { if n.Cmp(fork.Block) > 0 { @@ -396,7 +416,7 @@ func TestChainConfig_SortForks(t *testing.T) { } func TestChainConfig_GetSigner(t *testing.T) { - c := makeTestChainConfig() + c := getDefaultChainConfigSorted() var forkBlocks []*big.Int for _, fork := range c.Forks { forkBlocks = append(forkBlocks, fork.Block) diff --git a/core/state_processor.go b/core/state_processor.go index 782224dc7..b64ffaa31 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -144,6 +144,8 @@ func AccumulateRewards(config *ChainConfig, statedb *state.StateDB, header *type // block.Number = 2,534,999 // uncles are at same height (?) // ... as uncles get older (within validation), reward drops + // Since ECIP1017 impacts "Era 1" idempotently and with constant 0-block based eras, + // we don't care about where the block/fork implementing it is. feat, _, configured := config.HasFeature("reward") if !configured { reward := new(big.Int).Set(MaximumBlockReward) @@ -184,7 +186,6 @@ func AccumulateRewards(config *ChainConfig, statedb *state.StateDB, header *type statedb.AddBalance(header.Coinbase, wr) // $$ // Reward uncle miners. - for _, uncle := range uncles { ur := GetBlockUncleRewardByEra(era, header, uncle) statedb.AddBalance(uncle.Coinbase, ur) // $$ diff --git a/core/state_processor_test.go b/core/state_processor_test.go index c177785d9..4eadb8c9e 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -13,7 +13,8 @@ import ( "github.com/ethereumproject/go-ethereum/ethdb" ) -func TestGetBlockEra(t *testing.T) { +// Use default era length 5,000,000 +func TestGetBlockEra1(t *testing.T) { cases := map[*big.Int]*big.Int{ big.NewInt(0): big.NewInt(0), big.NewInt(1): big.NewInt(0), @@ -41,6 +42,32 @@ func TestGetBlockEra(t *testing.T) { } } +// Use custom era length 2 +func TestGetBlockEra2(t *testing.T) { + cases := map[*big.Int]*big.Int{ + big.NewInt(0): big.NewInt(0), + big.NewInt(1): big.NewInt(0), + big.NewInt(2): big.NewInt(0), + big.NewInt(3): big.NewInt(1), + big.NewInt(4): big.NewInt(1), + big.NewInt(5): big.NewInt(2), + big.NewInt(6): big.NewInt(2), + big.NewInt(7): big.NewInt(3), + big.NewInt(8): big.NewInt(3), + big.NewInt(9): big.NewInt(4), + big.NewInt(10): big.NewInt(4), + big.NewInt(11): big.NewInt(5), + big.NewInt(12): big.NewInt(5), + } + + for bn, expectedEra := range cases { + gotEra := GetBlockEra(bn, big.NewInt(2)) + if gotEra.Cmp(expectedEra) != 0 { + t.Errorf("got: %v, want: %v", gotEra, expectedEra) + } + } +} + func TestGetBlockWinnerRewardByEra(t *testing.T) { cases := map[*big.Int]*big.Int{ @@ -164,546 +191,103 @@ func TestGetBlockWinnerRewardForUnclesByEra(t *testing.T) { t.Errorf("@ %v: want: %v, got: %v", bn, want, got) } } - } -// -//func fakeAccumulateRewards(config *ChainConfig, states map[common.Address]*big.Int, header *types.Header, uncles []*types.Header) { -// feat, _, configured := config.GetFeature(header.Number, "reward") -// if !configured { -// reward := new(big.Int).Set(MaximumBlockReward) -// r := new(big.Int) -// -// for _, uncle := range uncles { -// r.Add(uncle.Number, big8) // 2,534,998 + 8 = 2,535,006 -// r.Sub(r, header.Number) // 2,535,006 - 2,534,999 = 7 -// r.Mul(r, MaximumBlockReward) // 7 * 5e+18 = 35e+18 -// r.Div(r, big8) // 35e+18 / 8 = 7/8 * 5e+18 -// -// prevBal := states[uncle.Coinbase] -// states[uncle.Coinbase] = new(big.Int).Add(prevBal, r) -// //statedb.AddBalance(uncle.Coinbase, r) // $$ -// -// r.Div(MaximumBlockReward, big32) // 5e+18 / 32 -// reward.Add(reward, r) // 5e+18 + (1/32*5e+18) -// } -// prevBal := states[header.Coinbase] -// states[header.Coinbase] = new(big.Int).Add(prevBal, reward) -// //states.AddBalance(header.Coinbase, reward) // $$ => 5e+18 + (1/32*5e+18) -// } else { -// // Check that configuration specifies ECIP1017. -// val, ok := feat.GetString("type") -// if !ok || val != "ecip1017" { -// panic(ErrConfiguration) -// } -// -// // Ensure value 'era' is configured. -// eraLen, ok := feat.GetBigInt("era") -// if !ok || eraLen.Cmp(big.NewInt(0)) <= 0 { -// panic(ErrConfiguration) -// } -// -// era := GetBlockEra(header.Number, eraLen) -// -// wr := GetBlockWinnerRewardByEra(era) // wr "winner reward". 5, 4, 3.2, 2.56, ... -// wurs := GetBlockWinnerRewardForUnclesByEra(era, uncles) // wurs "winner uncle rewards" -// wr.Add(wr, wurs) -// -// prevBal := states[header.Coinbase] -// states[header.Coinbase] = new(big.Int).Add(prevBal, wr) -// //states.AddBalance(header.Coinbase, wr) // $$ -// -// // Reward uncle miners. -// for _, uncle := range uncles { -// ur := GetBlockUncleRewardByEra(era, header, uncle) -// prevBal := states[uncle.Coinbase] -// states[uncle.Coinbase] = new(big.Int).Add(prevBal, ur) -// //states.AddBalance(uncle.Coinbase, ur) // $$ -// } -// } -//} -// -//// Accruing over block cases simulates compounding longevity of an account. -//// Uses two statedbs to maintain separate ledgers, with the 'testwith'db calling -//// AddBalance at tally points (instead of testing strictly through delegation to AccumulateRewards). -//// Ensures problem is not behind-the-scenes of statedb. -//func TestAccumulateRewards0(t *testing.T) { -// configs := []*ChainConfig{DefaultConfig, TestConfig} -// for i, config := range configs { -// dbTeston, _ := ethdb.NewMemDatabase() -// dbTestwith, _ := ethdb.NewMemDatabase() -// -// //dumps := []*GenesisDump{DefaultGenesis, TestNetGenesis} -// //genHead, e := dumps[i].Header() -// //if e != nil { -// // t.Fatalf("unexpected: %v", e) -// //} -// -// //stateDB, err := state.New(genHead.Hash(), db) -// stateDBTeston, err := state.New(common.Hash{}, dbTeston) -// if err != nil { -// t.Fatalf("could not open statedb: %v", err) -// } -// -// stateDBTestwith, err := state.New(common.Hash{}, dbTestwith) -// if err != nil { -// t.Fatalf("could not open statedb: %v", err) -// } -// -// var header *types.Header = &types.Header{} -// var uncles []*types.Header = []*types.Header{{}, {}} -// -// if i == 0 { -// header.Coinbase = common.StringToAddress("000d836201318ec6899a67540690382780743280") -// uncles[0].Coinbase = common.StringToAddress("001762430ea9c3a26e5749afdb70da5f78ddbb8c") -// uncles[1].Coinbase = common.StringToAddress("001d14804b399c6ef80e64576f657660804fec0b") -// } else { -// header.Coinbase = common.StringToAddress("0000000000000000000000000000000000000001") -// uncles[0].Coinbase = common.StringToAddress("0000000000000000000000000000000000000002") -// uncles[1].Coinbase = common.StringToAddress("0000000000000000000000000000000000000003") -// } -// -// // Manual tallies for reward accumulation. -// winnerB, totalB := new(big.Int), new(big.Int) -// unclesB := []*big.Int{new(big.Int), new(big.Int)} -// -// winnerB = stateDBTeston.GetBalance(header.Coinbase) -// unclesB[0] = stateDBTeston.GetBalance(uncles[0].Coinbase) -// unclesB[1] = stateDBTeston.GetBalance(uncles[1].Coinbase) -// -// totalB.Add(totalB, winnerB) -// totalB.Add(totalB, unclesB[0]) -// totalB.Add(totalB, unclesB[1]) -// -// if totalB.Cmp(big.NewInt(0)) != 0 { -// t.Errorf("unexpected: %v", totalB) -// } -// -// // Manual tallies for reward accumulation. -// winnerB, totalB = new(big.Int), new(big.Int) -// unclesB = []*big.Int{new(big.Int), new(big.Int)} -// -// winnerB = stateDBTestwith.GetBalance(header.Coinbase) -// unclesB[0] = stateDBTestwith.GetBalance(uncles[0].Coinbase) -// unclesB[1] = stateDBTestwith.GetBalance(uncles[1].Coinbase) -// -// totalB.Add(totalB, winnerB) -// totalB.Add(totalB, unclesB[0]) -// totalB.Add(totalB, unclesB[1]) -// -// if totalB.Cmp(big.NewInt(0)) != 0 { -// t.Errorf("unexpected: %v", totalB) -// } -// -// cases := []*big.Int{ -// //big.NewInt(0), -// big.NewInt(13), -// big.NewInt(4999999), -// big.NewInt(5000000), -// big.NewInt(5000001), -// big.NewInt(9999999), -// big.NewInt(10000000), -// big.NewInt(10000000), -// big.NewInt(10000001), -// big.NewInt(14999999), -// big.NewInt(15000000), -// big.NewInt(15000001), -// } -// -// for _, bn := range cases { -// era := GetBlockEra(bn, DefaultEraLength) -// t.Logf("era: %v", era) -// -// header.Number = bn -// -// for i, uncle := range uncles { -// // rand.Seed(time.Now().UTC().UnixNano()) -// // uncle.Number = new(big.Int).Sub(header.Number, big.NewInt(int64(rand.Int31n(int32(7))))) -// uncle.Number = new(big.Int).Sub(header.Number, big.NewInt(int64(1))) // +i -// -// ur := GetBlockUncleRewardByEra(era, header, uncle) -// t.Logf("ur: %v", ur) -// unclesB[i].Add(unclesB[i], ur) -// stateDBTestwith.AddBalance(uncles[i].Coinbase, ur) -// -// totalB.Add(totalB, ur) -// } -// -// wr := GetBlockWinnerRewardByEra(era) -// wr.Add(wr, GetBlockWinnerRewardForUnclesByEra(era, uncles)) -// t.Logf("wr: %v", wr) -// winnerB.Add(winnerB, wr) -// stateDBTestwith.AddBalance(header.Coinbase, wr) -// -// totalB.Add(totalB, winnerB) -// -// AccumulateRewards(config, stateDBTeston, header, uncles) -// -// // Check balances. -// if wb := stateDBTeston.GetBalance(header.Coinbase); wb.Cmp(stateDBTestwith.GetBalance(header.Coinbase)) != 0 { -// t.Errorf("winner balance @ %v, want: %v, got: %v (config: %v)", bn, stateDBTestwith.GetBalance(header.Coinbase), wb, i) -// } -// if uB0 := stateDBTeston.GetBalance(uncles[0].Coinbase); unclesB[0].Cmp(stateDBTestwith.GetBalance(uncles[0].Coinbase)) != 0 { -// t.Errorf("uncle1 balance @ %v, want: %v, got: %v (config: %v)", bn, stateDBTestwith.GetBalance(uncles[0].Coinbase), uB0, i) -// } -// if uB1 := stateDBTeston.GetBalance(uncles[1].Coinbase); unclesB[1].Cmp(stateDBTestwith.GetBalance(uncles[1].Coinbase)) != 0 { -// t.Errorf("uncle2 balance @ %v, want: %v, got: %v (config: %v)", bn, stateDBTestwith.GetBalance(uncles[1].Coinbase), uB1, i) -// } -// // overflows int64 -// //if bn.Cmp(big.NewInt(1)) == 0 && totalB.Cmp(big.NewInt(14.0625e+18)) != 0 { -// // t.Errorf("total balance @ 1, want: %v, got: %v", bn, big.NewInt(14.0625e+18), totalB) -// //} -// } -// dbTeston.Close() -// dbTestwith.Close() -// } -//} -// -//// Accruing over block cases simulates compounding longevity of an account. -//// Tests using maps of running sums for winner & 2 uncles, to keep tally. -//func TestAccumulateRewards1(t *testing.T) { -// configs := []*ChainConfig{DefaultConfig, TestConfig} -// for i, config := range configs { -// db, _ := ethdb.NewMemDatabase() -// -// //dumps := []*GenesisDump{DefaultGenesis, TestNetGenesis} -// //genHead, e := dumps[i].Header() -// //if e != nil { -// // t.Fatalf("unexpected: %v", e) -// //} -// -// //stateDB, err := state.New(genHead.Hash(), db) -// stateDB, err := state.New(common.Hash{}, db) -// if err != nil { -// t.Fatalf("could not open statedb: %v", err) -// } -// -// var header *types.Header = &types.Header{} -// var uncles []*types.Header = []*types.Header{{}, {}} -// -// if i == 0 { -// header.Coinbase = common.StringToAddress("000d836201318ec6899a67540690382780743280") -// uncles[0].Coinbase = common.StringToAddress("001762430ea9c3a26e5749afdb70da5f78ddbb8c") -// uncles[1].Coinbase = common.StringToAddress("001d14804b399c6ef80e64576f657660804fec0b") -// } else { -// header.Coinbase = common.StringToAddress("0000000000000000000000000000000000000001") -// uncles[0].Coinbase = common.StringToAddress("0000000000000000000000000000000000000002") -// uncles[1].Coinbase = common.StringToAddress("0000000000000000000000000000000000000003") -// } -// -// // Manual tallies for reward accumulation. -// winnerB, totalB := new(big.Int), new(big.Int) -// unclesB := []*big.Int{new(big.Int), new(big.Int)} -// -// winnerB = stateDB.GetBalance(header.Coinbase) -// unclesB[0] = stateDB.GetBalance(uncles[0].Coinbase) -// unclesB[1] = stateDB.GetBalance(uncles[1].Coinbase) -// -// totalB.Add(totalB, winnerB) -// totalB.Add(totalB, unclesB[0]) -// totalB.Add(totalB, unclesB[1]) -// -// if totalB.Cmp(big.NewInt(0)) != 0 { -// t.Errorf("unexpected: %v", totalB) -// } -// -// cases := []*big.Int{ -// //big.NewInt(0), -// big.NewInt(13), -// big.NewInt(4999999), -// big.NewInt(5000000), -// big.NewInt(5000001), -// big.NewInt(9999999), -// big.NewInt(10000000), -// big.NewInt(10000000), -// big.NewInt(10000001), -// big.NewInt(14999999), -// big.NewInt(15000000), -// big.NewInt(15000001), -// } -// -// for _, bn := range cases { -// era := GetBlockEra(bn, DefaultEraLength) -// t.Logf("era: %v", era) -// -// header.Number = bn -// -// for i, uncle := range uncles { -// // rand.Seed(time.Now().UTC().UnixNano()) -// // uncle.Number = new(big.Int).Sub(header.Number, big.NewInt(int64(rand.Int31n(int32(7))))) -// uncle.Number = new(big.Int).Sub(header.Number, big.NewInt(int64(1))) // +i -// -// ur := GetBlockUncleRewardByEra(era, header, uncle) -// t.Logf("ur: %v", ur) -// unclesB[i].Add(unclesB[i], ur) -// -// totalB.Add(totalB, ur) -// } -// -// wr := GetBlockWinnerRewardByEra(era) -// wr.Add(wr, GetBlockWinnerRewardForUnclesByEra(era, uncles)) -// t.Logf("wr: %v", wr) -// winnerB.Add(winnerB, wr) -// -// totalB.Add(totalB, winnerB) -// -// AccumulateRewards(config, stateDB, header, uncles) -// -// // Check balances. -// if wb := stateDB.GetBalance(header.Coinbase); wb.Cmp(winnerB) != 0 { -// t.Errorf("winner balance @ %v, want: %v, got: %v (config: %v)", bn, winnerB, wb, i) -// } -// if uB0 := stateDB.GetBalance(uncles[0].Coinbase); unclesB[0].Cmp(uB0) != 0 { -// t.Errorf("uncle1 balance @ %v, want: %v, got: %v (config: %v)", bn, unclesB[0], uB0, i) -// } -// if uB1 := stateDB.GetBalance(uncles[1].Coinbase); unclesB[1].Cmp(uB1) != 0 { -// t.Errorf("uncle2 balance @ %v, want: %v, got: %v (config: %v)", bn, unclesB[1], uB1, i) -// } -// // overflows int64 -// //if bn.Cmp(big.NewInt(1)) == 0 && totalB.Cmp(big.NewInt(14.0625e+18)) != 0 { -// // t.Errorf("total balance @ 1, want: %v, got: %v", bn, big.NewInt(14.0625e+18), totalB) -// //} -// } -// db.Close() -// } -//} -// -//// Tests a fake test, as found above. -//// The fake test does actually call statedb.AddBalance, but tallies sum -//// in a given map 'states'. -//// Accruing over block cases simulates compounding longevity of an account. -//func TestAccumulateRewards1_Fake(t *testing.T) { -// configs := []*ChainConfig{DefaultConfig, TestConfig} -// for i, config := range configs { -// db, _ := ethdb.NewMemDatabase() -// -// //dumps := []*GenesisDump{DefaultGenesis, TestNetGenesis} -// //genHead, e := dumps[i].Header() -// //if e != nil { -// // t.Fatalf("unexpected: %v", e) -// //} -// -// //stateDB, err := state.New(genHead.Hash(), db) -// stateDB, err := state.New(common.Hash{}, db) -// if err != nil { -// t.Fatalf("could not open statedb: %v", err) -// } -// -// var header *types.Header = &types.Header{} -// var uncles []*types.Header = []*types.Header{{}, {}} -// states := make(map[common.Address]*big.Int) -// -// if i == 0 { -// header.Coinbase = common.StringToAddress("000d836201318ec6899a67540690382780743280") -// uncles[0].Coinbase = common.StringToAddress("001762430ea9c3a26e5749afdb70da5f78ddbb8c") -// uncles[1].Coinbase = common.StringToAddress("001d14804b399c6ef80e64576f657660804fec0b") -// } else { -// header.Coinbase = common.StringToAddress("0000000000000000000000000000000000000001") -// uncles[0].Coinbase = common.StringToAddress("0000000000000000000000000000000000000002") -// uncles[1].Coinbase = common.StringToAddress("0000000000000000000000000000000000000003") -// } -// states[header.Coinbase] = big.NewInt(0) -// states[uncles[0].Coinbase] = big.NewInt(0) -// states[uncles[1].Coinbase] = big.NewInt(0) -// -// // Manual tallies for reward accumulation. -// winnerB, totalB := new(big.Int), new(big.Int) -// unclesB := []*big.Int{new(big.Int), new(big.Int)} -// -// winnerB = stateDB.GetBalance(header.Coinbase) -// unclesB[0] = stateDB.GetBalance(uncles[0].Coinbase) -// unclesB[1] = stateDB.GetBalance(uncles[1].Coinbase) -// -// totalB.Add(totalB, winnerB) -// totalB.Add(totalB, unclesB[0]) -// totalB.Add(totalB, unclesB[1]) -// -// if totalB.Cmp(big.NewInt(0)) != 0 { -// t.Errorf("unexpected: %v", totalB) -// } -// -// cases := []*big.Int{ -// //big.NewInt(0), -// big.NewInt(13), -// big.NewInt(4999999), -// big.NewInt(5000000), -// big.NewInt(5000001), -// big.NewInt(9999999), -// big.NewInt(10000000), -// big.NewInt(10000000), -// big.NewInt(10000001), -// big.NewInt(14999999), -// big.NewInt(15000000), -// big.NewInt(15000001), -// } -// -// for _, bn := range cases { -// era := GetBlockEra(bn, DefaultEraLength) -// t.Logf("era: %v", era) -// -// header.Number = bn -// -// for i, uncle := range uncles { -// // rand.Seed(time.Now().UTC().UnixNano()) -// // uncle.Number = new(big.Int).Sub(header.Number, big.NewInt(int64(rand.Int31n(int32(7))))) -// uncle.Number = new(big.Int).Sub(header.Number, big.NewInt(int64(1))) // +i -// -// ur := GetBlockUncleRewardByEra(era, header, uncle) -// t.Logf("ur: %v", ur) -// unclesB[i].Add(unclesB[i], ur) -// -// totalB.Add(totalB, ur) -// } -// -// wr := GetBlockWinnerRewardByEra(era) -// wr.Add(wr, GetBlockWinnerRewardForUnclesByEra(era, uncles)) -// t.Logf("wr: %v", wr) -// winnerB.Add(winnerB, wr) -// -// totalB.Add(totalB, winnerB) -// -// fakeAccumulateRewards(config, states, header, uncles) -// //AccumulateRewards(config, stateDB, header, uncles) -// -// // Check balances. -// if wb := states[header.Coinbase]; wb.Cmp(winnerB) != 0 { -// t.Errorf("winner balance @ %v, want: %v, got: %v (config: %v)", bn, winnerB, wb, i) -// } -// if uB0 := states[uncles[0].Coinbase]; unclesB[0].Cmp(uB0) != 0 { -// t.Errorf("uncle1 balance @ %v, want: %v, got: %v (config: %v)", bn, unclesB[0], uB0, i) -// } -// if uB1 := states[uncles[1].Coinbase]; unclesB[1].Cmp(uB1) != 0 { -// t.Errorf("uncle2 balance @ %v, want: %v, got: %v (config: %v)", bn, unclesB[1], uB1, i) -// } -// //if wb := stateDB.GetBalance(header.Coinbase); wb.Cmp(winnerB) != 0 { -// // t.Errorf("winner balance @ %v, want: %v, got: %v (config: %v)", bn, winnerB, wb, i) -// //} -// //if uB0 := stateDB.GetBalance(uncles[0].Coinbase); unclesB[0].Cmp(uB0) != 0 { -// // t.Errorf("uncle1 balance @ %v, want: %v, got: %v (config: %v)", bn, unclesB[0], uB0, i) -// //} -// //if uB1 := stateDB.GetBalance(uncles[1].Coinbase); unclesB[1].Cmp(uB1) != 0 { -// // t.Errorf("uncle2 balance @ %v, want: %v, got: %v (config: %v)", bn, unclesB[1], uB1, i) -// //} -// // overflows int64 -// //if bn.Cmp(big.NewInt(1)) == 0 && totalB.Cmp(big.NewInt(14.0625e+18)) != 0 { -// // t.Errorf("total balance @ 1, want: %v, got: %v", bn, big.NewInt(14.0625e+18), totalB) -// //} -// } -// db.Close() -// } -//} -// -//// Non-accruing over block cases simulates instance. -//func TestAccumulateRewards2(t *testing.T) { -// configs := []*ChainConfig{DefaultConfig, TestConfig} -// for i, config := range configs { -// -// cases := []*big.Int{ -// //big.NewInt(0), -// big.NewInt(13), -// big.NewInt(4999999), -// big.NewInt(5000000), -// big.NewInt(5000001), -// big.NewInt(9999999), -// big.NewInt(10000000), -// big.NewInt(10000001), -// big.NewInt(14999999), -// big.NewInt(15000000), -// big.NewInt(15000001), -// } -// -// for _, bn := range cases { -// -// db, _ := ethdb.NewMemDatabase() -// -// //dumps := []*GenesisDump{DefaultGenesis, TestNetGenesis} -// //genHead, e := dumps[i].Header() -// //if e != nil { -// // t.Fatalf("unexpected: %v", e) -// //} -// -// //stateDB, err := state.New(genHead.Hash(), db) -// stateDB, err := state.New(common.Hash{}, db) -// if err != nil { -// t.Fatalf("could not open statedb: %v", err) -// } -// if err != nil { -// t.Fatalf("could not open statedb: %v", err) -// } -// -// var header *types.Header = &types.Header{} -// var uncles []*types.Header = []*types.Header{{}, {}} -// -// if i == 0 { -// header.Coinbase = common.StringToAddress("000d836201318ec6899a67540690382780743280") -// uncles[0].Coinbase = common.StringToAddress("001762430ea9c3a26e5749afdb70da5f78ddbb8c") -// uncles[1].Coinbase = common.StringToAddress("001d14804b399c6ef80e64576f657660804fec0b") -// } else { -// header.Coinbase = common.StringToAddress("0000000000000000000000000000000000000001") -// uncles[0].Coinbase = common.StringToAddress("0000000000000000000000000000000000000002") -// uncles[1].Coinbase = common.StringToAddress("0000000000000000000000000000000000000003") -// } -// -// // Manual tallies for reward accumulation. -// winnerB, totalB := new(big.Int), new(big.Int) -// unclesB := []*big.Int{new(big.Int), new(big.Int)} -// -// winnerB = stateDB.GetBalance(header.Coinbase) -// unclesB[0] = stateDB.GetBalance(uncles[0].Coinbase) -// unclesB[1] = stateDB.GetBalance(uncles[1].Coinbase) -// -// totalB.Add(totalB, winnerB) -// totalB.Add(totalB, unclesB[0]) -// totalB.Add(totalB, unclesB[1]) -// -// if totalB.Cmp(big.NewInt(0)) != 0 { -// t.Errorf("unexpected: %v", totalB) -// } -// -// era := GetBlockEra(bn, DefaultEraLength) -// t.Logf("era: %v", era) -// -// header.Number = bn -// -// for i, uncle := range uncles { -// // rand.Seed(time.Now().UTC().UnixNano()) -// // uncle.Number = new(big.Int).Sub(header.Number, big.NewInt(int64(rand.Int31n(int32(7))))) -// uncle.Number = new(big.Int).Sub(header.Number, big.NewInt(int64(1))) // +i -// -// ur := GetBlockUncleRewardByEra(era, header, uncle) -// t.Logf("ur: %v", ur) -// unclesB[i].Add(unclesB[i], ur) -// -// totalB.Add(totalB, ur) -// } -// -// wr := GetBlockWinnerRewardByEra(era) -// wr.Add(wr, GetBlockWinnerRewardForUnclesByEra(era, uncles)) -// t.Logf("wr: %v", wr) -// winnerB.Add(winnerB, wr) -// -// totalB.Add(totalB, winnerB) -// -// AccumulateRewards(config, stateDB, header, uncles) -// -// // Check balances. -// if wb := stateDB.GetBalance(header.Coinbase); wb.Cmp(winnerB) != 0 { -// t.Errorf("winner balance @ %v, want: %v, got: %v (config: %v)", bn, winnerB, wb, i) -// } -// if uB0 := stateDB.GetBalance(uncles[0].Coinbase); unclesB[0].Cmp(uB0) != 0 { -// t.Errorf("uncle1 balance @ %v, want: %v, got: %v (config: %v)", bn, unclesB[0], uB0, i) -// } -// if uB1 := stateDB.GetBalance(uncles[1].Coinbase); unclesB[1].Cmp(uB1) != 0 { -// t.Errorf("uncle2 balance @ %v, want: %v, got: %v (config: %v)", bn, unclesB[1], uB1, i) -// } -// // overflows int64 -// //if bn.Cmp(big.NewInt(1)) == 0 && totalB.Cmp(big.NewInt(14.0625e+18)) != 0 { -// // t.Errorf("total balance @ 1, want: %v, got: %v", bn, big.NewInt(14.0625e+18), totalB) -// //} -// db.Close() -// } -// } -//} +// Accruing over block cases simulates compounding longevity of an account. +// Tests using maps of running sums for winner & 2 uncles to keep tally. +// "all star" miners win repeatedly +func TestAccumulateRewards1(t *testing.T) { + configs := []*ChainConfig{TestConfig} + for i, config := range configs { + db, _ := ethdb.NewMemDatabase() + + stateDB, err := state.New(common.Hash{}, db) + if err != nil { + t.Fatalf("could not open statedb: %v", err) + } + + var header *types.Header = &types.Header{} + var uncles []*types.Header = []*types.Header{{}, {}} + + if i == 0 { + header.Coinbase = common.StringToAddress("000d836201318ec6899a67540690382780743280") + uncles[0].Coinbase = common.StringToAddress("001762430ea9c3a26e5749afdb70da5f78ddbb8c") + uncles[1].Coinbase = common.StringToAddress("001d14804b399c6ef80e64576f657660804fec0b") + } else { + header.Coinbase = common.StringToAddress("0000000000000000000000000000000000000001") + uncles[0].Coinbase = common.StringToAddress("0000000000000000000000000000000000000002") + uncles[1].Coinbase = common.StringToAddress("0000000000000000000000000000000000000003") + } + + // Manual tallies for reward accumulation. + winnerB, totalB := new(big.Int), new(big.Int) + unclesB := []*big.Int{new(big.Int), new(big.Int)} + + winnerB = stateDB.GetBalance(header.Coinbase) + unclesB[0] = stateDB.GetBalance(uncles[0].Coinbase) + unclesB[1] = stateDB.GetBalance(uncles[1].Coinbase) + + totalB.Add(totalB, winnerB) + totalB.Add(totalB, unclesB[0]) + totalB.Add(totalB, unclesB[1]) + + if totalB.Cmp(big.NewInt(0)) != 0 { + t.Errorf("unexpected: %v", totalB) + } + + cases := []*big.Int{ + big.NewInt(1), + big.NewInt(4999999), + big.NewInt(5000000), + big.NewInt(5000001), + big.NewInt(9999999), + big.NewInt(10000000), + big.NewInt(10000000), + big.NewInt(10000001), + big.NewInt(14999999), + big.NewInt(15000000), + big.NewInt(15000001), + } + + for _, bn := range cases { + era := GetBlockEra(bn, DefaultEraLength) + + header.Number = bn + + for i, uncle := range uncles { + + // Randomize uncle numbers with bound ( 0 < n < 8 ) + rand.Seed(time.Now().UTC().UnixNano()) + uncle.Number = new(big.Int).Sub(header.Number, big.NewInt(int64(rand.Int31n(int32(7))))) + + ur := GetBlockUncleRewardByEra(era, header, uncle) + unclesB[i].Add(unclesB[i], ur) + + totalB.Add(totalB, ur) + } + + wr := GetBlockWinnerRewardByEra(era) + wr.Add(wr, GetBlockWinnerRewardForUnclesByEra(era, uncles)) + winnerB.Add(winnerB, wr) + + totalB.Add(totalB, winnerB) + + AccumulateRewards(config, stateDB, header, uncles) + + // Check balances. + if wb := stateDB.GetBalance(header.Coinbase); wb.Cmp(winnerB) != 0 { + t.Errorf("winner balance @ %v, want: %v, got: %v (config: %v)", bn, winnerB, wb, i) + } + if uB0 := stateDB.GetBalance(uncles[0].Coinbase); unclesB[0].Cmp(uB0) != 0 { + t.Errorf("uncle1 balance @ %v, want: %v, got: %v (config: %v)", bn, unclesB[0], uB0, i) + } + if uB1 := stateDB.GetBalance(uncles[1].Coinbase); unclesB[1].Cmp(uB1) != 0 { + t.Errorf("uncle2 balance @ %v, want: %v, got: %v (config: %v)", bn, unclesB[1], uB1, i) + } + } + db.Close() + } +} var ( WinnerCoinbase = common.StringToAddress("0000000000000000000000000000000000000001") @@ -727,15 +311,24 @@ var ( Era4UncleReward = new(big.Int).Div(new(big.Int).Mul(new(big.Int).Div(Era3WinnerReward, big.NewInt(5)), big.NewInt(4)), big32) ) -// Non-accruing over block cases simulates instance. -func TestAccumulateRewards3_Testnet(t *testing.T) { +// Non-accruing over block cases simulates instance, ie "one hit wonder" miners +func TestAccumulateRewards3(t *testing.T) { type rewards map[common.Address]*big.Int + configs := []*ChainConfig{DefaultConfig, TestConfig} cases := []struct { block *big.Int rewards rewards }{ + { + block: big.NewInt(1), + rewards: rewards{ + WinnerCoinbase: new(big.Int).Add(Era1WinnerReward, new(big.Int).Mul(Era1WinnerUncleReward, common.Big2)), + Uncle1Coinbase: Era1UncleReward, + Uncle2Coinbase: Era1UncleReward, + }, + }, { block: big.NewInt(13), rewards: rewards{ @@ -834,61 +427,81 @@ func TestAccumulateRewards3_Testnet(t *testing.T) { }, } - for _, c := range cases { + for i, config := range configs { + for _, c := range cases { - db, _ := ethdb.NewMemDatabase() - stateDB, err := state.New(common.Hash{}, db) - if err != nil { - t.Fatalf("could not open statedb: %v", err) - } - - var winner *types.Header = &types.Header{ - Number: c.block, - Coinbase: WinnerCoinbase, - } - var uncles []*types.Header = []*types.Header{{ - Number: new(big.Int).Sub(c.block, common.Big1), - Coinbase: Uncle1Coinbase, - }, { - Number: new(big.Int).Sub(c.block, common.Big1), - Coinbase: Uncle2Coinbase, - }} - - gotWinnerBalance := stateDB.GetBalance(winner.Coinbase) - gotUncle1Balance := stateDB.GetBalance(Uncle1Coinbase) - gotUncle2Balance := stateDB.GetBalance(Uncle2Coinbase) - r := new(big.Int) - r.Add(gotWinnerBalance, gotUncle1Balance) - r.Add(r, gotUncle2Balance) - if r.Cmp(big.NewInt(0)) != 0 { - t.Errorf("unexpected: %v", r) - } + db, _ := ethdb.NewMemDatabase() + stateDB, err := state.New(common.Hash{}, db) + if err != nil { + t.Fatalf("could not open statedb: %v", err) + } - AccumulateRewards(TestConfig, stateDB, winner, uncles) - gotWinnerBalance = stateDB.GetBalance(winner.Coinbase) - gotUncle1Balance = stateDB.GetBalance(Uncle1Coinbase) - gotUncle2Balance = stateDB.GetBalance(Uncle2Coinbase) + var winner *types.Header = &types.Header{ + Number: c.block, + Coinbase: WinnerCoinbase, + } + var uncles []*types.Header = []*types.Header{{ + Number: new(big.Int).Sub(c.block, common.Big1), + Coinbase: Uncle1Coinbase, + }, { + Number: new(big.Int).Sub(c.block, common.Big1), + Coinbase: Uncle2Coinbase, + }} + + gotWinnerBalance := stateDB.GetBalance(winner.Coinbase) + gotUncle1Balance := stateDB.GetBalance(Uncle1Coinbase) + gotUncle2Balance := stateDB.GetBalance(Uncle2Coinbase) + r := new(big.Int) + r.Add(gotWinnerBalance, gotUncle1Balance) + r.Add(r, gotUncle2Balance) + if r.Cmp(big.NewInt(0)) != 0 { + t.Errorf("unexpected: %v", r) + } - feat, _, configured := TestConfig.HasFeature("reward") - if !configured { - t.Error("unexpected reward feature not configured") - } - eraLen, ok := feat.GetBigInt("era") - if !ok { - t.Error("unexpected reward length not configured") - } - era := GetBlockEra(c.block, eraLen) + AccumulateRewards(config, stateDB, winner, uncles) + gotWinnerBalance = stateDB.GetBalance(winner.Coinbase) + gotUncle1Balance = stateDB.GetBalance(Uncle1Coinbase) + gotUncle2Balance = stateDB.GetBalance(Uncle2Coinbase) + + // Use config if possible. Currently on testnet only. + eraLen := new(big.Int) + feat, _, configured := config.HasFeature("reward") + if !configured { + eraLen = DefaultEraLength + } else { + elen, ok := feat.GetBigInt("era") + if !ok { + t.Error("unexpected reward length not configured") + } else { + eraLen = elen + } + } + era := GetBlockEra(c.block, eraLen) + + // Check balances. + if configured { + if gotWinnerBalance.Cmp(c.rewards[WinnerCoinbase]) != 0 { + t.Errorf("Config: %v | Era %v: winner balance @ %v, want: %v, got: %v, \n-> diff: %v", i, era, c.block, c.rewards[WinnerCoinbase], gotWinnerBalance, new(big.Int).Sub(gotWinnerBalance, c.rewards[WinnerCoinbase])) + } + if gotUncle1Balance.Cmp(c.rewards[Uncle1Coinbase]) != 0 { + t.Errorf("Config: %v | Era %v: uncle1 balance @ %v, want: %v, got: %v, \n-> diff: %v", i, era, c.block, c.rewards[Uncle1Coinbase], gotUncle1Balance, new(big.Int).Sub(gotUncle1Balance, c.rewards[Uncle1Coinbase])) + } + if gotUncle2Balance.Cmp(c.rewards[Uncle2Coinbase]) != 0 { + t.Errorf("Config: %v | Era %v: uncle2 balance @ %v, want: %v, got: %v, \n-> diff: %v", i, era, c.block, c.rewards[Uncle2Coinbase], gotUncle2Balance, new(big.Int).Sub(gotUncle2Balance, c.rewards[Uncle2Coinbase])) + } + } else { + if gotWinnerBalance.Cmp(new(big.Int).Add(Era1WinnerReward, new(big.Int).Mul(Era1WinnerUncleReward, big.NewInt(2)))) != 0 { + t.Errorf("Config: %v | Era %v: winner balance @ %v, want: %v, got: %v, \n-> diff: %v", i, era, c.block, new(big.Int).Add(Era1WinnerReward, new(big.Int).Mul(Era1WinnerUncleReward, big.NewInt(2))), gotWinnerBalance, new(big.Int).Sub(gotWinnerBalance, c.rewards[WinnerCoinbase])) + } + if gotUncle1Balance.Cmp(Era1UncleReward) != 0 { + t.Errorf("Config: %v | Era %v: uncle1 balance @ %v, want: %v, got: %v, \n-> diff: %v", i, era, c.block, Era1UncleReward, gotUncle1Balance, new(big.Int).Sub(gotUncle1Balance, c.rewards[Uncle1Coinbase])) + } + if gotUncle2Balance.Cmp(Era1UncleReward) != 0 { + t.Errorf("Config: %v | Era %v: uncle2 balance @ %v, want: %v, got: %v, \n-> diff: %v", i, era, c.block, Era1UncleReward, gotUncle2Balance, new(big.Int).Sub(gotUncle2Balance, c.rewards[Uncle2Coinbase])) + } + } - // Check balances. - if gotWinnerBalance.Cmp(c.rewards[WinnerCoinbase]) != 0 { - t.Errorf("Era %v: winner balance @ %v, want: %v, got: %v, \n-> diff: %v", era, c.block, c.rewards[WinnerCoinbase], gotWinnerBalance, new(big.Int).Sub(gotWinnerBalance, c.rewards[WinnerCoinbase])) - } - if gotUncle1Balance.Cmp(c.rewards[Uncle1Coinbase]) != 0 { - t.Errorf("Era %v: uncle1 balance @ %v, want: %v, got: %v, \n-> diff: %v", era, c.block, c.rewards[Uncle1Coinbase], gotUncle1Balance, new(big.Int).Sub(gotUncle1Balance, c.rewards[Uncle1Coinbase])) + db.Close() } - if gotUncle2Balance.Cmp(c.rewards[Uncle2Coinbase]) != 0 { - t.Errorf("Era %v: uncle2 balance @ %v, want: %v, got: %v, \n-> diff: %v", era, c.block, c.rewards[Uncle2Coinbase], gotUncle2Balance, new(big.Int).Sub(gotUncle2Balance, c.rewards[Uncle2Coinbase])) - } - db.Close() } } From cc0f25483238d42738ec53b88fdfc87a018b5ccd Mon Sep 17 00:00:00 2001 From: "Mr. Is" Date: Tue, 9 May 2017 08:26:29 -0500 Subject: [PATCH 11/18] problem: HasFeature test didn't test negative solution: test HasFeature doesnt find nonexistant features. passing. --- core/config_test.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/core/config_test.go b/core/config_test.go index 71f9b869c..d4d97caa6 100644 --- a/core/config_test.go +++ b/core/config_test.go @@ -208,6 +208,20 @@ func TestChainConfig_HasFeature(t *testing.T) { t.Errorf("feature not found: %v", id) } } + + // never gets unavailable keys + c = TestConfig.SortForks() + for _, id := range unavailableConfigKeys { + if _, _, ok := c.HasFeature(id); ok { + t.Errorf("nonexisting feature found: %v", id) + } + } + c = getDefaultChainConfigSorted() + for _, id := range unavailableConfigKeys { + if _, _, ok := c.HasFeature(id); ok { + t.Errorf("nonexisting feature found: %v", id) + } + } } // TestChainConfig_GetFeature should be able to get all features described in DefaultConfig. From 7aea026b58f6d7de7e1d11509846d43d2d31b155 Mon Sep 17 00:00:00 2001 From: "Mr. Is" Date: Tue, 9 May 2017 08:26:41 -0500 Subject: [PATCH 12/18] edit comments for clarity --- core/config.go | 1 + core/state_processor.go | 14 +++++++++----- core/state_processor_test.go | 10 +++++----- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/core/config.go b/core/config.go index 4bc3b51d1..33e14a120 100644 --- a/core/config.go +++ b/core/config.go @@ -313,6 +313,7 @@ func (c *ChainConfig) GetFeature(num *big.Int, id string) (*ForkFeature, *Fork, } // HasFeature looks up if fork feature exists _on any fork at any block_ in the configuration. +// In case of multiple same-'id'd features, returns latest (assuming forks are sorted). func (c *ChainConfig) HasFeature(id string) (*ForkFeature, *Fork, bool) { var okForkFeature = &ForkFeature{} var okFork = &Fork{} diff --git a/core/state_processor.go b/core/state_processor.go index b64ffaa31..a77c3b34a 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -141,8 +141,8 @@ func AccumulateRewards(config *ChainConfig, statedb *state.StateDB, header *type // https://www.reddit.com/r/ethereum/comments/3c9jbf/wtf_are_uncles_and_why_do_they_matter/ // uncle.Number = 2,535,998 // assuming "latest" uncle... - // block.Number = 2,534,999 // uncles are at same height (?) - // ... as uncles get older (within validation), reward drops + // block.Number = 2,534,999 // uncles can be at same height as each other + // ... as uncles get older (within validation; <=n-7), reward drops // Since ECIP1017 impacts "Era 1" idempotently and with constant 0-block based eras, // we don't care about where the block/fork implementing it is. @@ -193,7 +193,7 @@ func AccumulateRewards(config *ChainConfig, statedb *state.StateDB, header *type } } -// As of "Era 2", uncle miners and winners are rewarded equally for each included block. +// As of "Era 2" (zero-index era 1), uncle miners and winners are rewarded equally for each included block. // So they share this function. func getEraUncleBlockReward(era *big.Int) *big.Int { return new(big.Int).Div(GetBlockWinnerRewardByEra(era), big32) @@ -216,6 +216,7 @@ func GetBlockUncleRewardByEra(era *big.Int, header, uncle *types.Header) *big.In } // GetBlockWinnerRewardForUnclesByEra gets called _per winner_, and accumulates rewards for each included uncle. +// Assumes uncles have been validated and limited (@ func (v *BlockValidator) VerifyUncles). func GetBlockWinnerRewardForUnclesByEra(era *big.Int, uncles []*types.Header) *big.Int { r := big.NewInt(0) @@ -232,6 +233,9 @@ func GetBlockWinnerRewardByEra(era *big.Int) *big.Int { return new(big.Int).Set(MaximumBlockReward) } + // MaxBlockReward _r_ * (4/5)**era == MaxBlockReward * (4**era) / (5**era) + // since (q/d)**n == q**n / d**n + // qed var q, d, r *big.Int = new(big.Int), new(big.Int), new(big.Int) q.Exp(DisinflationRateQuotient, era, nil) @@ -243,8 +247,8 @@ func GetBlockWinnerRewardByEra(era *big.Int) *big.Int { return r } -// getBlockEra gets which "era" a given block is within, given era length (ecip-1017 -> era=5,000,000 blocks) -// Returns a zero-index era number, so "Era 1" -> 0, "Era 2" -> 1,... +// getBlockEra gets which "Era" a given block is within, given an era length (ecip-1017 has era=5,000,000 blocks) +// Returns a zero-index era number, so "Era 1": 0, "Era 2": 1, "Era 3": 2 ... func GetBlockEra(blockNum, eraLength *big.Int) *big.Int { if blockNum.Cmp(big.NewInt(0)) <= 0 { return big.NewInt(0) diff --git a/core/state_processor_test.go b/core/state_processor_test.go index 4eadb8c9e..eaeec25d5 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -193,9 +193,8 @@ func TestGetBlockWinnerRewardForUnclesByEra(t *testing.T) { } } -// Accruing over block cases simulates compounding longevity of an account. -// Tests using maps of running sums for winner & 2 uncles to keep tally. -// "all star" miners win repeatedly +// Accruing over block cases simulates miner account winning many times. +// Uses maps of running sums for winner & 2 uncles to keep tally. func TestAccumulateRewards1(t *testing.T) { configs := []*ChainConfig{TestConfig} for i, config := range configs { @@ -311,8 +310,9 @@ var ( Era4UncleReward = new(big.Int).Div(new(big.Int).Mul(new(big.Int).Div(Era3WinnerReward, big.NewInt(5)), big.NewInt(4)), big32) ) -// Non-accruing over block cases simulates instance, ie "one hit wonder" miners -func TestAccumulateRewards3(t *testing.T) { +// Non-accruing over block cases simulates instance, +// ie. a miner wins once at different blocks. +func TestAccumulateRewards2(t *testing.T) { type rewards map[common.Address]*big.Int From 1340383972f9c243fb7e27be35ba2777d12ffbbf Mon Sep 17 00:00:00 2001 From: "Mr. Is" Date: Wed, 10 May 2017 07:55:06 -0500 Subject: [PATCH 13/18] include tests for 2,1,0 uncle headers --- core/state_processor_test.go | 363 +++++++++++++++++++++++++++++++++-- 1 file changed, 345 insertions(+), 18 deletions(-) diff --git a/core/state_processor_test.go b/core/state_processor_test.go index eaeec25d5..fc71bfccd 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -45,19 +45,19 @@ func TestGetBlockEra1(t *testing.T) { // Use custom era length 2 func TestGetBlockEra2(t *testing.T) { cases := map[*big.Int]*big.Int{ - big.NewInt(0): big.NewInt(0), - big.NewInt(1): big.NewInt(0), - big.NewInt(2): big.NewInt(0), - big.NewInt(3): big.NewInt(1), - big.NewInt(4): big.NewInt(1), - big.NewInt(5): big.NewInt(2), - big.NewInt(6): big.NewInt(2), - big.NewInt(7): big.NewInt(3), - big.NewInt(8): big.NewInt(3), + big.NewInt(0): big.NewInt(0), + big.NewInt(1): big.NewInt(0), + big.NewInt(2): big.NewInt(0), + big.NewInt(3): big.NewInt(1), + big.NewInt(4): big.NewInt(1), + big.NewInt(5): big.NewInt(2), + big.NewInt(6): big.NewInt(2), + big.NewInt(7): big.NewInt(3), + big.NewInt(8): big.NewInt(3), big.NewInt(9): big.NewInt(4), - big.NewInt(10): big.NewInt(4), - big.NewInt(11): big.NewInt(5), - big.NewInt(12): big.NewInt(5), + big.NewInt(10): big.NewInt(4), + big.NewInt(11): big.NewInt(5), + big.NewInt(12): big.NewInt(5), } for bn, expectedEra := range cases { @@ -235,7 +235,7 @@ func TestAccumulateRewards1(t *testing.T) { } cases := []*big.Int{ - big.NewInt(1), + big.NewInt(11), // avoid messy if-switches for ommer availability/numbering big.NewInt(4999999), big.NewInt(5000000), big.NewInt(5000001), @@ -255,9 +255,14 @@ func TestAccumulateRewards1(t *testing.T) { for i, uncle := range uncles { - // Randomize uncle numbers with bound ( 0 < n < 8 ) + // Randomize uncle numbers with bound ( n-1 <= uncleNum <= n-7 ), where n is current head number + // See yellowpaper@11.1 for ommer validation reference. I expect n-7 is 6th-generation ommer. + // Note that ommer nth-generation impacts reward only for "Era 1". rand.Seed(time.Now().UTC().UnixNano()) - uncle.Number = new(big.Int).Sub(header.Number, big.NewInt(int64(rand.Int31n(int32(7))))) + + // 1 + [0..rand..7) == 1 + 0, 1 + 1, ... 1 + 6 + un := new(big.Int).Add(big.NewInt(1), big.NewInt(int64(rand.Int31n(int32(7))))) + uncle.Number = new(big.Int).Sub(header.Number, un) // n - un ur := GetBlockUncleRewardByEra(era, header, uncle) unclesB[i].Add(unclesB[i], ur) @@ -312,7 +317,9 @@ var ( // Non-accruing over block cases simulates instance, // ie. a miner wins once at different blocks. -func TestAccumulateRewards2(t *testing.T) { +// +// Tests winner includes 2 ommer headers. +func TestAccumulateRewards2_2Uncles(t *testing.T) { type rewards map[common.Address]*big.Int @@ -322,7 +329,7 @@ func TestAccumulateRewards2(t *testing.T) { rewards rewards }{ { - block: big.NewInt(1), + block: big.NewInt(2), rewards: rewards{ WinnerCoinbase: new(big.Int).Add(Era1WinnerReward, new(big.Int).Mul(Era1WinnerUncleReward, common.Big2)), Uncle1Coinbase: Era1UncleReward, @@ -441,7 +448,7 @@ func TestAccumulateRewards2(t *testing.T) { Coinbase: WinnerCoinbase, } var uncles []*types.Header = []*types.Header{{ - Number: new(big.Int).Sub(c.block, common.Big1), + Number: new(big.Int).Sub(c.block, common.Big1), // use 1st-generation ommer, since random n-[1,7) is tested by accrual above Coinbase: Uncle1Coinbase, }, { Number: new(big.Int).Sub(c.block, common.Big1), @@ -505,3 +512,323 @@ func TestAccumulateRewards2(t *testing.T) { } } } + +// Non-accruing over block cases simulates instance, +// ie. a miner wins once at different blocks. +// +// Tests winner includes 1 ommer header. +func TestAccumulateRewards3_1Uncle(t *testing.T) { + + type rewards map[common.Address]*big.Int + + configs := []*ChainConfig{DefaultConfig, TestConfig} + cases := []struct { + block *big.Int + rewards rewards + }{ + { + block: big.NewInt(2), + rewards: rewards{ + WinnerCoinbase: new(big.Int).Add(Era1WinnerReward, Era1WinnerUncleReward), + Uncle1Coinbase: Era1UncleReward, + }, + }, + { + block: big.NewInt(13), + rewards: rewards{ + WinnerCoinbase: new(big.Int).Add(Era1WinnerReward, Era1WinnerUncleReward), + Uncle1Coinbase: Era1UncleReward, + }, + }, + { + block: big.NewInt(1914999), + rewards: rewards{ + WinnerCoinbase: new(big.Int).Add(Era1WinnerReward, Era1WinnerUncleReward), + Uncle1Coinbase: Era1UncleReward, + }, + }, + { + block: big.NewInt(1915000), + rewards: rewards{ + WinnerCoinbase: new(big.Int).Add(Era1WinnerReward, Era1WinnerUncleReward), + Uncle1Coinbase: Era1UncleReward, + }, + }, + { + block: big.NewInt(1915001), + rewards: rewards{ + WinnerCoinbase: new(big.Int).Add(Era1WinnerReward, Era1WinnerUncleReward), + Uncle1Coinbase: Era1UncleReward, + }, + }, + { + block: big.NewInt(4999999), + rewards: rewards{ + WinnerCoinbase: new(big.Int).Add(Era1WinnerReward, Era1WinnerUncleReward), + Uncle1Coinbase: Era1UncleReward, + }, + }, + { + block: big.NewInt(5000001), + rewards: rewards{ + WinnerCoinbase: new(big.Int).Add(Era2WinnerReward, Era2WinnerUncleReward), + Uncle1Coinbase: Era2UncleReward, + }, + }, + { + block: big.NewInt(5000010), + rewards: rewards{ + WinnerCoinbase: new(big.Int).Add(Era2WinnerReward, Era2WinnerUncleReward), + Uncle1Coinbase: Era2UncleReward, + }, + }, + { + block: big.NewInt(10000000), + rewards: rewards{ + WinnerCoinbase: new(big.Int).Add(Era2WinnerReward, Era2WinnerUncleReward), + Uncle1Coinbase: Era2UncleReward, + }, + }, + { + block: big.NewInt(10000001), + rewards: rewards{ + WinnerCoinbase: new(big.Int).Add(Era3WinnerReward, Era3WinnerUncleReward), + Uncle1Coinbase: Era3UncleReward, + }, + }, + { + block: big.NewInt(15000000), + rewards: rewards{ + WinnerCoinbase: new(big.Int).Add(Era3WinnerReward, Era3WinnerUncleReward), + Uncle1Coinbase: Era3UncleReward, + }, + }, + { + block: big.NewInt(15000001), + rewards: rewards{ + WinnerCoinbase: new(big.Int).Add(Era4WinnerReward, Era4WinnerUncleReward), + Uncle1Coinbase: Era4UncleReward, + }, + }, + { + block: big.NewInt(20000000), + rewards: rewards{ + WinnerCoinbase: new(big.Int).Add(Era4WinnerReward, Era4WinnerUncleReward), + Uncle1Coinbase: Era4UncleReward, + }, + }, + } + + for i, config := range configs { + for _, c := range cases { + + db, _ := ethdb.NewMemDatabase() + stateDB, err := state.New(common.Hash{}, db) + if err != nil { + t.Fatalf("could not open statedb: %v", err) + } + + var winner *types.Header = &types.Header{ + Number: c.block, + Coinbase: WinnerCoinbase, + } + var uncles []*types.Header = []*types.Header{{ + Number: new(big.Int).Sub(c.block, common.Big1), // use 1st-generation ommer, since random n-[1,7) is tested by accrual above + Coinbase: Uncle1Coinbase, + }} + + gotWinnerBalance := stateDB.GetBalance(winner.Coinbase) + gotUncle1Balance := stateDB.GetBalance(Uncle1Coinbase) + r := new(big.Int) + r.Add(gotWinnerBalance, gotUncle1Balance) + if r.Cmp(big.NewInt(0)) != 0 { + t.Errorf("unexpected: %v", r) + } + + AccumulateRewards(config, stateDB, winner, uncles) + gotWinnerBalance = stateDB.GetBalance(winner.Coinbase) + gotUncle1Balance = stateDB.GetBalance(Uncle1Coinbase) + + // Use config if possible. Currently on testnet only. + eraLen := new(big.Int) + feat, _, configured := config.HasFeature("reward") + if !configured { + eraLen = DefaultEraLength + } else { + elen, ok := feat.GetBigInt("era") + if !ok { + t.Error("unexpected reward length not configured") + } else { + eraLen = elen + } + } + era := GetBlockEra(c.block, eraLen) + + // Check balances. + if configured { + if gotWinnerBalance.Cmp(c.rewards[WinnerCoinbase]) != 0 { + t.Errorf("Config: %v | Era %v: winner balance @ %v, want: %v, got: %v, \n-> diff: %v", i, era, c.block, c.rewards[WinnerCoinbase], gotWinnerBalance, new(big.Int).Sub(gotWinnerBalance, c.rewards[WinnerCoinbase])) + } + if gotUncle1Balance.Cmp(c.rewards[Uncle1Coinbase]) != 0 { + t.Errorf("Config: %v | Era %v: uncle1 balance @ %v, want: %v, got: %v, \n-> diff: %v", i, era, c.block, c.rewards[Uncle1Coinbase], gotUncle1Balance, new(big.Int).Sub(gotUncle1Balance, c.rewards[Uncle1Coinbase])) + } + } else { + if gotWinnerBalance.Cmp(new(big.Int).Add(Era1WinnerReward, new(big.Int).Mul(Era1WinnerUncleReward, big.NewInt(1)))) != 0 { + t.Errorf("Config: %v | Era %v: winner balance @ %v, want: %v, got: %v, \n-> diff: %v", i, era, c.block, new(big.Int).Add(Era1WinnerReward, new(big.Int).Mul(Era1WinnerUncleReward, big.NewInt(1))), gotWinnerBalance, new(big.Int).Sub(gotWinnerBalance, c.rewards[WinnerCoinbase])) + } + if gotUncle1Balance.Cmp(Era1UncleReward) != 0 { + t.Errorf("Config: %v | Era %v: uncle1 balance @ %v, want: %v, got: %v, \n-> diff: %v", i, era, c.block, Era1UncleReward, gotUncle1Balance, new(big.Int).Sub(gotUncle1Balance, c.rewards[Uncle1Coinbase])) + } + } + + db.Close() + } + } +} + +// Non-accruing over block cases simulates instance, +// ie. a miner wins once at different blocks. +// +// Tests winner includes 0 ommer headers. +func TestAccumulateRewards4_0Uncles(t *testing.T) { + + type rewards map[common.Address]*big.Int + + configs := []*ChainConfig{DefaultConfig, TestConfig} + cases := []struct { + block *big.Int + rewards rewards + }{ + { + block: big.NewInt(2), + rewards: rewards{ + WinnerCoinbase: Era1WinnerReward, + }, + }, + { + block: big.NewInt(13), + rewards: rewards{ + WinnerCoinbase: Era1WinnerReward, + }, + }, + { + block: big.NewInt(1914999), + rewards: rewards{ + WinnerCoinbase: Era1WinnerReward, + }, + }, + { + block: big.NewInt(1915000), + rewards: rewards{ + WinnerCoinbase: Era1WinnerReward, + }, + }, + { + block: big.NewInt(1915001), + rewards: rewards{ + WinnerCoinbase: Era1WinnerReward, + }, + }, + { + block: big.NewInt(4999999), + rewards: rewards{ + WinnerCoinbase: Era1WinnerReward, + }, + }, + { + block: big.NewInt(5000001), + rewards: rewards{ + WinnerCoinbase: Era2WinnerReward, + }, + }, + { + block: big.NewInt(5000010), + rewards: rewards{ + WinnerCoinbase: Era2WinnerReward, + }, + }, + { + block: big.NewInt(10000000), + rewards: rewards{ + WinnerCoinbase: Era2WinnerReward, + }, + }, + { + block: big.NewInt(10000001), + rewards: rewards{ + WinnerCoinbase: Era3WinnerReward, + }, + }, + { + block: big.NewInt(15000000), + rewards: rewards{ + WinnerCoinbase: Era3WinnerReward, + }, + }, + { + block: big.NewInt(15000001), + rewards: rewards{ + WinnerCoinbase: Era4WinnerReward, + }, + }, + { + block: big.NewInt(20000000), + rewards: rewards{ + WinnerCoinbase: Era4WinnerReward, + }, + }, + } + + for i, config := range configs { + for _, c := range cases { + + db, _ := ethdb.NewMemDatabase() + stateDB, err := state.New(common.Hash{}, db) + if err != nil { + t.Fatalf("could not open statedb: %v", err) + } + + var winner *types.Header = &types.Header{ + Number: c.block, + Coinbase: WinnerCoinbase, + } + var uncles []*types.Header = []*types.Header{} + + gotWinnerBalance := stateDB.GetBalance(winner.Coinbase) + if gotWinnerBalance.Cmp(big.NewInt(0)) != 0 { + t.Errorf("unexpected: %v", gotWinnerBalance) + } + + AccumulateRewards(config, stateDB, winner, uncles) + gotWinnerBalance = stateDB.GetBalance(winner.Coinbase) + + // Use config if possible. Currently on testnet only. + eraLen := new(big.Int) + feat, _, configured := config.HasFeature("reward") + if !configured { + eraLen = DefaultEraLength + } else { + elen, ok := feat.GetBigInt("era") + if !ok { + t.Error("unexpected reward length not configured") + } else { + eraLen = elen + } + } + era := GetBlockEra(c.block, eraLen) + + // Check balances. + if configured { + if gotWinnerBalance.Cmp(c.rewards[WinnerCoinbase]) != 0 { + t.Errorf("Config: %v | Era %v: winner balance @ %v, want: %v, got: %v, \n-> diff: %v", i, era, c.block, c.rewards[WinnerCoinbase], gotWinnerBalance, new(big.Int).Sub(gotWinnerBalance, c.rewards[WinnerCoinbase])) + } + } else { + if gotWinnerBalance.Cmp(Era1WinnerReward) != 0 { + t.Errorf("Config: %v | Era %v: winner balance @ %v, want: %v, got: %v, \n-> diff: %v", i, era, c.block, Era1WinnerReward, gotWinnerBalance, new(big.Int).Sub(gotWinnerBalance, c.rewards[WinnerCoinbase])) + } + } + + db.Close() + } + } +} From 50ff54c9e292eb79912d6aa3f00c3d31f571b159 Mon Sep 17 00:00:00 2001 From: "Mr. Is" Date: Wed, 24 May 2017 19:12:11 -0500 Subject: [PATCH 14/18] Problem: downloader test fails often and sporadically Solution: try waiting for 'synchronising' attribute instead of sleeping --- eth/downloader/downloader_test.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go index 961e2b117..14b7b7fdb 100644 --- a/eth/downloader/downloader_test.go +++ b/eth/downloader/downloader_test.go @@ -1781,7 +1781,13 @@ func testFastCriticalRestarts(t *testing.T, protocol int) { } // Wait to make sure all data is set after sync - time.Sleep(400 * time.Millisecond) + n := time.Now() + for tester.downloader.synchronising > 0 { + if time.Since(n) > time.Second { + break + } + } + t.Logf("required %v for downloader to synchronise", time.Since(n)) // Retry limit exhausted, downloader will switch to full sync, should succeed if err := tester.sync("peer", nil, FastSync); err != nil { From d00b78a5d6a7436b31663a1d7c44ef8507a3c09a Mon Sep 17 00:00:00 2001 From: "Mr. Is" Date: Mon, 29 May 2017 08:14:52 -0500 Subject: [PATCH 15/18] Problem: default era length var does not need to be exported Solution: don't export it and declare only for testing --- core/state_processor.go | 3 +-- core/state_processor_test.go | 26 ++++++++++++++------------ 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/core/state_processor.go b/core/state_processor.go index a77c3b34a..ff143e394 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -36,7 +36,6 @@ var ( big32 = big.NewInt(32) DisinflationRateQuotient = big.NewInt(4) DisinflationRateDivisor = big.NewInt(5) - DefaultEraLength = big.NewInt(5000000) // Convenient for testing. ErrConfiguration = errors.New("invalid configuration") ) @@ -247,7 +246,7 @@ func GetBlockWinnerRewardByEra(era *big.Int) *big.Int { return r } -// getBlockEra gets which "Era" a given block is within, given an era length (ecip-1017 has era=5,000,000 blocks) +// GetBlockEra gets which "Era" a given block is within, given an era length (ecip-1017 has era=5,000,000 blocks) // Returns a zero-index era number, so "Era 1": 0, "Era 2": 1, "Era 3": 2 ... func GetBlockEra(blockNum, eraLength *big.Int) *big.Int { if blockNum.Cmp(big.NewInt(0)) <= 0 { diff --git a/core/state_processor_test.go b/core/state_processor_test.go index fc71bfccd..88871387e 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -13,6 +13,8 @@ import ( "github.com/ethereumproject/go-ethereum/ethdb" ) +var defaultEraLength *big.Int = big.NewInt(5000000) + // Use default era length 5,000,000 func TestGetBlockEra1(t *testing.T) { cases := map[*big.Int]*big.Int{ @@ -35,7 +37,7 @@ func TestGetBlockEra1(t *testing.T) { } for bn, expectedEra := range cases { - gotEra := GetBlockEra(bn, DefaultEraLength) + gotEra := GetBlockEra(bn, defaultEraLength) if gotEra.Cmp(expectedEra) != 0 { t.Errorf("got: %v, want: %v", gotEra, expectedEra) } @@ -85,7 +87,7 @@ func TestGetBlockWinnerRewardByEra(t *testing.T) { } for bn, expectedReward := range cases { - gotReward := GetBlockWinnerRewardByEra(GetBlockEra(bn, DefaultEraLength)) + gotReward := GetBlockWinnerRewardByEra(GetBlockEra(bn, defaultEraLength)) if gotReward.Cmp(expectedReward) != 0 { t.Errorf("@ %v, got: %v, want: %v", bn, gotReward, expectedReward) } @@ -104,9 +106,9 @@ func TestGetBlockUncleRewardByEra(t *testing.T) { var we1, we2, we3, we4 *big.Int = new(big.Int), new(big.Int), new(big.Int), new(big.Int) // manually divide maxblockreward/32 to compare to got - we2.Div(GetBlockWinnerRewardByEra(GetBlockEra(big.NewInt(5000001), DefaultEraLength)), big.NewInt(32)) - we3.Div(GetBlockWinnerRewardByEra(GetBlockEra(big.NewInt(10000001), DefaultEraLength)), big.NewInt(32)) - we4.Div(GetBlockWinnerRewardByEra(GetBlockEra(big.NewInt(15000001), DefaultEraLength)), big.NewInt(32)) + we2.Div(GetBlockWinnerRewardByEra(GetBlockEra(big.NewInt(5000001), defaultEraLength)), big.NewInt(32)) + we3.Div(GetBlockWinnerRewardByEra(GetBlockEra(big.NewInt(10000001), defaultEraLength)), big.NewInt(32)) + we4.Div(GetBlockWinnerRewardByEra(GetBlockEra(big.NewInt(15000001), defaultEraLength)), big.NewInt(32)) cases := map[*big.Int]*big.Int{ big.NewInt(0): nil, @@ -124,7 +126,7 @@ func TestGetBlockUncleRewardByEra(t *testing.T) { for bn, want := range cases { - era := GetBlockEra(bn, DefaultEraLength) + era := GetBlockEra(bn, defaultEraLength) var header, uncle *types.Header = &types.Header{}, &types.Header{} header.Number = bn @@ -179,13 +181,13 @@ func TestGetBlockWinnerRewardForUnclesByEra(t *testing.T) { for bn, want := range cases { // test single uncle - got := GetBlockWinnerRewardForUnclesByEra(GetBlockEra(bn, DefaultEraLength), uncleSingle) + got := GetBlockWinnerRewardForUnclesByEra(GetBlockEra(bn, defaultEraLength), uncleSingle) if got.Cmp(want) != 0 { t.Errorf("@ %v: want: %v, got: %v", bn, want, got) } // test double uncle - got = GetBlockWinnerRewardForUnclesByEra(GetBlockEra(bn, DefaultEraLength), uncleDouble) + got = GetBlockWinnerRewardForUnclesByEra(GetBlockEra(bn, defaultEraLength), uncleDouble) dub := new(big.Int) if got.Cmp(dub.Mul(want, big.NewInt(2))) != 0 { t.Errorf("@ %v: want: %v, got: %v", bn, want, got) @@ -249,7 +251,7 @@ func TestAccumulateRewards1(t *testing.T) { } for _, bn := range cases { - era := GetBlockEra(bn, DefaultEraLength) + era := GetBlockEra(bn, defaultEraLength) header.Number = bn @@ -474,7 +476,7 @@ func TestAccumulateRewards2_2Uncles(t *testing.T) { eraLen := new(big.Int) feat, _, configured := config.HasFeature("reward") if !configured { - eraLen = DefaultEraLength + eraLen = defaultEraLength } else { elen, ok := feat.GetBigInt("era") if !ok { @@ -653,7 +655,7 @@ func TestAccumulateRewards3_1Uncle(t *testing.T) { eraLen := new(big.Int) feat, _, configured := config.HasFeature("reward") if !configured { - eraLen = DefaultEraLength + eraLen = defaultEraLength } else { elen, ok := feat.GetBigInt("era") if !ok { @@ -806,7 +808,7 @@ func TestAccumulateRewards4_0Uncles(t *testing.T) { eraLen := new(big.Int) feat, _, configured := config.HasFeature("reward") if !configured { - eraLen = DefaultEraLength + eraLen = defaultEraLength } else { elen, ok := feat.GetBigInt("era") if !ok { From 6469f17f2000b0f1d82f8582acd94849c468ed58 Mon Sep 17 00:00:00 2001 From: "Mr. Is" Date: Mon, 29 May 2017 08:15:56 -0500 Subject: [PATCH 16/18] Problem: method comment should not use markdown formatting for emphasis Solution: remove _'s. --- core/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/config.go b/core/config.go index 6b76431ec..c318beb7e 100644 --- a/core/config.go +++ b/core/config.go @@ -321,7 +321,7 @@ func (c *ChainConfig) GetFeature(num *big.Int, id string) (*ForkFeature, *Fork, return okForkFeature, okFork, found } -// HasFeature looks up if fork feature exists _on any fork at any block_ in the configuration. +// HasFeature looks up if fork feature exists on any fork at any block in the configuration. // In case of multiple same-'id'd features, returns latest (assuming forks are sorted). func (c *ChainConfig) HasFeature(id string) (*ForkFeature, *Fork, bool) { var okForkFeature = &ForkFeature{} From 2f735ea6fa256d1cc74b250752eed932c6a09247 Mon Sep 17 00:00:00 2001 From: "Mr. Is" Date: Mon, 29 May 2017 08:17:47 -0500 Subject: [PATCH 17/18] Problem: testing high block values were ambiguously arbitrary Solution: declare vars with more descriptive names --- core/config_test.go | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/core/config_test.go b/core/config_test.go index 6ff3e60e2..20c116b9b 100644 --- a/core/config_test.go +++ b/core/config_test.go @@ -302,11 +302,15 @@ var unavailableConfigKeys = []string{ "monkey", } +// veryHighBlock is a block in the far distant future (so far, in fact, that it will never actually exist) +// Used to test cumulative aggregation functions, ie "eventually". +var veryHighBlock *big.Int = big.NewInt(250000000) + // TestChainConfig_EventuallyGetAllPossibleFeatures should aggregate all available features from previous branches func TestChainConfig_GetFeature2_EventuallyGetAllPossibleFeatures(t *testing.T) { c := getDefaultChainConfigSorted() for _, id := range allAvailableDefaultConfigKeys { - if _, _, ok := c.GetFeature(big.NewInt(50000000), id); !ok { + if _, _, ok := c.GetFeature(veryHighBlock, id); !ok { t.Errorf("could not get feature with id: %v, at block: %v", id, big.NewInt(5000000)) } } @@ -316,7 +320,7 @@ func TestChainConfig_GetFeature2_EventuallyGetAllPossibleFeatures(t *testing.T) func TestChainConfig_GetFeature3_NeverGetNonexistantFeatures(t *testing.T) { c := getDefaultChainConfigSorted() for _, id := range unavailableConfigKeys { - if feat, _, ok := c.GetFeature(big.NewInt(50000000), id); ok { + if feat, _, ok := c.GetFeature(veryHighBlock, id); ok { t.Errorf("found unexpected feature: %v, for name: %v, at block: %v", feat, id, big.NewInt(5000000)) } } @@ -324,9 +328,9 @@ func TestChainConfig_GetFeature3_NeverGetNonexistantFeatures(t *testing.T) { func TestChainConfig_GetFeature4_WorkForHighNumbers(t *testing.T) { c := getDefaultChainConfigSorted() - highBlock := big.NewInt(99999999999999999) - if _, _, ok := c.GetFeature(highBlock, "difficulty"); !ok { - t.Errorf("unexpected unfound difficulty feature for far-future block: %v", highBlock) + ultraHighBlock := big.NewInt(99999999999999999) + if _, _, ok := c.GetFeature(ultraHighBlock, "difficulty"); !ok { + t.Errorf("unexpected unfound difficulty feature for far-future block: %v", ultraHighBlock) } } From 7f551de4bf1adca91f11838bdb15b2a0cbada455 Mon Sep 17 00:00:00 2001 From: "Mr. Is" Date: Mon, 29 May 2017 08:22:21 -0500 Subject: [PATCH 18/18] Problem: imports out of order (formatting) Solution: gofmt file --- core/state_processor_test.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/state_processor_test.go b/core/state_processor_test.go index 88871387e..b07c9393c 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -2,9 +2,8 @@ package core import ( "math/big" - "testing" - "math/rand" + "testing" "time" "github.com/ethereumproject/go-ethereum/common"