mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-22 22:54:33 +00:00
update new set of masternodes at end of each epoch (distance = m1Gap)
This commit is contained in:
parent
3d11656c45
commit
9f5cba7dc7
6 changed files with 135 additions and 42 deletions
102
cmd/XDC/main.go
102
cmd/XDC/main.go
|
|
@ -26,8 +26,11 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts"
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||
"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"
|
||||
|
|
@ -37,6 +40,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/metrics"
|
||||
"github.com/ethereum/go-ethereum/node"
|
||||
"gopkg.in/urfave/cli.v1"
|
||||
validatorContract "github.com/ethereum/go-ethereum/contracts/validator/contract"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -46,7 +50,6 @@ const (
|
|||
var (
|
||||
// Git SHA1 commit hash of the release (set via linker flags)
|
||||
gitCommit = ""
|
||||
|
||||
// The app that holds all commands and flags.
|
||||
app = utils.NewApp(gitCommit, "the go-ethereum command line interface")
|
||||
// flags that configure the node
|
||||
|
|
@ -314,39 +317,78 @@ func startNode(ctx *cli.Context, stack *node.Node) {
|
|||
started = true
|
||||
log.Info("Enabled mining node!!!")
|
||||
}
|
||||
defer close(core.Checkpoint)
|
||||
defer close(core.CheckpointCh)
|
||||
defer close(core.M1Ch)
|
||||
for {
|
||||
select {
|
||||
case <-core.CheckpointCh:
|
||||
log.Info("Checkpoint!!! It's time to reconcile node's state...")
|
||||
ok, err := ethereum.ValidateStaker()
|
||||
if err != nil {
|
||||
utils.Fatalf("Can't verify masternode permission: %v", err)
|
||||
}
|
||||
if !ok {
|
||||
log.Info("Only masternode can propose and verify blocks. Cancelling mining on this node...")
|
||||
if started {
|
||||
ethereum.StopMining()
|
||||
started = false
|
||||
}
|
||||
log.Info("Cancelled mining mode!!!")
|
||||
} else if !started {
|
||||
log.Info("Masternode 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.StartStaking(true); err != nil {
|
||||
utils.Fatalf("Failed to start mining: %v", err)
|
||||
}
|
||||
started = true
|
||||
log.Info("Enabled mining node!!!")
|
||||
}
|
||||
case <-core.M1Ch:
|
||||
log.Info("It's time to update new set of masternodes for the next epoch...")
|
||||
// get masternodes information from smart contract
|
||||
client, err := ethclient.Dial(stack.IPCEndpoint())
|
||||
if err != nil {
|
||||
utils.Fatalf("Fail to connect RPC", "error", err)
|
||||
}
|
||||
addr := common.HexToAddress(common.Validator)
|
||||
validator, err := validatorContract.NewXDCValidator(addr, client)
|
||||
if err != nil {
|
||||
utils.Fatalf("Fail to get validator smc", "error", err)
|
||||
}
|
||||
opts := new(bind.CallOpts)
|
||||
candidates, err := validator.GetCandidates(opts)
|
||||
if err != nil {
|
||||
utils.Fatalf("Can't get list of candidates", "error", err)
|
||||
}
|
||||
|
||||
for range core.Checkpoint {
|
||||
log.Info("Checkpoint!!! It's time to reconcile node's state...")
|
||||
ok, err := ethereum.ValidateStaker()
|
||||
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)
|
||||
var ms []clique.Masternode
|
||||
for _, candidate := range candidates {
|
||||
v, err := validator.GetCandidateCap(opts, candidate)
|
||||
if err != nil {
|
||||
log.Warn("Can't get cap of a candidate. Will ignore him", "address", candidate, "error", err)
|
||||
}
|
||||
ms = append(ms, clique.Masternode{candidate, v.Int64()})
|
||||
}
|
||||
// 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.StartStaking(true); err != nil {
|
||||
utils.Fatalf("Failed to start mining: %v", err)
|
||||
// order by cap
|
||||
sort.Slice(ms, func(i, j int) bool {
|
||||
return ms[i].Stake > ms[j].Stake
|
||||
})
|
||||
// update masternodes
|
||||
err = ethereum.UpdateMasternodes(ms)
|
||||
if err != nil {
|
||||
utils.Fatalf("Can't update masternodes", "error", err)
|
||||
}
|
||||
started = true
|
||||
log.Info("Enabled mining node!!!")
|
||||
log.Info("Masternodes are ready for the next epoch")
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ const (
|
|||
HashLength = 32
|
||||
AddressLength = 20
|
||||
BlockSigners = "0x0000000000000000000000000000000000000089"
|
||||
Validator = "0x0000000000000000000000000000000000000088"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
|||
|
|
@ -43,14 +43,18 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
checkpointInterval = 1024 // Number of blocks after which to save the vote snapshot to the database
|
||||
inmemorySnapshots = 128 // Number of recent vote snapshots to keep in memory
|
||||
inmemorySignatures = 4096 // Number of recent block signatures to keep in memory
|
||||
checkpointInterval = 1024 // Number of blocks after which to save the vote snapshot to the database
|
||||
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"
|
||||
)
|
||||
|
||||
type Masternode struct {
|
||||
Address common.Address
|
||||
Stake int64
|
||||
}
|
||||
|
||||
// Clique proof-of-authority protocol constants.
|
||||
var (
|
||||
epochLength = uint64(30000) // Default number of blocks after which to checkpoint and reset the pending votes
|
||||
|
|
@ -377,6 +381,10 @@ func (c *Clique) GetSnapshot(chain consensus.ChainReader, header *types.Header)
|
|||
return snap, nil
|
||||
}
|
||||
|
||||
func (c *Clique) StoreSnapshot(snap *Snapshot) error {
|
||||
return snap.store(c.db)
|
||||
}
|
||||
|
||||
func position(list []common.Address, x common.Address) int {
|
||||
for i, item := range list {
|
||||
if item == x {
|
||||
|
|
@ -613,7 +621,6 @@ func (c *Clique) Finalize(chain consensus.ChainReader, header *types.Header, sta
|
|||
if c.HookReward != nil && number%rCheckpoint == 0 {
|
||||
if err := c.HookReward(chain, state, header); err != nil {
|
||||
return nil, err
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -47,7 +47,8 @@ import (
|
|||
|
||||
var (
|
||||
blockInsertTimer = metrics.NewRegisteredTimer("chain/inserts", nil)
|
||||
Checkpoint = make(chan int)
|
||||
CheckpointCh = make(chan int)
|
||||
M1Ch = make(chan int)
|
||||
ErrNoGenesis = errors.New("Genesis not found in chain")
|
||||
)
|
||||
|
||||
|
|
@ -61,6 +62,7 @@ const (
|
|||
|
||||
// BlockChainVersion ensures that an incompatible database forces a resync from scratch.
|
||||
BlockChainVersion = 3
|
||||
M1Gap = 10
|
||||
)
|
||||
|
||||
// CacheConfig contains the configuration values for the trie caching/pruning
|
||||
|
|
@ -1185,9 +1187,14 @@ 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 (bc.chainConfig.Clique != nil) && (chain[i].NumberU64()%bc.chainConfig.Clique.Epoch) == 0 {
|
||||
Checkpoint <- 1
|
||||
if i == len(chain)-1 && bc.chainConfig.Clique != nil {
|
||||
// epoch block
|
||||
if (chain[i].NumberU64() % bc.chainConfig.Clique.Epoch) == 0 {
|
||||
CheckpointCh <- 1
|
||||
}
|
||||
// prepare set of masternodes for the next epoch
|
||||
if (chain[i].NumberU64() % bc.chainConfig.Clique.Epoch) == (bc.chainConfig.Clique.Epoch - M1Gap) {
|
||||
M1Ch <- 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,6 +53,8 @@ import (
|
|||
"github.com/ethereum/go-ethereum/rpc"
|
||||
)
|
||||
|
||||
const NumOfMasternodes = 99
|
||||
|
||||
type LesServer interface {
|
||||
Start(srvr *p2p.Server)
|
||||
Stop()
|
||||
|
|
@ -420,6 +422,33 @@ func (s *Ethereum) ValidateStaker() (bool, error) {
|
|||
return true, nil
|
||||
}
|
||||
|
||||
// Store new set of masternodes into local db
|
||||
func (s *Ethereum) UpdateMasternodes(ms []clique.Masternode) error {
|
||||
// get snapshot from local db
|
||||
if s.chainConfig.Clique == nil {
|
||||
return errors.New("not clique")
|
||||
}
|
||||
c := s.engine.(*clique.Clique)
|
||||
snap, err := c.GetSnapshot(s.blockchain, s.blockchain.CurrentHeader())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
snap.Signers = make(map[common.Address]struct{})
|
||||
for i, m := range ms {
|
||||
if i == NumOfMasternodes {
|
||||
break
|
||||
}
|
||||
snap.Signers[m.Address] = struct{}{}
|
||||
}
|
||||
err = c.StoreSnapshot(snap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Trace("Stored masternodes snapshot to db", "number", snap.Number, "hash", snap.Hash)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Ethereum) StartStaking(local bool) error {
|
||||
eb, err := s.Etherbase()
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -530,8 +530,15 @@ 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.config.Clique != nil) && (work.Block.NumberU64()%work.config.Clique.Epoch) == 0 {
|
||||
core.Checkpoint <- 1
|
||||
if work.config.Clique != nil {
|
||||
// epoch block
|
||||
if (work.Block.NumberU64() % work.config.Clique.Epoch) == 0 {
|
||||
core.CheckpointCh <- 1
|
||||
}
|
||||
// prepare set of masternodes for the next epoch
|
||||
if (work.Block.NumberU64() % work.config.Clique.Epoch) == (work.config.Clique.Epoch - core.M1Gap) {
|
||||
core.M1Ch <- 1
|
||||
}
|
||||
}
|
||||
self.push(work)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue