mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 02:12:23 +00:00
Merge remote-tracking branch 'tomochain/master' into dev
This commit is contained in:
commit
09456a7359
7 changed files with 219 additions and 26 deletions
|
|
@ -103,6 +103,10 @@ func (w *wizard) makeGenesis() {
|
||||||
copy(genesis.ExtraData[32+i*common.AddressLength:], signer[:])
|
copy(genesis.ExtraData[32+i*common.AddressLength:], signer[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fmt.Println()
|
||||||
|
fmt.Println("How many blocks per checkpoint? (default = 990)")
|
||||||
|
genesis.Config.Clique.RewardCheckpoint = uint64(w.readDefaultInt(990))
|
||||||
|
|
||||||
default:
|
default:
|
||||||
log.Crit("Invalid consensus engine choice", "choice", choice)
|
log.Crit("Invalid consensus engine choice", "choice", choice)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/accounts/keystore"
|
"github.com/ethereum/go-ethereum/accounts/keystore"
|
||||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||||
"github.com/ethereum/go-ethereum/console"
|
"github.com/ethereum/go-ethereum/console"
|
||||||
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/eth"
|
"github.com/ethereum/go-ethereum/eth"
|
||||||
"github.com/ethereum/go-ethereum/ethclient"
|
"github.com/ethereum/go-ethereum/ethclient"
|
||||||
"github.com/ethereum/go-ethereum/internal/debug"
|
"github.com/ethereum/go-ethereum/internal/debug"
|
||||||
|
|
@ -287,6 +288,14 @@ func startNode(ctx *cli.Context, stack *node.Node) {
|
||||||
if err := stack.Service(ðereum); err != nil {
|
if err := stack.Service(ðereum); err != nil {
|
||||||
utils.Fatalf("Ethereum service not running: %v", err)
|
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
|
// Use a reduced number of threads if requested
|
||||||
if threads := ctx.GlobalInt(utils.MinerThreadsFlag.Name); threads > 0 {
|
if threads := ctx.GlobalInt(utils.MinerThreadsFlag.Name); threads > 0 {
|
||||||
type threaded interface {
|
type threaded interface {
|
||||||
|
|
@ -301,5 +310,44 @@ func startNode(ctx *cli.Context, stack *node.Node) {
|
||||||
if err := ethereum.StartMining(true); err != nil {
|
if err := ethereum.StartMining(true); err != nil {
|
||||||
utils.Fatalf("Failed to start mining: %v", err)
|
utils.Fatalf("Failed to start mining: %v", err)
|
||||||
}
|
}
|
||||||
|
started = true
|
||||||
|
log.Info("Enabled mining node!!!")
|
||||||
|
}
|
||||||
|
defer close(core.Checkpoint)
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
started = true
|
||||||
|
log.Info("Enabled mining node!!!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"encoding/json"
|
||||||
"github.com/ethereum/go-ethereum/accounts"
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
|
@ -39,7 +40,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
lru "github.com/hashicorp/golang-lru"
|
"github.com/hashicorp/golang-lru"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -48,6 +49,7 @@ const (
|
||||||
inmemorySignatures = 4096 // Number of recent block signatures 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.
|
// Clique proof-of-authority protocol constants.
|
||||||
|
|
@ -277,9 +279,6 @@ func (c *Clique) verifyHeader(chain consensus.ChainReader, header *types.Header,
|
||||||
}
|
}
|
||||||
// Checkpoint blocks need to enforce zero beneficiary
|
// Checkpoint blocks need to enforce zero beneficiary
|
||||||
checkpoint := (number % c.config.Epoch) == 0
|
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
|
// Nonces must be 0x00..0 or 0xff..f, zeroes enforced on checkpoints
|
||||||
if !bytes.Equal(header.Nonce[:], nonceAuthVote) && !bytes.Equal(header.Nonce[:], nonceDropVote) {
|
if !bytes.Equal(header.Nonce[:], nonceAuthVote) && !bytes.Equal(header.Nonce[:], nonceDropVote) {
|
||||||
return errInvalidVote
|
return errInvalidVote
|
||||||
|
|
@ -367,6 +366,41 @@ func (c *Clique) verifyCascadingFields(chain consensus.ChainReader, header *type
|
||||||
return c.verifySeal(chain, header, parents)
|
return c.verifySeal(chain, header, parents)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Clique) GetSnapshot(chain consensus.ChainReader, header *types.Header) (*Snapshot, error) {
|
||||||
|
number := header.Number.Uint64()
|
||||||
|
log.Trace("take snapshot", "number", number, "hash", header.Hash())
|
||||||
|
snap, err := c.snapshot(chain, number, header.Hash(), nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
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, 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
|
||||||
|
}
|
||||||
|
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, nil
|
||||||
|
}
|
||||||
|
|
||||||
// snapshot retrieves the authorization snapshot at a given point in time.
|
// 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) {
|
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
|
// Search for a snapshot in memory or on disk for checkpoints
|
||||||
|
|
@ -572,10 +606,9 @@ 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) {
|
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
|
// set block reward
|
||||||
// FIXME: unit Ether could be too plump
|
// FIXME: unit Ether could be too plump
|
||||||
chainReward := new(big.Int).SetUint64(chain.Config().Clique.Reward * params.Ether)
|
if err := c.accumulateRewards(chain, state, header); err != nil {
|
||||||
|
return nil, err
|
||||||
reward := new(big.Int).Set(chainReward)
|
}
|
||||||
state.AddBalance(header.Coinbase, reward)
|
|
||||||
|
|
||||||
// No block rewards in PoA, so the state remains as is and uncles are dropped
|
// No block rewards in PoA, so the state remains as is and uncles are dropped
|
||||||
header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
|
header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
|
||||||
|
|
@ -690,3 +723,55 @@ func (c *Clique) APIs(chain consensus.ChainReader) []rpc.API {
|
||||||
Public: false,
|
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()
|
||||||
|
rCheckpoint := chain.Config().Clique.RewardCheckpoint
|
||||||
|
|
||||||
|
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 - rCheckpoint + 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, rLog := range signers {
|
||||||
|
calcReward.Mul(chainReward, new(big.Int).SetUint64(rLog.Sign))
|
||||||
|
calcReward.Div(calcReward, new(big.Int).SetUint64(totalSigner))
|
||||||
|
rLog.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
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ import (
|
||||||
|
|
||||||
var (
|
var (
|
||||||
blockInsertTimer = metrics.NewRegisteredTimer("chain/inserts", nil)
|
blockInsertTimer = metrics.NewRegisteredTimer("chain/inserts", nil)
|
||||||
|
Checkpoint = make(chan int)
|
||||||
ErrNoGenesis = errors.New("Genesis not found in chain")
|
ErrNoGenesis = errors.New("Genesis not found in chain")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -1185,6 +1185,11 @@ func (bc *BlockChain) insertChain(chain types.Blocks) (int, []interface{}, []*ty
|
||||||
stats.processed++
|
stats.processed++
|
||||||
stats.usedGas += usedGas
|
stats.usedGas += usedGas
|
||||||
stats.report(chain, i, bc.stateCache.TrieDB().Size())
|
stats.report(chain, i, bc.stateCache.TrieDB().Size())
|
||||||
|
if i == len(chain)-1 {
|
||||||
|
if (bc.chainConfig.Clique != nil) && (chain[i].NumberU64()%bc.chainConfig.Clique.Epoch) == 0 {
|
||||||
|
Checkpoint <- 1
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Append a single chain head event if we've progressed the chain
|
// Append a single chain head event if we've progressed the chain
|
||||||
if lastCanon != nil && bc.CurrentBlock().Hash() == lastCanon.Hash() {
|
if lastCanon != nil && bc.CurrentBlock().Hash() == lastCanon.Hash() {
|
||||||
|
|
|
||||||
|
|
@ -334,6 +334,29 @@ func (self *Ethereum) SetEtherbase(etherbase common.Address) {
|
||||||
self.miner.SetEtherbase(etherbase)
|
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 {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
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 {
|
||||||
|
//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
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Ethereum) StartMining(local bool) error {
|
func (s *Ethereum) StartMining(local bool) error {
|
||||||
eb, err := s.Etherbase()
|
eb, err := s.Etherbase()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/consensus"
|
"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/consensus/misc"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
|
|
@ -397,6 +398,29 @@ func (self *worker) commitNewWork() {
|
||||||
tstart := time.Now()
|
tstart := time.Now()
|
||||||
parent := self.chain.CurrentBlock()
|
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
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tstamp := tstart.Unix()
|
tstamp := tstart.Unix()
|
||||||
if parent.Time().Cmp(new(big.Int).SetInt64(tstamp)) >= 0 {
|
if parent.Time().Cmp(new(big.Int).SetInt64(tstamp)) >= 0 {
|
||||||
tstamp = parent.Time().Int64() + 1
|
tstamp = parent.Time().Int64() + 1
|
||||||
|
|
@ -488,6 +512,9 @@ 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)))
|
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)
|
self.unconfirmed.Shift(work.Block.NumberU64() - 1)
|
||||||
}
|
}
|
||||||
|
if (work.config.Clique != nil) && (work.Block.NumberU64()%work.config.Clique.Epoch) == 0 {
|
||||||
|
core.Checkpoint <- 1
|
||||||
|
}
|
||||||
self.push(work)
|
self.push(work)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -136,6 +136,7 @@ type CliqueConfig struct {
|
||||||
Period uint64 `json:"period"` // Number of seconds between blocks to enforce
|
Period uint64 `json:"period"` // Number of seconds between blocks to enforce
|
||||||
Epoch uint64 `json:"epoch"` // Epoch length to reset votes and checkpoint
|
Epoch uint64 `json:"epoch"` // Epoch length to reset votes and checkpoint
|
||||||
Reward uint64 `json:"reward"` // Block reward - unit Ether
|
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.
|
// String implements the stringer interface, returning the consensus engine details.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue