From 304f116b0df475c6d645c31c87af20adc9b133bb Mon Sep 17 00:00:00 2001 From: Tuna Date: Mon, 14 May 2018 18:12:05 +0700 Subject: [PATCH 01/19] add validation in front of mining --- cmd/tomo/main.go | 8 ++++++++ consensus/clique/clique.go | 13 +++++++++++++ eth/backend.go | 20 ++++++++++++++++++++ 3 files changed, 41 insertions(+) diff --git a/cmd/tomo/main.go b/cmd/tomo/main.go index 26ebe5ace4..03b8099dc7 100644 --- a/cmd/tomo/main.go +++ b/cmd/tomo/main.go @@ -290,6 +290,14 @@ func startNode(ctx *cli.Context, stack *node.Node) { if err := stack.Service(ðereum); err != nil { utils.Fatalf("Ethereum service not running: %v", err) } + + // Mining only enabled for validator nodes + if ok, err := ethereum.ValidateMiner(); err != nil { + utils.Fatalf("Can't verify validator permission: %v", err) + } else if !ok { + utils.Fatalf("Only validators can mine blocks") + } + // Use a reduced number of threads if requested if threads := ctx.GlobalInt(utils.MinerThreadsFlag.Name); threads > 0 { type threaded interface { diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go index 2aa4648552..ecf7ef6262 100644 --- a/consensus/clique/clique.go +++ b/consensus/clique/clique.go @@ -34,6 +34,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto/sha3" + "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" @@ -367,6 +368,18 @@ func (c *Clique) verifyCascadingFields(chain consensus.ChainReader, header *type return c.verifySeal(chain, header, parents) } +func (c *Clique) GetSnapshot(chain consensus.ChainReader, header *types.Header) (*Snapshot, error) { + number := header.Number.Uint64() + if number == 0 { + return nil, nil + } + snap, err := c.snapshot(chain, number-1, header.ParentHash, nil) + if err != nil { + return nil, err + } + return snap, nil +} + // snapshot retrieves the authorization snapshot at a given point in time. func (c *Clique) snapshot(chain consensus.ChainReader, number uint64, hash common.Hash, parents []*types.Header) (*Snapshot, error) { // Search for a snapshot in memory or on disk for checkpoints diff --git a/eth/backend.go b/eth/backend.go index 94aad23101..9d31475b07 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -334,6 +334,26 @@ func (self *Ethereum) SetEtherbase(etherbase common.Address) { self.miner.SetEtherbase(etherbase) } +func (s *Ethereum) ValidateMiner() (bool, error) { + eb, err := s.Etherbase() + if err != nil { + return false, err + } + if c, ok := s.engine.(*clique.Clique); !ok { + return false, fmt.Errorf("Only verify miners in Clique protocol") + } else { + //check if miner's wallet is in set of validators + snap, err := c.GetSnapshot(chain, header) + if err != nil { + return false, fmt.Errorf("Can't verify miner: %v", err) + } + if _, authorized := snap.Signers[eb]; !authorized { + return false, fmt.Errorf("This miner doesn't belong to set of validators") + } + } + return true, nil +} + func (s *Ethereum) StartMining(local bool) error { eb, err := s.Etherbase() if err != nil { From f1cf546defec332deb47232b3635bb3b32263bec Mon Sep 17 00:00:00 2001 From: Tuna Date: Tue, 15 May 2018 10:54:52 +0700 Subject: [PATCH 02/19] correct chain, header params --- cmd/tomo/main.go | 2 +- consensus/clique/clique.go | 1 - eth/backend.go | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/cmd/tomo/main.go b/cmd/tomo/main.go index 03b8099dc7..f5c397310c 100644 --- a/cmd/tomo/main.go +++ b/cmd/tomo/main.go @@ -295,7 +295,7 @@ func startNode(ctx *cli.Context, stack *node.Node) { if ok, err := ethereum.ValidateMiner(); err != nil { utils.Fatalf("Can't verify validator permission: %v", err) } else if !ok { - utils.Fatalf("Only validators can mine blocks") + utils.Fatalf("Only validator can mine blocks") } // Use a reduced number of threads if requested diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go index ecf7ef6262..1157ab00a3 100644 --- a/consensus/clique/clique.go +++ b/consensus/clique/clique.go @@ -34,7 +34,6 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto/sha3" - "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" diff --git a/eth/backend.go b/eth/backend.go index 9d31475b07..11e95c1d74 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -343,7 +343,7 @@ func (s *Ethereum) ValidateMiner() (bool, error) { return false, fmt.Errorf("Only verify miners in Clique protocol") } else { //check if miner's wallet is in set of validators - snap, err := c.GetSnapshot(chain, header) + snap, err := c.GetSnapshot(s.blockchain, s.blockchain.CurrentHeader()) if err != nil { return false, fmt.Errorf("Can't verify miner: %v", err) } From 0953671747bb8f41166b712ac52dc05399d67de8 Mon Sep 17 00:00:00 2001 From: Tuna Date: Wed, 16 May 2018 11:01:45 +0700 Subject: [PATCH 03/19] fix bug: only cancel mining mode, keep node alive --- cmd/tomo/main.go | 3 ++- consensus/clique/clique.go | 6 ++---- eth/backend.go | 10 ++++++---- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/cmd/tomo/main.go b/cmd/tomo/main.go index f5c397310c..4daa19bb06 100644 --- a/cmd/tomo/main.go +++ b/cmd/tomo/main.go @@ -295,7 +295,8 @@ func startNode(ctx *cli.Context, stack *node.Node) { if ok, err := ethereum.ValidateMiner(); err != nil { utils.Fatalf("Can't verify validator permission: %v", err) } else if !ok { - utils.Fatalf("Only validator can mine blocks") + log.Info("Only validator can mine blocks. Cancel mining on this node") + return } // Use a reduced number of threads if requested diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go index 1157ab00a3..4def588dfa 100644 --- a/consensus/clique/clique.go +++ b/consensus/clique/clique.go @@ -369,10 +369,8 @@ func (c *Clique) verifyCascadingFields(chain consensus.ChainReader, header *type func (c *Clique) GetSnapshot(chain consensus.ChainReader, header *types.Header) (*Snapshot, error) { number := header.Number.Uint64() - if number == 0 { - return nil, nil - } - snap, err := c.snapshot(chain, number-1, header.ParentHash, nil) + log.Trace("take snapshot", "number", number, "hash", header.Hash()) + snap, err := c.snapshot(chain, number, header.Hash(), nil) if err != nil { return nil, err } diff --git a/eth/backend.go b/eth/backend.go index 11e95c1d74..1908a38a22 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -339,17 +339,19 @@ func (s *Ethereum) ValidateMiner() (bool, error) { if err != nil { return false, err } - if c, ok := s.engine.(*clique.Clique); !ok { - return false, fmt.Errorf("Only verify miners in Clique protocol") - } else { + if s.chainConfig.Clique != nil { //check if miner's wallet is in set of validators + c := s.engine.(*clique.Clique) snap, err := c.GetSnapshot(s.blockchain, s.blockchain.CurrentHeader()) if err != nil { return false, fmt.Errorf("Can't verify miner: %v", err) } if _, authorized := snap.Signers[eb]; !authorized { - return false, fmt.Errorf("This miner doesn't belong to set of validators") + //This miner doesn't belong to set of validators + return false, nil } + } else { + return false, fmt.Errorf("Only verify miners in Clique protocol") } return true, nil } From 034f773b6bb47de025bddf2b966ee71f77a8b889 Mon Sep 17 00:00:00 2001 From: Tuna Date: Wed, 16 May 2018 23:17:00 +0700 Subject: [PATCH 04/19] allow non-zero coinbase in block header --- consensus/clique/clique.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go index 4def588dfa..13e8bb878e 100644 --- a/consensus/clique/clique.go +++ b/consensus/clique/clique.go @@ -277,9 +277,6 @@ func (c *Clique) verifyHeader(chain consensus.ChainReader, header *types.Header, } // Checkpoint blocks need to enforce zero beneficiary checkpoint := (number % c.config.Epoch) == 0 - if checkpoint && header.Coinbase != (common.Address{}) { - return errInvalidCheckpointBeneficiary - } // Nonces must be 0x00..0 or 0xff..f, zeroes enforced on checkpoints if !bytes.Equal(header.Nonce[:], nonceAuthVote) && !bytes.Equal(header.Nonce[:], nonceDropVote) { return errInvalidVote From 0a3aeb71026b2014f2a7ea6a32164669db174190 Mon Sep 17 00:00:00 2001 From: Tuna Date: Fri, 18 May 2018 16:28:56 +0700 Subject: [PATCH 05/19] check mining permission every epoch block + 1 --- cmd/tomo/main.go | 48 +++++++++++++++++++++++++++--------------------- eth/backend.go | 5 +++++ 2 files changed, 32 insertions(+), 21 deletions(-) diff --git a/cmd/tomo/main.go b/cmd/tomo/main.go index 4daa19bb06..05b1404c49 100644 --- a/cmd/tomo/main.go +++ b/cmd/tomo/main.go @@ -290,28 +290,34 @@ func startNode(ctx *cli.Context, stack *node.Node) { if err := stack.Service(ðereum); err != nil { utils.Fatalf("Ethereum service not running: %v", err) } + go func() { + for { + if ethereum.Checkpoint() { + // Mining only enabled for validator nodes + if ok, err := ethereum.ValidateMiner(); err != nil { + utils.Fatalf("Can't verify validator permission: %v", err) + } else if !ok { + log.Info("Only validator can mine blocks. Cancel mining on this node") + ethereum.StopMining() + continue + } - // Mining only enabled for validator nodes - if ok, err := ethereum.ValidateMiner(); err != nil { - utils.Fatalf("Can't verify validator permission: %v", err) - } else if !ok { - log.Info("Only validator can mine blocks. Cancel mining on this node") - return - } - - // Use a reduced number of threads if requested - if threads := ctx.GlobalInt(utils.MinerThreadsFlag.Name); threads > 0 { - type threaded interface { - SetThreads(threads int) + // Use a reduced number of threads if requested + if threads := ctx.GlobalInt(utils.MinerThreadsFlag.Name); threads > 0 { + type threaded interface { + SetThreads(threads int) + } + if th, ok := ethereum.Engine().(threaded); ok { + th.SetThreads(threads) + } + } + // Set the gas price to the limits from the CLI and start mining + ethereum.TxPool().SetGasPrice(utils.GlobalBig(ctx, utils.GasPriceFlag.Name)) + if err := ethereum.StartMining(true); err != nil { + utils.Fatalf("Failed to start mining: %v", err) + } + } } - if th, ok := ethereum.Engine().(threaded); ok { - th.SetThreads(threads) - } - } - // Set the gas price to the limits from the CLI and start mining - ethereum.TxPool().SetGasPrice(utils.GlobalBig(ctx, utils.GasPriceFlag.Name)) - if err := ethereum.StartMining(true); err != nil { - utils.Fatalf("Failed to start mining: %v", err) - } + }() } } diff --git a/eth/backend.go b/eth/backend.go index 1908a38a22..9e639d144d 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -356,6 +356,11 @@ func (s *Ethereum) ValidateMiner() (bool, error) { return true, nil } +func (s *Ethereum) Checkpoint() bool { + number := s.blockchain.CurrentHeader().Number.Uint64() + return number%s.chainConfig.Clique.Epoch == 1 +} + func (s *Ethereum) StartMining(local bool) error { eb, err := s.Etherbase() if err != nil { From b11297c0b9d3d30e35f7d73a81458939347c40de Mon Sep 17 00:00:00 2001 From: Tuna Date: Fri, 18 May 2018 18:03:44 +0700 Subject: [PATCH 06/19] cover cases: node up & down, checkpoint or not --- cmd/tomo/main.go | 69 +++++++++++++++++++++++++++++++++++------------- eth/backend.go | 3 ++- 2 files changed, 53 insertions(+), 19 deletions(-) diff --git a/cmd/tomo/main.go b/cmd/tomo/main.go index 05b1404c49..52e4f1bb69 100644 --- a/cmd/tomo/main.go +++ b/cmd/tomo/main.go @@ -291,30 +291,63 @@ func startNode(ctx *cli.Context, stack *node.Node) { utils.Fatalf("Ethereum service not running: %v", err) } go func() { + started := false + ok, err := ethereum.ValidateMiner() + if err != nil { + utils.Fatalf("Can't verify validator permission: %v", err) + } + if ok { + log.Info("Validator found. Enabling mining mode...") + // Use a reduced number of threads if requested + if threads := ctx.GlobalInt(utils.MinerThreadsFlag.Name); threads > 0 { + type threaded interface { + SetThreads(threads int) + } + if th, ok := ethereum.Engine().(threaded); ok { + th.SetThreads(threads) + } + } + // Set the gas price to the limits from the CLI and start mining + ethereum.TxPool().SetGasPrice(utils.GlobalBig(ctx, utils.GasPriceFlag.Name)) + if err := ethereum.StartMining(true); err != nil { + utils.Fatalf("Failed to start mining: %v", err) + } + started = true + log.Info("Enabled mining node!!!") + } + for { if ethereum.Checkpoint() { - // Mining only enabled for validator nodes - if ok, err := ethereum.ValidateMiner(); err != nil { + //Checkpoint!!! It's time to reconcile node's state... + ok, err := ethereum.ValidateMiner() + if err != nil { utils.Fatalf("Can't verify validator permission: %v", err) - } else if !ok { - log.Info("Only validator can mine blocks. Cancel mining on this node") - ethereum.StopMining() - continue } - - // Use a reduced number of threads if requested - if threads := ctx.GlobalInt(utils.MinerThreadsFlag.Name); threads > 0 { - type threaded interface { - SetThreads(threads int) + if !ok { + log.Info("Only validator can mine blocks. Cancelling mining on this node...") + if started { + ethereum.StopMining() + started = false } - if th, ok := ethereum.Engine().(threaded); ok { - th.SetThreads(threads) + log.Info("Cancelled mining mode!!!") + } else if !started { + log.Info("Validator found. Enabling mining mode...") + // Use a reduced number of threads if requested + if threads := ctx.GlobalInt(utils.MinerThreadsFlag.Name); threads > 0 { + type threaded interface { + SetThreads(threads int) + } + if th, ok := ethereum.Engine().(threaded); ok { + th.SetThreads(threads) + } } - } - // Set the gas price to the limits from the CLI and start mining - ethereum.TxPool().SetGasPrice(utils.GlobalBig(ctx, utils.GasPriceFlag.Name)) - if err := ethereum.StartMining(true); err != nil { - utils.Fatalf("Failed to start mining: %v", err) + // Set the gas price to the limits from the CLI and start mining + ethereum.TxPool().SetGasPrice(utils.GlobalBig(ctx, utils.GasPriceFlag.Name)) + if err := ethereum.StartMining(true); err != nil { + utils.Fatalf("Failed to start mining: %v", err) + } + started = true + log.Info("Enabled mining node!!!") } } } diff --git a/eth/backend.go b/eth/backend.go index 9e639d144d..bd6a53c3be 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -334,6 +334,7 @@ func (self *Ethereum) SetEtherbase(etherbase common.Address) { self.miner.SetEtherbase(etherbase) } +// ValidateMiner checks if node's address is in set of validators func (s *Ethereum) ValidateMiner() (bool, error) { eb, err := s.Etherbase() if err != nil { @@ -358,7 +359,7 @@ func (s *Ethereum) ValidateMiner() (bool, error) { func (s *Ethereum) Checkpoint() bool { number := s.blockchain.CurrentHeader().Number.Uint64() - return number%s.chainConfig.Clique.Epoch == 1 + return number%s.chainConfig.Clique.Epoch == 1 || number == 0 } func (s *Ethereum) StartMining(local bool) error { From ce3e6410850402c7155d75a8906ac2f846c01fb3 Mon Sep 17 00:00:00 2001 From: Tuna Date: Mon, 21 May 2018 17:30:06 +0700 Subject: [PATCH 07/19] use cross-package channel listenning to checkpoint --- cmd/tomo/main.go | 7 +++++-- consensus/clique/clique.go | 2 ++ core/blockchain.go | 6 ++++++ eth/backend.go | 5 ----- miner/worker.go | 5 +++++ 5 files changed, 18 insertions(+), 7 deletions(-) diff --git a/cmd/tomo/main.go b/cmd/tomo/main.go index 52e4f1bb69..60442de7e6 100644 --- a/cmd/tomo/main.go +++ b/cmd/tomo/main.go @@ -29,6 +29,7 @@ import ( "github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/consensus/clique" "github.com/ethereum/go-ethereum/console" "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/ethclient" @@ -315,10 +316,12 @@ func startNode(ctx *cli.Context, stack *node.Node) { started = true log.Info("Enabled mining node!!!") } + defer close(clique.Checkpoint) for { - if ethereum.Checkpoint() { - //Checkpoint!!! It's time to reconcile node's state... + select { + case _ = <-clique.Checkpoint: + log.Info("Checkpoint!!! It's time to reconcile node's state...") ok, err := ethereum.ValidateMiner() if err != nil { utils.Fatalf("Can't verify validator permission: %v", err) diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go index 13e8bb878e..60c0ec4b1d 100644 --- a/consensus/clique/clique.go +++ b/consensus/clique/clique.go @@ -65,6 +65,7 @@ var ( diffInTurn = big.NewInt(2) // Block difficulty for in-turn signatures diffNoTurn = big.NewInt(1) // Block difficulty for out-of-turn signatures + Checkpoint chan int ) // Various error messages to mark blocks invalid. These should be private to @@ -216,6 +217,7 @@ func New(config *params.CliqueConfig, db ethdb.Database) *Clique { if conf.Epoch == 0 { conf.Epoch = epochLength } + Checkpoint = make(chan int) // Allocate the snapshot caches and create the engine recents, _ := lru.NewARC(inmemorySnapshots) signatures, _ := lru.NewARC(inmemorySignatures) diff --git a/core/blockchain.go b/core/blockchain.go index b33eb85a44..799c22ac42 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -43,6 +43,7 @@ import ( "github.com/ethereum/go-ethereum/trie" "github.com/hashicorp/golang-lru" "gopkg.in/karalabe/cookiejar.v2/collections/prque" + "github.com/ethereum/go-ethereum/consensus/clique" ) var ( @@ -1185,6 +1186,11 @@ func (bc *BlockChain) insertChain(chain types.Blocks) (int, []interface{}, []*ty stats.processed++ stats.usedGas += usedGas stats.report(chain, i, bc.stateCache.TrieDB().Size()) + if i == len(chain) - 1 { + if (chain[i].NumberU64() % bc.chainConfig.Clique.Epoch) == 0 { + clique.Checkpoint <- 1 + } + } } // Append a single chain head event if we've progressed the chain if lastCanon != nil && bc.CurrentBlock().Hash() == lastCanon.Hash() { diff --git a/eth/backend.go b/eth/backend.go index bd6a53c3be..9f31f935c6 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -357,11 +357,6 @@ func (s *Ethereum) ValidateMiner() (bool, error) { return true, nil } -func (s *Ethereum) Checkpoint() bool { - number := s.blockchain.CurrentHeader().Number.Uint64() - return number%s.chainConfig.Clique.Epoch == 1 || number == 0 -} - func (s *Ethereum) StartMining(local bool) error { eb, err := s.Etherbase() if err != nil { diff --git a/miner/worker.go b/miner/worker.go index 15395ae0b9..742b2398d8 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -36,6 +36,7 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" "gopkg.in/fatih/set.v0" + "github.com/ethereum/go-ethereum/consensus/clique" ) const ( @@ -488,6 +489,10 @@ func (self *worker) commitNewWork() { log.Info("Commit new mining work", "number", work.Block.Number(), "txs", work.tcount, "uncles", len(uncles), "elapsed", common.PrettyDuration(time.Since(tstart))) self.unconfirmed.Shift(work.Block.NumberU64() - 1) } + if (work.Block.NumberU64() % work.config.Clique.Epoch) == 0 { + log.Info("hey checkpoint") + clique.Checkpoint <- 1 + } self.push(work) } From a546ae74bd3245b11cd7fc41596dac9bfc2d6ffe Mon Sep 17 00:00:00 2001 From: Tuna Date: Fri, 25 May 2018 16:02:11 +0700 Subject: [PATCH 08/19] gofmt --- core/blockchain.go | 4 ++-- miner/worker.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 799c22ac42..ba13c23192 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -30,6 +30,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/consensus" + "github.com/ethereum/go-ethereum/consensus/clique" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" @@ -43,7 +44,6 @@ import ( "github.com/ethereum/go-ethereum/trie" "github.com/hashicorp/golang-lru" "gopkg.in/karalabe/cookiejar.v2/collections/prque" - "github.com/ethereum/go-ethereum/consensus/clique" ) var ( @@ -1186,7 +1186,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks) (int, []interface{}, []*ty stats.processed++ stats.usedGas += usedGas stats.report(chain, i, bc.stateCache.TrieDB().Size()) - if i == len(chain) - 1 { + if i == len(chain)-1 { if (chain[i].NumberU64() % bc.chainConfig.Clique.Epoch) == 0 { clique.Checkpoint <- 1 } diff --git a/miner/worker.go b/miner/worker.go index 742b2398d8..e2ef0f5ad4 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -26,6 +26,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus" + "github.com/ethereum/go-ethereum/consensus/clique" "github.com/ethereum/go-ethereum/consensus/misc" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/state" @@ -36,7 +37,6 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" "gopkg.in/fatih/set.v0" - "github.com/ethereum/go-ethereum/consensus/clique" ) const ( From 0ae49c74fa28a105859bf246ca68a9f3f5d3acb4 Mon Sep 17 00:00:00 2001 From: Tuna Date: Thu, 31 May 2018 16:34:17 +0700 Subject: [PATCH 09/19] fix import cycle --- cmd/tomo/main.go | 61 ++++++++++++++++++-------------------- consensus/clique/clique.go | 2 -- core/blockchain.go | 7 ++--- miner/worker.go | 3 +- 4 files changed, 33 insertions(+), 40 deletions(-) diff --git a/cmd/tomo/main.go b/cmd/tomo/main.go index 60442de7e6..1faa8e331a 100644 --- a/cmd/tomo/main.go +++ b/cmd/tomo/main.go @@ -29,8 +29,8 @@ import ( "github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/consensus/clique" "github.com/ethereum/go-ethereum/console" + "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/internal/debug" @@ -316,42 +316,39 @@ func startNode(ctx *cli.Context, stack *node.Node) { started = true log.Info("Enabled mining node!!!") } - defer close(clique.Checkpoint) + defer close(core.Checkpoint) - for { - select { - case _ = <-clique.Checkpoint: - log.Info("Checkpoint!!! It's time to reconcile node's state...") - ok, err := ethereum.ValidateMiner() - if err != nil { - utils.Fatalf("Can't verify validator permission: %v", err) + for range core.Checkpoint { + log.Info("Checkpoint!!! It's time to reconcile node's state...") + ok, err := ethereum.ValidateMiner() + if err != nil { + utils.Fatalf("Can't verify validator permission: %v", err) + } + if !ok { + log.Info("Only validator can mine blocks. Cancelling mining on this node...") + if started { + ethereum.StopMining() + started = false } - if !ok { - log.Info("Only validator can mine blocks. Cancelling mining on this node...") - if started { - ethereum.StopMining() - started = false + log.Info("Cancelled mining mode!!!") + } else if !started { + log.Info("Validator found. Enabling mining mode...") + // Use a reduced number of threads if requested + if threads := ctx.GlobalInt(utils.MinerThreadsFlag.Name); threads > 0 { + type threaded interface { + SetThreads(threads int) } - log.Info("Cancelled mining mode!!!") - } else if !started { - log.Info("Validator found. Enabling mining mode...") - // Use a reduced number of threads if requested - if threads := ctx.GlobalInt(utils.MinerThreadsFlag.Name); threads > 0 { - type threaded interface { - SetThreads(threads int) - } - if th, ok := ethereum.Engine().(threaded); ok { - th.SetThreads(threads) - } + if th, ok := ethereum.Engine().(threaded); ok { + th.SetThreads(threads) } - // Set the gas price to the limits from the CLI and start mining - ethereum.TxPool().SetGasPrice(utils.GlobalBig(ctx, utils.GasPriceFlag.Name)) - if err := ethereum.StartMining(true); err != nil { - utils.Fatalf("Failed to start mining: %v", err) - } - started = true - log.Info("Enabled mining node!!!") } + // Set the gas price to the limits from the CLI and start mining + ethereum.TxPool().SetGasPrice(utils.GlobalBig(ctx, utils.GasPriceFlag.Name)) + if err := ethereum.StartMining(true); err != nil { + utils.Fatalf("Failed to start mining: %v", err) + } + started = true + log.Info("Enabled mining node!!!") } } }() diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go index 60c0ec4b1d..13e8bb878e 100644 --- a/consensus/clique/clique.go +++ b/consensus/clique/clique.go @@ -65,7 +65,6 @@ var ( diffInTurn = big.NewInt(2) // Block difficulty for in-turn signatures diffNoTurn = big.NewInt(1) // Block difficulty for out-of-turn signatures - Checkpoint chan int ) // Various error messages to mark blocks invalid. These should be private to @@ -217,7 +216,6 @@ func New(config *params.CliqueConfig, db ethdb.Database) *Clique { if conf.Epoch == 0 { conf.Epoch = epochLength } - Checkpoint = make(chan int) // Allocate the snapshot caches and create the engine recents, _ := lru.NewARC(inmemorySnapshots) signatures, _ := lru.NewARC(inmemorySignatures) diff --git a/core/blockchain.go b/core/blockchain.go index ba13c23192..64f20b5840 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -30,7 +30,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/consensus" - "github.com/ethereum/go-ethereum/consensus/clique" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" @@ -48,8 +47,8 @@ import ( var ( blockInsertTimer = metrics.NewRegisteredTimer("chain/inserts", nil) - - ErrNoGenesis = errors.New("Genesis not found in chain") + Checkpoint = make(chan int) + ErrNoGenesis = errors.New("Genesis not found in chain") ) const ( @@ -1188,7 +1187,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks) (int, []interface{}, []*ty stats.report(chain, i, bc.stateCache.TrieDB().Size()) if i == len(chain)-1 { if (chain[i].NumberU64() % bc.chainConfig.Clique.Epoch) == 0 { - clique.Checkpoint <- 1 + Checkpoint <- 1 } } } diff --git a/miner/worker.go b/miner/worker.go index e2ef0f5ad4..6062affc01 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -26,7 +26,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus" - "github.com/ethereum/go-ethereum/consensus/clique" "github.com/ethereum/go-ethereum/consensus/misc" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/state" @@ -491,7 +490,7 @@ func (self *worker) commitNewWork() { } if (work.Block.NumberU64() % work.config.Clique.Epoch) == 0 { log.Info("hey checkpoint") - clique.Checkpoint <- 1 + core.Checkpoint <- 1 } self.push(work) } From 90ceb82c9caab8b13993d4427e7ad9caf8b57c65 Mon Sep 17 00:00:00 2001 From: Tuna Date: Thu, 31 May 2018 17:09:52 +0700 Subject: [PATCH 10/19] fix unittests --- core/blockchain.go | 2 +- miner/worker.go | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 64f20b5840..1d55df9394 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1186,7 +1186,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks) (int, []interface{}, []*ty stats.usedGas += usedGas stats.report(chain, i, bc.stateCache.TrieDB().Size()) if i == len(chain)-1 { - if (chain[i].NumberU64() % bc.chainConfig.Clique.Epoch) == 0 { + if (bc.chainConfig.Clique != nil) && (chain[i].NumberU64()%bc.chainConfig.Clique.Epoch) == 0 { Checkpoint <- 1 } } diff --git a/miner/worker.go b/miner/worker.go index 6062affc01..7b106aeb00 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -488,8 +488,7 @@ func (self *worker) commitNewWork() { log.Info("Commit new mining work", "number", work.Block.Number(), "txs", work.tcount, "uncles", len(uncles), "elapsed", common.PrettyDuration(time.Since(tstart))) self.unconfirmed.Shift(work.Block.NumberU64() - 1) } - if (work.Block.NumberU64() % work.config.Clique.Epoch) == 0 { - log.Info("hey checkpoint") + if (work.config.Clique != nil) && (work.Block.NumberU64()%work.config.Clique.Epoch) == 0 { core.Checkpoint <- 1 } self.push(work) From 5494d3a7d0bccc436ae5732d8bcc2eaa8181929c Mon Sep 17 00:00:00 2001 From: Tuna Date: Wed, 30 May 2018 12:08:02 +0700 Subject: [PATCH 11/19] masternode takes turn (circle) to propose block --- consensus/clique/clique.go | 13 +++++++++++++ miner/worker.go | 18 ++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go index 13e8bb878e..69176ac2ff 100644 --- a/consensus/clique/clique.go +++ b/consensus/clique/clique.go @@ -374,6 +374,19 @@ func (c *Clique) GetSnapshot(chain consensus.ChainReader, header *types.Header) return snap, nil } +func position(list []common.Address, x common.Address) int { + for i, item := range list { + if item == x { + return i + } + } + return -1 +} + +func YourTurn(snap *Snapshot, pre, cur common.Address) bool { + return (position(snap.signers(), pre)+1) % len(snap.signers()) == position(snap.signers(), cur) +} + // snapshot retrieves the authorization snapshot at a given point in time. func (c *Clique) snapshot(chain consensus.ChainReader, number uint64, hash common.Hash, parents []*types.Header) (*Snapshot, error) { // Search for a snapshot in memory or on disk for checkpoints diff --git a/miner/worker.go b/miner/worker.go index 7b106aeb00..de5c162827 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -397,6 +397,24 @@ func (self *worker) commitNewWork() { tstart := time.Now() parent := self.chain.CurrentBlock() + // Only try to commit new work if we are mining + if atomic.LoadInt32(&self.mining) == 1 { + // check if we are right after parent's coinbase in the list + // only go with Clique + if self.config.Clique != nil { + c := self.engine.(*clique.Clique) + snap, err := c.GetSnapshot(self.chain, parent.Header()) + if err != nil { + log.Error("Failed when trying to commit new work", "err", err) + return + } + if !clique.YourTurn(snap, parent.Coinbase(), self.coinbase) { + log.Info("Not our turn to commit block", "wait") + return + } + } + } + tstamp := tstart.Unix() if parent.Time().Cmp(new(big.Int).SetInt64(tstamp)) >= 0 { tstamp = parent.Time().Int64() + 1 From cfdde4333e40186f11594427ff81c7815e8f0a85 Mon Sep 17 00:00:00 2001 From: Tuna Date: Wed, 30 May 2018 14:24:47 +0700 Subject: [PATCH 12/19] golint fix --- miner/worker.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miner/worker.go b/miner/worker.go index de5c162827..40d2b63dad 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -409,7 +409,7 @@ func (self *worker) commitNewWork() { return } if !clique.YourTurn(snap, parent.Coinbase(), self.coinbase) { - log.Info("Not our turn to commit block", "wait") + log.Info("Not our turn to commit block", "wait", nil) return } } From 789e03f167e08a75596a4361ec23c982b64b5f3e Mon Sep 17 00:00:00 2001 From: Tuna Date: Wed, 30 May 2018 14:52:15 +0700 Subject: [PATCH 13/19] block 1 - all masternodes race to create --- consensus/clique/clique.go | 11 ++++++++--- miner/worker.go | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go index 69176ac2ff..d845734f17 100644 --- a/consensus/clique/clique.go +++ b/consensus/clique/clique.go @@ -47,7 +47,8 @@ const ( inmemorySnapshots = 128 // Number of recent vote snapshots to keep in memory inmemorySignatures = 4096 // Number of recent block signatures to keep in memory - wiggleTime = 500 * time.Millisecond // Random delay (per signer) to allow concurrent signers + wiggleTime = 500 * time.Millisecond // Random delay (per signer) to allow concurrent signers + genesisCoinBase = "0x0000000000000000000000000000000000000000" ) // Clique proof-of-authority protocol constants. @@ -384,7 +385,10 @@ func position(list []common.Address, x common.Address) int { } func YourTurn(snap *Snapshot, pre, cur common.Address) bool { - return (position(snap.signers(), pre)+1) % len(snap.signers()) == position(snap.signers(), cur) + 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 } // snapshot retrieves the authorization snapshot at a given point in time. @@ -526,7 +530,8 @@ func (c *Clique) verifySeal(chain consensus.ChainReader, header *types.Header, p // header for running the transactions on top. func (c *Clique) Prepare(chain consensus.ChainReader, header *types.Header) error { // If the block isn't a checkpoint, cast a random vote (good enough for now) - header.Coinbase = common.Address{} + //FIXME: keep header.Coinbase == miner's address + //header.Coinbase = common.Address{} header.Nonce = types.BlockNonce{} number := header.Number.Uint64() diff --git a/miner/worker.go b/miner/worker.go index 40d2b63dad..4f27e6d3ce 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -409,7 +409,7 @@ func (self *worker) commitNewWork() { return } if !clique.YourTurn(snap, parent.Coinbase(), self.coinbase) { - log.Info("Not our turn to commit block", "wait", nil) + log.Info("Not our turn to commit block. Wait for next time") return } } From d91e00e170cdd6a969f03eab895d22f309846f28 Mon Sep 17 00:00:00 2001 From: Tuna Date: Thu, 31 May 2018 15:41:20 +0700 Subject: [PATCH 14/19] reuse Clique voting strategy for now, leave header.Coinbase empty --- consensus/clique/clique.go | 11 +++++++---- miner/worker.go | 8 +++++++- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go index d845734f17..51acff9709 100644 --- a/consensus/clique/clique.go +++ b/consensus/clique/clique.go @@ -384,11 +384,15 @@ func position(list []common.Address, x common.Address) int { return -1 } -func YourTurn(snap *Snapshot, pre, cur common.Address) bool { +func YourTurn(snap *Snapshot, header *types.Header, cur common.Address) (bool, error) { + pre, err := ecrecover(header, snap.sigcache) + if err != nil { + return false, err + } 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 + return (preIndex+1)%len(snap.signers()) == curIndex || pre.String() == genesisCoinBase, nil } // snapshot retrieves the authorization snapshot at a given point in time. @@ -530,8 +534,7 @@ func (c *Clique) verifySeal(chain consensus.ChainReader, header *types.Header, p // header for running the transactions on top. func (c *Clique) Prepare(chain consensus.ChainReader, header *types.Header) error { // If the block isn't a checkpoint, cast a random vote (good enough for now) - //FIXME: keep header.Coinbase == miner's address - //header.Coinbase = common.Address{} + header.Coinbase = common.Address{} header.Nonce = types.BlockNonce{} number := header.Number.Uint64() diff --git a/miner/worker.go b/miner/worker.go index 4f27e6d3ce..fdd69a0301 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -26,6 +26,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus" + "github.com/ethereum/go-ethereum/consensus/clique" "github.com/ethereum/go-ethereum/consensus/misc" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/state" @@ -408,7 +409,12 @@ func (self *worker) commitNewWork() { log.Error("Failed when trying to commit new work", "err", err) return } - if !clique.YourTurn(snap, parent.Coinbase(), self.coinbase) { + ok, err := clique.YourTurn(snap, parent.Header(), self.coinbase) + if err != nil { + log.Error("Failed when trying to commit new work", "err", err) + return + } + if !ok { log.Info("Not our turn to commit block. Wait for next time") return } From fdcd97950d2aa81422eafdbde64b5e40f48e09e1 Mon Sep 17 00:00:00 2001 From: dinhln89 Date: Mon, 4 Jun 2018 16:17:38 +0700 Subject: [PATCH 15/19] 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 16/19] 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 17/19] 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 18/19] 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 19/19] 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.