mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-15 09:20:44 +00:00
Move consensus hooks to its own package
This commit is contained in:
parent
0aec2a1e9e
commit
48be4e4ca7
7 changed files with 375 additions and 1604 deletions
|
|
@ -1081,15 +1081,15 @@ func NewFaker(db ethdb.Database) *XDPoS_v1 {
|
||||||
conf := params.TestXDPoSMockChainConfig.XDPoS
|
conf := params.TestXDPoSMockChainConfig.XDPoS
|
||||||
|
|
||||||
// Allocate the snapshot caches and create the engine
|
// Allocate the snapshot caches and create the engine
|
||||||
BlockSigners, _ := lru.New(utils.BlockSignersCacheLimit)
|
// BlockSigners, _ := lru.New(utils.BlockSignersCacheLimit)
|
||||||
recents, _ := lru.NewARC(utils.InmemorySnapshots)
|
recents, _ := lru.NewARC(utils.InmemorySnapshots)
|
||||||
signatures, _ := lru.NewARC(utils.InmemorySnapshots)
|
signatures, _ := lru.NewARC(utils.InmemorySnapshots)
|
||||||
validatorSignatures, _ := lru.NewARC(utils.InmemorySnapshots)
|
validatorSignatures, _ := lru.NewARC(utils.InmemorySnapshots)
|
||||||
verifiedHeaders, _ := lru.NewARC(utils.InmemorySnapshots)
|
verifiedHeaders, _ := lru.NewARC(utils.InmemorySnapshots)
|
||||||
fakeEngine = &XDPoS_v1{
|
fakeEngine = &XDPoS_v1{
|
||||||
config: conf,
|
config: conf,
|
||||||
db: db,
|
db: db,
|
||||||
BlockSigners: BlockSigners,
|
// BlockSigners: BlockSigners,
|
||||||
recents: recents,
|
recents: recents,
|
||||||
signatures: signatures,
|
signatures: signatures,
|
||||||
verifiedHeaders: verifiedHeaders,
|
verifiedHeaders: verifiedHeaders,
|
||||||
|
|
|
||||||
1259
coverage.txt
1259
coverage.txt
File diff suppressed because it is too large
Load diff
|
|
@ -46,6 +46,7 @@ import (
|
||||||
"github.com/XinFinOrg/XDPoSChain/core/vm"
|
"github.com/XinFinOrg/XDPoSChain/core/vm"
|
||||||
"github.com/XinFinOrg/XDPoSChain/eth/downloader"
|
"github.com/XinFinOrg/XDPoSChain/eth/downloader"
|
||||||
"github.com/XinFinOrg/XDPoSChain/eth/gasprice"
|
"github.com/XinFinOrg/XDPoSChain/eth/gasprice"
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/eth/util"
|
||||||
"github.com/XinFinOrg/XDPoSChain/ethdb"
|
"github.com/XinFinOrg/XDPoSChain/ethdb"
|
||||||
"github.com/XinFinOrg/XDPoSChain/event"
|
"github.com/XinFinOrg/XDPoSChain/event"
|
||||||
"github.com/XinFinOrg/XDPoSChain/log"
|
"github.com/XinFinOrg/XDPoSChain/log"
|
||||||
|
|
@ -327,7 +328,7 @@ func (b *EthApiBackend) GetVotersRewards(masternodeAddr common.Address) map[comm
|
||||||
// Get signers in blockSigner smartcontract.
|
// Get signers in blockSigner smartcontract.
|
||||||
// Get reward inflation.
|
// Get reward inflation.
|
||||||
chainReward := new(big.Int).Mul(new(big.Int).SetUint64(chain.Config().XDPoS.Reward), new(big.Int).SetUint64(params.Ether))
|
chainReward := new(big.Int).Mul(new(big.Int).SetUint64(chain.Config().XDPoS.Reward), new(big.Int).SetUint64(params.Ether))
|
||||||
chainReward = rewardInflation(chain, chainReward, number, common.BlocksPerYear)
|
chainReward = util.RewardInflation(chain, chainReward, number, common.BlocksPerYear)
|
||||||
totalSigner := new(uint64)
|
totalSigner := new(uint64)
|
||||||
signers, err := contracts.GetRewardForCheckpoint(engine, chain, lastCheckpointBlock.Header(), rCheckpoint, totalSigner)
|
signers, err := contracts.GetRewardForCheckpoint(engine, chain, lastCheckpointBlock.Header(), rCheckpoint, totalSigner)
|
||||||
|
|
||||||
|
|
|
||||||
341
eth/backend.go
341
eth/backend.go
|
|
@ -22,21 +22,16 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
"runtime"
|
"runtime"
|
||||||
"sort"
|
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/XinFinOrg/XDPoSChain/XDCxlending"
|
"github.com/XinFinOrg/XDPoSChain/XDCxlending"
|
||||||
|
|
||||||
"github.com/XinFinOrg/XDPoSChain/accounts/abi/bind"
|
|
||||||
"github.com/XinFinOrg/XDPoSChain/common/hexutil"
|
"github.com/XinFinOrg/XDPoSChain/common/hexutil"
|
||||||
"github.com/XinFinOrg/XDPoSChain/core/state"
|
|
||||||
"github.com/XinFinOrg/XDPoSChain/eth/filters"
|
"github.com/XinFinOrg/XDPoSChain/eth/filters"
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/eth/hooks"
|
||||||
"github.com/XinFinOrg/XDPoSChain/rlp"
|
"github.com/XinFinOrg/XDPoSChain/rlp"
|
||||||
|
|
||||||
"bytes"
|
|
||||||
|
|
||||||
"github.com/XinFinOrg/XDPoSChain/accounts"
|
"github.com/XinFinOrg/XDPoSChain/accounts"
|
||||||
"github.com/XinFinOrg/XDPoSChain/common"
|
"github.com/XinFinOrg/XDPoSChain/common"
|
||||||
"github.com/XinFinOrg/XDPoSChain/consensus"
|
"github.com/XinFinOrg/XDPoSChain/consensus"
|
||||||
|
|
@ -44,7 +39,6 @@ import (
|
||||||
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS/utils"
|
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS/utils"
|
||||||
"github.com/XinFinOrg/XDPoSChain/consensus/ethash"
|
"github.com/XinFinOrg/XDPoSChain/consensus/ethash"
|
||||||
"github.com/XinFinOrg/XDPoSChain/contracts"
|
"github.com/XinFinOrg/XDPoSChain/contracts"
|
||||||
contractValidator "github.com/XinFinOrg/XDPoSChain/contracts/validator/contract"
|
|
||||||
"github.com/XinFinOrg/XDPoSChain/core"
|
"github.com/XinFinOrg/XDPoSChain/core"
|
||||||
"github.com/XinFinOrg/XDPoSChain/core/bloombits"
|
"github.com/XinFinOrg/XDPoSChain/core/bloombits"
|
||||||
|
|
||||||
|
|
@ -290,289 +284,7 @@ func New(ctx *node.ServiceContext, config *Config, XDCXServ *XDCx.XDCX, lendingS
|
||||||
/*
|
/*
|
||||||
XDPoS1.0 Specific hooks
|
XDPoS1.0 Specific hooks
|
||||||
*/
|
*/
|
||||||
|
hooks.AttachConsensusV1Hooks(c, eth.blockchain, chainConfig)
|
||||||
// Hook calculates reward for masternodes
|
|
||||||
c.EngineV1.HookReward = func(chain consensus.ChainReader, stateBlock *state.StateDB, parentState *state.StateDB, header *types.Header) (error, map[string]interface{}) {
|
|
||||||
number := header.Number.Uint64()
|
|
||||||
rCheckpoint := chain.Config().XDPoS.RewardCheckpoint
|
|
||||||
foundationWalletAddr := chain.Config().XDPoS.FoudationWalletAddr
|
|
||||||
if foundationWalletAddr == (common.Address{}) {
|
|
||||||
log.Error("Foundation Wallet Address is empty", "error", foundationWalletAddr)
|
|
||||||
return errors.New("Foundation Wallet Address is empty"), nil
|
|
||||||
}
|
|
||||||
rewards := make(map[string]interface{})
|
|
||||||
if number > 0 && number-rCheckpoint > 0 && foundationWalletAddr != (common.Address{}) {
|
|
||||||
start := time.Now()
|
|
||||||
// Get signers in blockSigner smartcontract.
|
|
||||||
// Get reward inflation.
|
|
||||||
chainReward := new(big.Int).Mul(new(big.Int).SetUint64(chain.Config().XDPoS.Reward), new(big.Int).SetUint64(params.Ether))
|
|
||||||
chainReward = rewardInflation(chain, chainReward, number, common.BlocksPerYear)
|
|
||||||
|
|
||||||
totalSigner := new(uint64)
|
|
||||||
signers, err := contracts.GetRewardForCheckpoint(c, chain, header, rCheckpoint, totalSigner)
|
|
||||||
|
|
||||||
log.Debug("Time Get Signers", "block", header.Number.Uint64(), "time", common.PrettyDuration(time.Since(start)))
|
|
||||||
if err != nil {
|
|
||||||
log.Crit("Fail to get signers for reward checkpoint", "error", err)
|
|
||||||
}
|
|
||||||
rewards["signers"] = signers
|
|
||||||
rewardSigners, err := contracts.CalculateRewardForSigner(chainReward, signers, *totalSigner)
|
|
||||||
if err != nil {
|
|
||||||
log.Crit("Fail to calculate reward for signers", "error", err)
|
|
||||||
}
|
|
||||||
// Add reward for coin holders.
|
|
||||||
voterResults := make(map[common.Address]interface{})
|
|
||||||
if len(signers) > 0 {
|
|
||||||
for signer, calcReward := range rewardSigners {
|
|
||||||
err, rewards := contracts.CalculateRewardForHolders(foundationWalletAddr, parentState, signer, calcReward, number)
|
|
||||||
if err != nil {
|
|
||||||
log.Crit("Fail to calculate reward for holders.", "error", err)
|
|
||||||
}
|
|
||||||
if len(rewards) > 0 {
|
|
||||||
for holder, reward := range rewards {
|
|
||||||
stateBlock.AddBalance(holder, reward)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
voterResults[signer] = rewards
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rewards["rewards"] = voterResults
|
|
||||||
log.Debug("Time Calculated HookReward ", "block", header.Number.Uint64(), "time", common.PrettyDuration(time.Since(start)))
|
|
||||||
}
|
|
||||||
return nil, rewards
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
HookGetSignersFromContract return list masternode for current state (block)
|
|
||||||
This is a solution for work around issue return wrong list signers from snapshot
|
|
||||||
*/
|
|
||||||
c.EngineV1.HookGetSignersFromContract = func(block common.Hash) ([]common.Address, error) {
|
|
||||||
client, err := eth.blockchain.GetClient()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
addr := common.HexToAddress(common.MasternodeVotingSMC)
|
|
||||||
validator, err := contractValidator.NewXDCValidator(addr, client)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
opts := new(bind.CallOpts)
|
|
||||||
var (
|
|
||||||
candidateAddresses []common.Address
|
|
||||||
candidates []utils.Masternode
|
|
||||||
)
|
|
||||||
|
|
||||||
stateDB, err := eth.blockchain.StateAt(eth.blockchain.GetBlockByHash(block).Root())
|
|
||||||
candidateAddresses = state.GetCandidates(stateDB)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
for _, address := range candidateAddresses {
|
|
||||||
v, err := validator.GetCandidateCap(opts, address)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if address.String() != "0x0000000000000000000000000000000000000000" {
|
|
||||||
candidates = append(candidates, utils.Masternode{Address: address, Stake: v})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// sort candidates by stake descending
|
|
||||||
sort.Slice(candidates, func(i, j int) bool {
|
|
||||||
return candidates[i].Stake.Cmp(candidates[j].Stake) >= 0
|
|
||||||
})
|
|
||||||
if len(candidates) > 150 {
|
|
||||||
candidates = candidates[:150]
|
|
||||||
}
|
|
||||||
result := []common.Address{}
|
|
||||||
for _, candidate := range candidates {
|
|
||||||
result = append(result, candidate.Address)
|
|
||||||
}
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hook scans for bad masternodes and decide to penalty them
|
|
||||||
c.EngineV1.HookPenalty = func(chain consensus.ChainReader, blockNumberEpoc uint64) ([]common.Address, error) {
|
|
||||||
canonicalState, err := eth.blockchain.State()
|
|
||||||
if canonicalState == nil || err != nil {
|
|
||||||
log.Crit("Can't get state at head of canonical chain", "head number", eth.blockchain.CurrentHeader().Number.Uint64(), "err", err)
|
|
||||||
}
|
|
||||||
prevEpoc := blockNumberEpoc - chain.Config().XDPoS.Epoch
|
|
||||||
if prevEpoc >= 0 {
|
|
||||||
start := time.Now()
|
|
||||||
prevHeader := chain.GetHeaderByNumber(prevEpoc)
|
|
||||||
penSigners := c.GetMasternodes(chain, prevHeader)
|
|
||||||
if len(penSigners) > 0 {
|
|
||||||
// Loop for each block to check missing sign.
|
|
||||||
for i := prevEpoc; i < blockNumberEpoc; i++ {
|
|
||||||
if i%common.MergeSignRange == 0 || !chainConfig.IsTIP2019(big.NewInt(int64(i))) {
|
|
||||||
bheader := chain.GetHeaderByNumber(i)
|
|
||||||
bhash := bheader.Hash()
|
|
||||||
block := chain.GetBlock(bhash, i)
|
|
||||||
if len(penSigners) > 0 {
|
|
||||||
signedMasternodes, err := contracts.GetSignersFromContract(canonicalState, block)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if len(signedMasternodes) > 0 {
|
|
||||||
// Check signer signed?
|
|
||||||
for _, signed := range signedMasternodes {
|
|
||||||
for j, addr := range penSigners {
|
|
||||||
if signed == addr {
|
|
||||||
// Remove it from dupSigners.
|
|
||||||
penSigners = append(penSigners[:j], penSigners[j+1:]...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log.Debug("Time Calculated HookPenalty ", "block", blockNumberEpoc, "time", common.PrettyDuration(time.Since(start)))
|
|
||||||
return penSigners, nil
|
|
||||||
}
|
|
||||||
return []common.Address{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hook scans for bad masternodes and decide to penalty them
|
|
||||||
c.EngineV1.HookPenaltyTIPSigning = func(chain consensus.ChainReader, header *types.Header, candidates []common.Address) ([]common.Address, error) {
|
|
||||||
prevEpoc := header.Number.Uint64() - chain.Config().XDPoS.Epoch
|
|
||||||
combackEpoch := uint64(0)
|
|
||||||
comebackLength := (common.LimitPenaltyEpoch + 1) * chain.Config().XDPoS.Epoch
|
|
||||||
if header.Number.Uint64() > comebackLength {
|
|
||||||
combackEpoch = header.Number.Uint64() - comebackLength
|
|
||||||
}
|
|
||||||
if prevEpoc >= 0 {
|
|
||||||
start := time.Now()
|
|
||||||
|
|
||||||
listBlockHash := make([]common.Hash, chain.Config().XDPoS.Epoch)
|
|
||||||
|
|
||||||
// get list block hash & stats total created block
|
|
||||||
statMiners := make(map[common.Address]int)
|
|
||||||
listBlockHash[0] = header.ParentHash
|
|
||||||
parentnumber := header.Number.Uint64() - 1
|
|
||||||
parentHash := header.ParentHash
|
|
||||||
for i := uint64(1); i < chain.Config().XDPoS.Epoch; i++ {
|
|
||||||
parentHeader := chain.GetHeader(parentHash, parentnumber)
|
|
||||||
miner, _ := c.RecoverSigner(parentHeader)
|
|
||||||
value, exist := statMiners[miner]
|
|
||||||
if exist {
|
|
||||||
value = value + 1
|
|
||||||
} else {
|
|
||||||
value = 1
|
|
||||||
}
|
|
||||||
statMiners[miner] = value
|
|
||||||
parentHash = parentHeader.ParentHash
|
|
||||||
parentnumber--
|
|
||||||
listBlockHash[i] = parentHash
|
|
||||||
}
|
|
||||||
|
|
||||||
// add list not miner to penalties
|
|
||||||
prevHeader := chain.GetHeaderByNumber(prevEpoc)
|
|
||||||
preMasternodes := c.GetMasternodes(chain, prevHeader)
|
|
||||||
penalties := []common.Address{}
|
|
||||||
for miner, total := range statMiners {
|
|
||||||
if total < common.MinimunMinerBlockPerEpoch {
|
|
||||||
log.Debug("Find a node not enough requirement create block", "addr", miner.Hex(), "total", total)
|
|
||||||
penalties = append(penalties, miner)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, addr := range preMasternodes {
|
|
||||||
if _, exist := statMiners[addr]; !exist {
|
|
||||||
log.Debug("Find a node don't create block", "addr", addr.Hex())
|
|
||||||
penalties = append(penalties, addr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// get list check penalties signing block & list master nodes wil comeback
|
|
||||||
penComebacks := []common.Address{}
|
|
||||||
if combackEpoch > 0 {
|
|
||||||
combackHeader := chain.GetHeaderByNumber(combackEpoch)
|
|
||||||
penalties := common.ExtractAddressFromBytes(combackHeader.Penalties)
|
|
||||||
for _, penaltie := range penalties {
|
|
||||||
for _, addr := range candidates {
|
|
||||||
if penaltie == addr {
|
|
||||||
penComebacks = append(penComebacks, penaltie)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Loop for each block to check missing sign. with comeback nodes
|
|
||||||
mapBlockHash := map[common.Hash]bool{}
|
|
||||||
for i := common.RangeReturnSigner - 1; i >= 0; i-- {
|
|
||||||
if len(penComebacks) > 0 {
|
|
||||||
blockNumber := header.Number.Uint64() - uint64(i) - 1
|
|
||||||
bhash := listBlockHash[i]
|
|
||||||
if blockNumber%common.MergeSignRange == 0 {
|
|
||||||
mapBlockHash[bhash] = true
|
|
||||||
}
|
|
||||||
signData, ok := c.GetCachedSignerData(bhash)
|
|
||||||
if !ok {
|
|
||||||
block := chain.GetBlock(bhash, blockNumber)
|
|
||||||
txs := block.Transactions()
|
|
||||||
signData = c.CacheSigningTxs(bhash, txs)
|
|
||||||
}
|
|
||||||
txs := signData.([]*types.Transaction)
|
|
||||||
// Check signer signed?
|
|
||||||
for _, tx := range txs {
|
|
||||||
blkHash := common.BytesToHash(tx.Data()[len(tx.Data())-32:])
|
|
||||||
from := *tx.From()
|
|
||||||
if mapBlockHash[blkHash] {
|
|
||||||
for j, addr := range penComebacks {
|
|
||||||
if from == addr {
|
|
||||||
// Remove it from dupSigners.
|
|
||||||
penComebacks = append(penComebacks[:j], penComebacks[j+1:]...)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Debug("Time Calculated HookPenaltyTIPSigning ", "block", header.Number, "hash", header.Hash().Hex(), "pen comeback nodes", len(penComebacks), "not enough miner", len(penalties), "time", common.PrettyDuration(time.Since(start)))
|
|
||||||
penalties = append(penalties, penComebacks...)
|
|
||||||
if chain.Config().IsTIPRandomize(header.Number) {
|
|
||||||
return penalties, nil
|
|
||||||
}
|
|
||||||
return penComebacks, nil
|
|
||||||
}
|
|
||||||
return []common.Address{}, nil
|
|
||||||
}
|
|
||||||
// Hook prepares validators M2 for the current epoch at checkpoint block
|
|
||||||
c.EngineV1.HookValidator = func(header *types.Header, signers []common.Address) ([]byte, error) {
|
|
||||||
start := time.Now()
|
|
||||||
validators, err := getValidators(eth.blockchain, signers)
|
|
||||||
if err != nil {
|
|
||||||
return []byte{}, err
|
|
||||||
}
|
|
||||||
header.Validators = validators
|
|
||||||
log.Debug("Time Calculated HookValidator ", "block", header.Number.Uint64(), "time", common.PrettyDuration(time.Since(start)))
|
|
||||||
return validators, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hook verifies masternodes set
|
|
||||||
c.EngineV1.HookVerifyMNs = func(header *types.Header, signers []common.Address) error {
|
|
||||||
number := header.Number.Int64()
|
|
||||||
if number > 0 && number%common.EpocBlockRandomize == 0 {
|
|
||||||
start := time.Now()
|
|
||||||
validators, err := getValidators(eth.blockchain, signers)
|
|
||||||
log.Debug("Time Calculated HookVerifyMNs ", "block", header.Number.Uint64(), "time", common.PrettyDuration(time.Since(start)))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if !bytes.Equal(header.Validators, validators) {
|
|
||||||
return utils.ErrInvalidCheckpointValidators
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
eth.txPool.IsSigner = func(address common.Address) bool {
|
eth.txPool.IsSigner = func(address common.Address) bool {
|
||||||
currentHeader := eth.blockchain.CurrentHeader()
|
currentHeader := eth.blockchain.CurrentHeader()
|
||||||
|
|
@ -883,55 +595,6 @@ func (s *Ethereum) Stop() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getValidators(bc *core.BlockChain, masternodes []common.Address) ([]byte, error) {
|
|
||||||
if bc.Config().XDPoS == nil {
|
|
||||||
return nil, core.ErrNotXDPoS
|
|
||||||
}
|
|
||||||
client, err := bc.GetClient()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// Check m2 exists on chaindb.
|
|
||||||
// Get secrets and opening at epoc block checkpoint.
|
|
||||||
|
|
||||||
var candidates []int64
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
lenSigners := int64(len(masternodes))
|
|
||||||
if lenSigners > 0 {
|
|
||||||
for _, addr := range masternodes {
|
|
||||||
random, err := contracts.GetRandomizeFromContract(client, addr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
candidates = append(candidates, random)
|
|
||||||
}
|
|
||||||
// Get randomize m2 list.
|
|
||||||
m2, err := contracts.GenM2FromRandomize(candidates, lenSigners)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return contracts.BuildValidatorFromM2(m2), nil
|
|
||||||
}
|
|
||||||
return nil, core.ErrNotFoundM1
|
|
||||||
}
|
|
||||||
|
|
||||||
func rewardInflation(chain consensus.ChainReader, chainReward *big.Int, number uint64, blockPerYear uint64) *big.Int {
|
|
||||||
if chain != nil && chain.Config().IsTIPNoHalvingMNReward(new(big.Int).SetUint64(number)) {
|
|
||||||
return chainReward
|
|
||||||
}
|
|
||||||
|
|
||||||
if blockPerYear*2 <= number && number < blockPerYear*5 {
|
|
||||||
chainReward.Div(chainReward, new(big.Int).SetUint64(2))
|
|
||||||
}
|
|
||||||
if blockPerYear*5 <= number {
|
|
||||||
chainReward.Div(chainReward, new(big.Int).SetUint64(4))
|
|
||||||
}
|
|
||||||
|
|
||||||
return chainReward
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Ethereum) GetPeer() int {
|
func (s *Ethereum) GetPeer() int {
|
||||||
return len(s.protocolManager.peers.peers)
|
return len(s.protocolManager.peers.peers)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"math/big"
|
"math/big"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/eth/util"
|
||||||
"github.com/XinFinOrg/XDPoSChain/params"
|
"github.com/XinFinOrg/XDPoSChain/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -11,7 +12,7 @@ func TestRewardInflation(t *testing.T) {
|
||||||
for i := 0; i < 100; i++ {
|
for i := 0; i < 100; i++ {
|
||||||
// the first 2 years
|
// the first 2 years
|
||||||
chainReward := new(big.Int).Mul(new(big.Int).SetUint64(250), new(big.Int).SetUint64(params.Ether))
|
chainReward := new(big.Int).Mul(new(big.Int).SetUint64(250), new(big.Int).SetUint64(params.Ether))
|
||||||
chainReward = rewardInflation(nil, chainReward, uint64(i), 10)
|
chainReward = util.RewardInflation(nil, chainReward, uint64(i), 10)
|
||||||
|
|
||||||
// 3rd year, 4th year, 5th year
|
// 3rd year, 4th year, 5th year
|
||||||
halfReward := new(big.Int).Mul(new(big.Int).SetUint64(125), new(big.Int).SetUint64(params.Ether))
|
halfReward := new(big.Int).Mul(new(big.Int).SetUint64(125), new(big.Int).SetUint64(params.Ether))
|
||||||
|
|
|
||||||
343
eth/hooks/engine_v1_hooks.go
Normal file
343
eth/hooks/engine_v1_hooks.go
Normal file
|
|
@ -0,0 +1,343 @@
|
||||||
|
package hooks
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"math/big"
|
||||||
|
"sort"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/accounts/abi/bind"
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/common"
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/consensus"
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS"
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS/utils"
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/contracts"
|
||||||
|
contractValidator "github.com/XinFinOrg/XDPoSChain/contracts/validator/contract"
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/core"
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/core/state"
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/core/types"
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/eth/util"
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/log"
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/params"
|
||||||
|
)
|
||||||
|
|
||||||
|
func AttachConsensusV1Hooks(adaptor *XDPoS.XDPoS, bc *core.BlockChain, chainConfig *params.ChainConfig) {
|
||||||
|
// Hook scans for bad masternodes and decide to penalty them
|
||||||
|
adaptor.EngineV1.HookPenalty = func(chain consensus.ChainReader, blockNumberEpoc uint64) ([]common.Address, error) {
|
||||||
|
canonicalState, err := bc.State()
|
||||||
|
if canonicalState == nil || err != nil {
|
||||||
|
log.Crit("Can't get state at head of canonical chain", "head number", bc.CurrentHeader().Number.Uint64(), "err", err)
|
||||||
|
}
|
||||||
|
prevEpoc := blockNumberEpoc - chain.Config().XDPoS.Epoch
|
||||||
|
if prevEpoc >= 0 {
|
||||||
|
start := time.Now()
|
||||||
|
prevHeader := chain.GetHeaderByNumber(prevEpoc)
|
||||||
|
penSigners := adaptor.GetMasternodes(chain, prevHeader)
|
||||||
|
if len(penSigners) > 0 {
|
||||||
|
// Loop for each block to check missing sign.
|
||||||
|
for i := prevEpoc; i < blockNumberEpoc; i++ {
|
||||||
|
if i%common.MergeSignRange == 0 || !chainConfig.IsTIP2019(big.NewInt(int64(i))) {
|
||||||
|
bheader := chain.GetHeaderByNumber(i)
|
||||||
|
bhash := bheader.Hash()
|
||||||
|
block := chain.GetBlock(bhash, i)
|
||||||
|
if len(penSigners) > 0 {
|
||||||
|
signedMasternodes, err := contracts.GetSignersFromContract(canonicalState, block)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(signedMasternodes) > 0 {
|
||||||
|
// Check signer signed?
|
||||||
|
for _, signed := range signedMasternodes {
|
||||||
|
for j, addr := range penSigners {
|
||||||
|
if signed == addr {
|
||||||
|
// Remove it from dupSigners.
|
||||||
|
penSigners = append(penSigners[:j], penSigners[j+1:]...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Debug("Time Calculated HookPenalty ", "block", blockNumberEpoc, "time", common.PrettyDuration(time.Since(start)))
|
||||||
|
return penSigners, nil
|
||||||
|
}
|
||||||
|
return []common.Address{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hook scans for bad masternodes and decide to penalty them
|
||||||
|
adaptor.EngineV1.HookPenaltyTIPSigning = func(chain consensus.ChainReader, header *types.Header, candidates []common.Address) ([]common.Address, error) {
|
||||||
|
prevEpoc := header.Number.Uint64() - chain.Config().XDPoS.Epoch
|
||||||
|
combackEpoch := uint64(0)
|
||||||
|
comebackLength := (common.LimitPenaltyEpoch + 1) * chain.Config().XDPoS.Epoch
|
||||||
|
if header.Number.Uint64() > comebackLength {
|
||||||
|
combackEpoch = header.Number.Uint64() - comebackLength
|
||||||
|
}
|
||||||
|
if prevEpoc >= 0 {
|
||||||
|
start := time.Now()
|
||||||
|
|
||||||
|
listBlockHash := make([]common.Hash, chain.Config().XDPoS.Epoch)
|
||||||
|
|
||||||
|
// get list block hash & stats total created block
|
||||||
|
statMiners := make(map[common.Address]int)
|
||||||
|
listBlockHash[0] = header.ParentHash
|
||||||
|
parentnumber := header.Number.Uint64() - 1
|
||||||
|
parentHash := header.ParentHash
|
||||||
|
for i := uint64(1); i < chain.Config().XDPoS.Epoch; i++ {
|
||||||
|
parentHeader := chain.GetHeader(parentHash, parentnumber)
|
||||||
|
miner, _ := adaptor.RecoverSigner(parentHeader)
|
||||||
|
value, exist := statMiners[miner]
|
||||||
|
if exist {
|
||||||
|
value = value + 1
|
||||||
|
} else {
|
||||||
|
value = 1
|
||||||
|
}
|
||||||
|
statMiners[miner] = value
|
||||||
|
parentHash = parentHeader.ParentHash
|
||||||
|
parentnumber--
|
||||||
|
listBlockHash[i] = parentHash
|
||||||
|
}
|
||||||
|
|
||||||
|
// add list not miner to penalties
|
||||||
|
prevHeader := chain.GetHeaderByNumber(prevEpoc)
|
||||||
|
preMasternodes := adaptor.GetMasternodes(chain, prevHeader)
|
||||||
|
penalties := []common.Address{}
|
||||||
|
for miner, total := range statMiners {
|
||||||
|
if total < common.MinimunMinerBlockPerEpoch {
|
||||||
|
log.Debug("Find a node not enough requirement create block", "addr", miner.Hex(), "total", total)
|
||||||
|
penalties = append(penalties, miner)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, addr := range preMasternodes {
|
||||||
|
if _, exist := statMiners[addr]; !exist {
|
||||||
|
log.Debug("Find a node don't create block", "addr", addr.Hex())
|
||||||
|
penalties = append(penalties, addr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get list check penalties signing block & list master nodes wil comeback
|
||||||
|
penComebacks := []common.Address{}
|
||||||
|
if combackEpoch > 0 {
|
||||||
|
combackHeader := chain.GetHeaderByNumber(combackEpoch)
|
||||||
|
penalties := common.ExtractAddressFromBytes(combackHeader.Penalties)
|
||||||
|
for _, penaltie := range penalties {
|
||||||
|
for _, addr := range candidates {
|
||||||
|
if penaltie == addr {
|
||||||
|
penComebacks = append(penComebacks, penaltie)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop for each block to check missing sign. with comeback nodes
|
||||||
|
mapBlockHash := map[common.Hash]bool{}
|
||||||
|
for i := common.RangeReturnSigner - 1; i >= 0; i-- {
|
||||||
|
if len(penComebacks) > 0 {
|
||||||
|
blockNumber := header.Number.Uint64() - uint64(i) - 1
|
||||||
|
bhash := listBlockHash[i]
|
||||||
|
if blockNumber%common.MergeSignRange == 0 {
|
||||||
|
mapBlockHash[bhash] = true
|
||||||
|
}
|
||||||
|
signData, ok := adaptor.GetCachedSignerData(bhash)
|
||||||
|
if !ok {
|
||||||
|
block := chain.GetBlock(bhash, blockNumber)
|
||||||
|
txs := block.Transactions()
|
||||||
|
signData = adaptor.CacheSigningTxs(bhash, txs)
|
||||||
|
}
|
||||||
|
txs := signData.([]*types.Transaction)
|
||||||
|
// Check signer signed?
|
||||||
|
for _, tx := range txs {
|
||||||
|
blkHash := common.BytesToHash(tx.Data()[len(tx.Data())-32:])
|
||||||
|
from := *tx.From()
|
||||||
|
if mapBlockHash[blkHash] {
|
||||||
|
for j, addr := range penComebacks {
|
||||||
|
if from == addr {
|
||||||
|
// Remove it from dupSigners.
|
||||||
|
penComebacks = append(penComebacks[:j], penComebacks[j+1:]...)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debug("Time Calculated HookPenaltyTIPSigning ", "block", header.Number, "hash", header.Hash().Hex(), "pen comeback nodes", len(penComebacks), "not enough miner", len(penalties), "time", common.PrettyDuration(time.Since(start)))
|
||||||
|
penalties = append(penalties, penComebacks...)
|
||||||
|
if chain.Config().IsTIPRandomize(header.Number) {
|
||||||
|
return penalties, nil
|
||||||
|
}
|
||||||
|
return penComebacks, nil
|
||||||
|
}
|
||||||
|
return []common.Address{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hook prepares validators M2 for the current epoch at checkpoint block
|
||||||
|
adaptor.EngineV1.HookValidator = func(header *types.Header, signers []common.Address) ([]byte, error) {
|
||||||
|
start := time.Now()
|
||||||
|
validators, err := getValidators(bc, signers)
|
||||||
|
if err != nil {
|
||||||
|
return []byte{}, err
|
||||||
|
}
|
||||||
|
header.Validators = validators
|
||||||
|
log.Debug("Time Calculated HookValidator ", "block", header.Number.Uint64(), "time", common.PrettyDuration(time.Since(start)))
|
||||||
|
return validators, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hook verifies masternodes set
|
||||||
|
adaptor.EngineV1.HookVerifyMNs = func(header *types.Header, signers []common.Address) error {
|
||||||
|
number := header.Number.Int64()
|
||||||
|
if number > 0 && number%common.EpocBlockRandomize == 0 {
|
||||||
|
start := time.Now()
|
||||||
|
validators, err := getValidators(bc, signers)
|
||||||
|
log.Debug("Time Calculated HookVerifyMNs ", "block", header.Number.Uint64(), "time", common.PrettyDuration(time.Since(start)))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !bytes.Equal(header.Validators, validators) {
|
||||||
|
return utils.ErrInvalidCheckpointValidators
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
HookGetSignersFromContract return list masternode for current state (block)
|
||||||
|
This is a solution for work around issue return wrong list signers from snapshot
|
||||||
|
*/
|
||||||
|
adaptor.EngineV1.HookGetSignersFromContract = func(block common.Hash) ([]common.Address, error) {
|
||||||
|
client, err := bc.GetClient()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
addr := common.HexToAddress(common.MasternodeVotingSMC)
|
||||||
|
validator, err := contractValidator.NewXDCValidator(addr, client)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
opts := new(bind.CallOpts)
|
||||||
|
var (
|
||||||
|
candidateAddresses []common.Address
|
||||||
|
candidates []utils.Masternode
|
||||||
|
)
|
||||||
|
|
||||||
|
stateDB, err := bc.StateAt(bc.GetBlockByHash(block).Root())
|
||||||
|
candidateAddresses = state.GetCandidates(stateDB)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, address := range candidateAddresses {
|
||||||
|
v, err := validator.GetCandidateCap(opts, address)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if address.String() != "0x0000000000000000000000000000000000000000" {
|
||||||
|
candidates = append(candidates, utils.Masternode{Address: address, Stake: v})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// sort candidates by stake descending
|
||||||
|
sort.Slice(candidates, func(i, j int) bool {
|
||||||
|
return candidates[i].Stake.Cmp(candidates[j].Stake) >= 0
|
||||||
|
})
|
||||||
|
if len(candidates) > 150 {
|
||||||
|
candidates = candidates[:150]
|
||||||
|
}
|
||||||
|
result := []common.Address{}
|
||||||
|
for _, candidate := range candidates {
|
||||||
|
result = append(result, candidate.Address)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hook calculates reward for masternodes
|
||||||
|
adaptor.EngineV1.HookReward = func(chain consensus.ChainReader, stateBlock *state.StateDB, parentState *state.StateDB, header *types.Header) (error, map[string]interface{}) {
|
||||||
|
number := header.Number.Uint64()
|
||||||
|
rCheckpoint := chain.Config().XDPoS.RewardCheckpoint
|
||||||
|
foundationWalletAddr := chain.Config().XDPoS.FoudationWalletAddr
|
||||||
|
if foundationWalletAddr == (common.Address{}) {
|
||||||
|
log.Error("Foundation Wallet Address is empty", "error", foundationWalletAddr)
|
||||||
|
return errors.New("Foundation Wallet Address is empty"), nil
|
||||||
|
}
|
||||||
|
rewards := make(map[string]interface{})
|
||||||
|
if number > 0 && number-rCheckpoint > 0 && foundationWalletAddr != (common.Address{}) {
|
||||||
|
start := time.Now()
|
||||||
|
// Get signers in blockSigner smartcontract.
|
||||||
|
// Get reward inflation.
|
||||||
|
chainReward := new(big.Int).Mul(new(big.Int).SetUint64(chain.Config().XDPoS.Reward), new(big.Int).SetUint64(params.Ether))
|
||||||
|
chainReward = util.RewardInflation(chain, chainReward, number, common.BlocksPerYear)
|
||||||
|
|
||||||
|
totalSigner := new(uint64)
|
||||||
|
signers, err := contracts.GetRewardForCheckpoint(adaptor, chain, header, rCheckpoint, totalSigner)
|
||||||
|
|
||||||
|
log.Debug("Time Get Signers", "block", header.Number.Uint64(), "time", common.PrettyDuration(time.Since(start)))
|
||||||
|
if err != nil {
|
||||||
|
log.Crit("Fail to get signers for reward checkpoint", "error", err)
|
||||||
|
}
|
||||||
|
rewards["signers"] = signers
|
||||||
|
rewardSigners, err := contracts.CalculateRewardForSigner(chainReward, signers, *totalSigner)
|
||||||
|
if err != nil {
|
||||||
|
log.Crit("Fail to calculate reward for signers", "error", err)
|
||||||
|
}
|
||||||
|
// Add reward for coin holders.
|
||||||
|
voterResults := make(map[common.Address]interface{})
|
||||||
|
if len(signers) > 0 {
|
||||||
|
for signer, calcReward := range rewardSigners {
|
||||||
|
err, rewards := contracts.CalculateRewardForHolders(foundationWalletAddr, parentState, signer, calcReward, number)
|
||||||
|
if err != nil {
|
||||||
|
log.Crit("Fail to calculate reward for holders.", "error", err)
|
||||||
|
}
|
||||||
|
if len(rewards) > 0 {
|
||||||
|
for holder, reward := range rewards {
|
||||||
|
stateBlock.AddBalance(holder, reward)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
voterResults[signer] = rewards
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rewards["rewards"] = voterResults
|
||||||
|
log.Debug("Time Calculated HookReward ", "block", header.Number.Uint64(), "time", common.PrettyDuration(time.Since(start)))
|
||||||
|
}
|
||||||
|
return nil, rewards
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getValidators(bc *core.BlockChain, masternodes []common.Address) ([]byte, error) {
|
||||||
|
if bc.Config().XDPoS == nil {
|
||||||
|
return nil, core.ErrNotXDPoS
|
||||||
|
}
|
||||||
|
client, err := bc.GetClient()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Check m2 exists on chaindb.
|
||||||
|
// Get secrets and opening at epoc block checkpoint.
|
||||||
|
|
||||||
|
var candidates []int64
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
lenSigners := int64(len(masternodes))
|
||||||
|
if lenSigners > 0 {
|
||||||
|
for _, addr := range masternodes {
|
||||||
|
random, err := contracts.GetRandomizeFromContract(client, addr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
candidates = append(candidates, random)
|
||||||
|
}
|
||||||
|
// Get randomize m2 list.
|
||||||
|
m2, err := contracts.GenM2FromRandomize(candidates, lenSigners)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return contracts.BuildValidatorFromM2(m2), nil
|
||||||
|
}
|
||||||
|
return nil, core.ErrNotFoundM1
|
||||||
|
}
|
||||||
22
eth/util/util.go
Normal file
22
eth/util/util.go
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/consensus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func RewardInflation(chain consensus.ChainReader, chainReward *big.Int, number uint64, blockPerYear uint64) *big.Int {
|
||||||
|
if chain != nil && chain.Config().IsTIPNoHalvingMNReward(new(big.Int).SetUint64(number)) {
|
||||||
|
return chainReward
|
||||||
|
}
|
||||||
|
|
||||||
|
if blockPerYear*2 <= number && number < blockPerYear*5 {
|
||||||
|
chainReward.Div(chainReward, new(big.Int).SetUint64(2))
|
||||||
|
}
|
||||||
|
if blockPerYear*5 <= number {
|
||||||
|
chainReward.Div(chainReward, new(big.Int).SetUint64(4))
|
||||||
|
}
|
||||||
|
|
||||||
|
return chainReward
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue