From fdcd97950d2aa81422eafdbde64b5e40f48e09e1 Mon Sep 17 00:00:00 2001 From: dinhln89 Date: Mon, 4 Jun 2018 16:17:38 +0700 Subject: [PATCH 1/5] Fixed parse signer address using ecrecover and add reward for signer not using coinbase value. --- consensus/clique/clique.go | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go index 51acff9709..01487b3d37 100644 --- a/consensus/clique/clique.go +++ b/consensus/clique/clique.go @@ -39,7 +39,7 @@ import ( "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rpc" - lru "github.com/hashicorp/golang-lru" + "github.com/hashicorp/golang-lru" ) const ( @@ -385,6 +385,11 @@ func position(list []common.Address, x common.Address) int { } func YourTurn(snap *Snapshot, header *types.Header, cur common.Address) (bool, error) { + if (header.Number.Uint64() == 0) { + // Not check signer for genesis block. + return true, nil + } + pre, err := ecrecover(header, snap.sigcache) if err != nil { return false, err @@ -392,7 +397,7 @@ func YourTurn(snap *Snapshot, header *types.Header, cur common.Address) (bool, e preIndex := position(snap.signers(), pre) curIndex := position(snap.signers(), cur) log.Info("Debugging info", "number of masternodes", len(snap.signers()), "previous", pre, "position", preIndex, "current", cur, "position", curIndex) - return (preIndex+1)%len(snap.signers()) == curIndex || pre.String() == genesisCoinBase, nil + return (preIndex+1)%len(snap.signers()) == curIndex, nil } // snapshot retrieves the authorization snapshot at a given point in time. @@ -600,10 +605,19 @@ func (c *Clique) Prepare(chain consensus.ChainReader, header *types.Header) erro func (c *Clique) Finalize(chain consensus.ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) { // set block reward // FIXME: unit Ether could be too plump - chainReward := new(big.Int).SetUint64(chain.Config().Clique.Reward * params.Ether) + parentHeader := chain.GetHeaderByHash(header.ParentHash) + if (parentHeader.Number.Uint64() > 0) { + chainReward := new(big.Int).SetUint64(chain.Config().Clique.Reward * params.Ether) + // Not reward for singer of genesis block. + reward := new(big.Int).Set(chainReward) - reward := new(big.Int).Set(chainReward) - state.AddBalance(header.Coinbase, reward) + parentSigner, err := ecrecover(parentHeader, c.signatures) + if err != nil { + return nil, err + } + + state.AddBalance(parentSigner, reward) + } // No block rewards in PoA, so the state remains as is and uncles are dropped header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) From 2085e02f2c4eded459dbb1d2c706fbda7cd56cbe Mon Sep 17 00:00:00 2001 From: dinhln89 Date: Tue, 5 Jun 2018 11:21:29 +0700 Subject: [PATCH 2/5] Add config epoch for puppeth cli. --- .gitmodules | 3 --- cmd/puppeth/wizard_genesis.go | 4 ++++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.gitmodules b/.gitmodules index 32bdb3b6e5..e69de29bb2 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +0,0 @@ -[submodule "tests"] - path = tests/testdata - url = https://github.com/ethereum/tests diff --git a/cmd/puppeth/wizard_genesis.go b/cmd/puppeth/wizard_genesis.go index 799384985a..4c38963ffb 100644 --- a/cmd/puppeth/wizard_genesis.go +++ b/cmd/puppeth/wizard_genesis.go @@ -103,6 +103,10 @@ func (w *wizard) makeGenesis() { copy(genesis.ExtraData[32+i*common.AddressLength:], signer[:]) } + fmt.Println() + fmt.Println("How many blocks per checkpoint? (default = 990)") + genesis.Config.Clique.Epoch = uint64(w.readDefaultInt(990)) + default: log.Crit("Invalid consensus engine choice", "choice", choice) } From 0d59fa340801ec414dd5ff802bbd67bb8e66c6ec Mon Sep 17 00:00:00 2001 From: dinhln89 Date: Wed, 6 Jun 2018 15:36:03 +0700 Subject: [PATCH 3/5] Add feature calculate reward for signers at checkpoint block. --- cmd/puppeth/wizard_genesis.go | 2 +- consensus/clique/clique.go | 67 ++++++++++++++++++++++++++++------- params/config.go | 1 + 3 files changed, 57 insertions(+), 13 deletions(-) diff --git a/cmd/puppeth/wizard_genesis.go b/cmd/puppeth/wizard_genesis.go index 4c38963ffb..0135e027ea 100644 --- a/cmd/puppeth/wizard_genesis.go +++ b/cmd/puppeth/wizard_genesis.go @@ -105,7 +105,7 @@ func (w *wizard) makeGenesis() { fmt.Println() fmt.Println("How many blocks per checkpoint? (default = 990)") - genesis.Config.Clique.Epoch = uint64(w.readDefaultInt(990)) + genesis.Config.Clique.Checkpoint = uint64(w.readDefaultInt(990)) default: log.Crit("Invalid consensus engine choice", "choice", choice) diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go index 01487b3d37..93c4e3fac6 100644 --- a/consensus/clique/clique.go +++ b/consensus/clique/clique.go @@ -40,6 +40,7 @@ import ( "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rpc" "github.com/hashicorp/golang-lru" + "encoding/json" ) const ( @@ -605,18 +606,8 @@ func (c *Clique) Prepare(chain consensus.ChainReader, header *types.Header) erro func (c *Clique) Finalize(chain consensus.ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) { // set block reward // FIXME: unit Ether could be too plump - parentHeader := chain.GetHeaderByHash(header.ParentHash) - if (parentHeader.Number.Uint64() > 0) { - chainReward := new(big.Int).SetUint64(chain.Config().Clique.Reward * params.Ether) - // Not reward for singer of genesis block. - reward := new(big.Int).Set(chainReward) - - parentSigner, err := ecrecover(parentHeader, c.signatures) - if err != nil { - return nil, err - } - - state.AddBalance(parentSigner, reward) + if err := c.accumulateRewards(chain, state, header); err != nil { + return nil, err } // No block rewards in PoA, so the state remains as is and uncles are dropped @@ -732,3 +723,55 @@ func (c *Clique) APIs(chain consensus.ChainReader) []rpc.API { Public: false, }} } + +func (c *Clique) accumulateRewards(chain consensus.ChainReader, state *state.StateDB, header *types.Header) (error) { + type rewardLog struct { + Sign uint64 `json:"sign"` + Reward float64 `json:"reward"` + } + + number := header.Number.Uint64() + checkpoint := chain.Config().Clique.Checkpoint + + if number > 0 && number%checkpoint == 0 { + // Not reward for singer of genesis block and only calculate reward at checkpoint block. + parentHeader := chain.GetHeaderByHash(header.ParentHash) + startBlockNumber := number - checkpoint + 1 + endBlockNumber := parentHeader.Number.Uint64() + signers := make(map[common.Address]*rewardLog) + totalSigner := uint64(0) + + for i := startBlockNumber; i <= endBlockNumber; i++ { + blockHeader := chain.GetHeaderByNumber(i) + if signer, err := ecrecover(blockHeader, c.signatures); err != nil { + return err + } else { + _, exist := signers[signer] + if exist { + signers[signer].Sign++ + } else { + signers[signer] = &rewardLog{1, 0} + } + totalSigner++ + } + } + + chainReward := new(big.Int).SetUint64(chain.Config().Clique.Reward * params.Ether) + // Update balance reward. + calcReward := new(big.Int) + for signer, log := range signers { + calcReward.Mul(chainReward, new(big.Int).SetUint64(log.Sign)) + calcReward.Div(calcReward, new(big.Int).SetUint64(totalSigner)) + log.Reward = float64(calcReward.Int64()) + + state.AddBalance(signer, calcReward) + } + jsonSigners, err := json.Marshal(signers) + if err != nil { + return err + } + log.Info("TOMO - Calculate reward at checkpoint", "startBlock", startBlockNumber, "endBlock", endBlockNumber, "signers", string(jsonSigners), "totalSigner", totalSigner, "totalReward", chainReward) + } + + return nil +} diff --git a/params/config.go b/params/config.go index 868ed1ff84..b47f9bf299 100644 --- a/params/config.go +++ b/params/config.go @@ -136,6 +136,7 @@ type CliqueConfig struct { Period uint64 `json:"period"` // Number of seconds between blocks to enforce Epoch uint64 `json:"epoch"` // Epoch length to reset votes and checkpoint Reward uint64 `json:"reward"` // Block reward - unit Ether + Checkpoint uint64 `json:"checkpoint"` // Checkpoint block for calculate rewards. } // String implements the stringer interface, returning the consensus engine details. From b1cbee6c9ab1a32a0cc43b69e1b297e656a7dc79 Mon Sep 17 00:00:00 2001 From: Tuna Date: Wed, 6 Jun 2018 18:13:26 +0700 Subject: [PATCH 4/5] restore tests --- .gitmodules | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitmodules b/.gitmodules index e69de29bb2..32bdb3b6e5 100644 --- a/.gitmodules +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "tests"] + path = tests/testdata + url = https://github.com/ethereum/tests From 7b74ed6bf52ebec9aae223371f5b227b6c9bb5fd Mon Sep 17 00:00:00 2001 From: dinhln89 Date: Wed, 6 Jun 2018 18:16:47 +0700 Subject: [PATCH 5/5] Fixed minor warning of go lint and rename checkpoint config parameter. --- cmd/puppeth/wizard_genesis.go | 2 +- consensus/clique/clique.go | 18 +++++++++--------- params/config.go | 8 ++++---- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/cmd/puppeth/wizard_genesis.go b/cmd/puppeth/wizard_genesis.go index 0135e027ea..89423e8b55 100644 --- a/cmd/puppeth/wizard_genesis.go +++ b/cmd/puppeth/wizard_genesis.go @@ -105,7 +105,7 @@ func (w *wizard) makeGenesis() { fmt.Println() fmt.Println("How many blocks per checkpoint? (default = 990)") - genesis.Config.Clique.Checkpoint = uint64(w.readDefaultInt(990)) + genesis.Config.Clique.RewardCheckpoint = uint64(w.readDefaultInt(990)) default: log.Crit("Invalid consensus engine choice", "choice", choice) diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go index 93c4e3fac6..f5b4ef1972 100644 --- a/consensus/clique/clique.go +++ b/consensus/clique/clique.go @@ -25,6 +25,7 @@ import ( "sync" "time" + "encoding/json" "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" @@ -40,7 +41,6 @@ import ( "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rpc" "github.com/hashicorp/golang-lru" - "encoding/json" ) const ( @@ -386,7 +386,7 @@ func position(list []common.Address, x common.Address) int { } func YourTurn(snap *Snapshot, header *types.Header, cur common.Address) (bool, error) { - if (header.Number.Uint64() == 0) { + if header.Number.Uint64() == 0 { // Not check signer for genesis block. return true, nil } @@ -724,19 +724,19 @@ func (c *Clique) APIs(chain consensus.ChainReader) []rpc.API { }} } -func (c *Clique) accumulateRewards(chain consensus.ChainReader, state *state.StateDB, header *types.Header) (error) { +func (c *Clique) accumulateRewards(chain consensus.ChainReader, state *state.StateDB, header *types.Header) error { type rewardLog struct { Sign uint64 `json:"sign"` Reward float64 `json:"reward"` } number := header.Number.Uint64() - checkpoint := chain.Config().Clique.Checkpoint + rCheckpoint := chain.Config().Clique.RewardCheckpoint - if number > 0 && number%checkpoint == 0 { + if number > 0 && rCheckpoint > 0 && number%rCheckpoint == 0 { // Not reward for singer of genesis block and only calculate reward at checkpoint block. parentHeader := chain.GetHeaderByHash(header.ParentHash) - startBlockNumber := number - checkpoint + 1 + startBlockNumber := number - rCheckpoint + 1 endBlockNumber := parentHeader.Number.Uint64() signers := make(map[common.Address]*rewardLog) totalSigner := uint64(0) @@ -759,10 +759,10 @@ func (c *Clique) accumulateRewards(chain consensus.ChainReader, state *state.Sta chainReward := new(big.Int).SetUint64(chain.Config().Clique.Reward * params.Ether) // Update balance reward. calcReward := new(big.Int) - for signer, log := range signers { - calcReward.Mul(chainReward, new(big.Int).SetUint64(log.Sign)) + for signer, rLog := range signers { + calcReward.Mul(chainReward, new(big.Int).SetUint64(rLog.Sign)) calcReward.Div(calcReward, new(big.Int).SetUint64(totalSigner)) - log.Reward = float64(calcReward.Int64()) + rLog.Reward = float64(calcReward.Int64()) state.AddBalance(signer, calcReward) } diff --git a/params/config.go b/params/config.go index b47f9bf299..e6ce0828d5 100644 --- a/params/config.go +++ b/params/config.go @@ -133,10 +133,10 @@ func (c *EthashConfig) String() string { // CliqueConfig is the consensus engine configs for proof-of-authority based sealing. type CliqueConfig struct { - Period uint64 `json:"period"` // Number of seconds between blocks to enforce - Epoch uint64 `json:"epoch"` // Epoch length to reset votes and checkpoint - Reward uint64 `json:"reward"` // Block reward - unit Ether - Checkpoint uint64 `json:"checkpoint"` // Checkpoint block for calculate rewards. + Period uint64 `json:"period"` // Number of seconds between blocks to enforce + Epoch uint64 `json:"epoch"` // Epoch length to reset votes and checkpoint + Reward uint64 `json:"reward"` // Block reward - unit Ether + RewardCheckpoint uint64 `json:"rewardCheckpoint"` // Checkpoint block for calculate rewards. } // String implements the stringer interface, returning the consensus engine details.