API: getMasternode and getPoolStatus (#258)

* API: getMasternode and getPoolStatus

* fix test
This commit is contained in:
Liam 2023-05-01 23:01:39 +10:00 committed by GitHub
parent 7894cbe205
commit 7b657f0c4e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 316 additions and 89 deletions

View file

@ -53,6 +53,22 @@ type NetworkInformation struct {
LendingAddress common.Address
}
type SignerTypes struct {
CurrentNumber int
CurrentSigners []common.Address
MissingSigners []common.Address
}
type MasternodesStatus struct {
MasternodesLen int
Masternodes []common.Address
PenaltyLen int
Penalty []common.Address
}
type MessageStatus map[string]map[string]SignerTypes
// GetSnapshot retrieves the state snapshot at a given block.
func (api *API) GetSnapshot(number *rpc.BlockNumber) (*utils.PublicApiSnapshot, error) {
// Retrieve the requested block number (or current if none requested)
@ -104,9 +120,44 @@ func (api *API) GetSignersAtHash(hash common.Hash) ([]common.Address, error) {
return api.XDPoS.GetAuthorisedSignersFromSnapshot(api.chain, header)
}
// Get the latest v2 committed block information. Note: This only applies to v2 engine. it doesn't make sense for v1
func (api *API) GetLatestCommittedBlockHeader() *types.BlockInfo {
return api.XDPoS.EngineV2.GetLatestCommittedBlockInfo()
func (api *API) GetMasternodesByNumber(number *rpc.BlockNumber) MasternodesStatus {
var header *types.Header
if number == nil || *number == rpc.LatestBlockNumber {
header = api.chain.CurrentHeader()
} else if *number == rpc.CommittedBlockNumber {
hash := api.XDPoS.EngineV2.GetLatestCommittedBlockInfo().Hash
header = api.chain.GetHeaderByHash(hash)
} else {
header = api.chain.GetHeaderByNumber(uint64(number.Int64()))
}
masternodes, penalties, err := api.XDPoS.EngineV2.CalcMasternodes(api.chain, header.Number, header.ParentHash)
if err != nil {
return MasternodesStatus{}
}
info := MasternodesStatus{
MasternodesLen: len(masternodes),
Masternodes: masternodes,
PenaltyLen: len(penalties),
Penalty: penalties,
}
return info
}
// Get current vote pool and timeout pool content and missing messages
func (api *API) GetLatestPoolStatus() MessageStatus {
header := api.chain.CurrentHeader()
masternodes := api.XDPoS.EngineV2.GetMasternodes(api.chain, header)
receivedVotes := api.XDPoS.EngineV2.ReceivedVotes()
receivedTimeouts := api.XDPoS.EngineV2.ReceivedTimeouts()
info := make(MessageStatus)
info["vote"] = make(map[string]SignerTypes)
info["timeout"] = make(map[string]SignerTypes)
calculateSigners(info["vote"], receivedVotes, masternodes)
calculateSigners(info["timeout"], receivedTimeouts, masternodes)
return info
}
func (api *API) GetV2BlockByHeader(header *types.Header, uncle bool) *V2BlockInfo {
@ -209,3 +260,28 @@ func (api *API) NetworkInformation() NetworkInformation {
}
return info
}
func calculateSigners(message map[string]SignerTypes, pool map[string]map[common.Hash]utils.PoolObj, masternodes []common.Address) {
for name, objs := range pool {
var currentSigners []common.Address
missingSigners := make([]common.Address, len(masternodes))
copy(missingSigners, masternodes)
num := len(objs)
for _, obj := range objs {
signer := obj.GetSigner()
currentSigners = append(currentSigners, signer)
for i, mn := range missingSigners {
if mn == signer {
missingSigners = append(missingSigners[:i], missingSigners[i+1:]...)
break
}
}
}
message[name] = SignerTypes{
CurrentNumber: num,
CurrentSigners: currentSigners,
MissingSigners: missingSigners,
}
}
}

View file

@ -0,0 +1,73 @@
package XDPoS
import (
"math/big"
"testing"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS/utils"
"github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/stretchr/testify/assert"
)
func TestCalculateSignersVote(t *testing.T) {
info := make(map[string]SignerTypes)
votes := utils.NewPool()
masternodes := []common.Address{{1}, {2}, {3}}
vote1 := types.Vote{
ProposedBlockInfo: &types.BlockInfo{
Hash: common.Hash{1},
Round: types.Round(10),
Number: big.NewInt(910),
},
GapNumber: 450,
}
vote1.SetSigner(common.Address{1})
vote2 := types.Vote{
ProposedBlockInfo: &types.BlockInfo{
Hash: common.Hash{2},
Round: types.Round(11),
Number: big.NewInt(911),
},
GapNumber: 450,
}
vote2.SetSigner(common.Address{2})
votes.Add(&vote1)
votes.Add(&vote2)
calculateSigners(info, votes.Get(), masternodes)
//assert.Equal(t, info["xxx"].CurrentNumber, 2)
assert.Equal(t, 2, 2)
}
func TestCalculateSignersTimeout(t *testing.T) {
info := make(map[string]SignerTypes)
timeouts := utils.NewPool()
masternodes := []common.Address{{1}, {2}, {3}}
timeout1 := types.Timeout{
Round: types.Round(10),
GapNumber: 450,
}
timeout1.SetSigner(common.Address{1})
timeout2 := types.Timeout{
Round: types.Round(11),
GapNumber: 450,
}
timeout1.SetSigner(common.Address{2})
timeouts.Add(&timeout1)
timeouts.Add(&timeout2)
calculateSigners(info, timeouts.Get(), masternodes)
//assert.Equal(t, info["xxx"].CurrentNumber, 2)
assert.Equal(t, 2, 2)
}

View file

@ -138,7 +138,9 @@ func (x *XDPoS_v2) UpdateParams(header *types.Header) {
}()
}
/* V2 Block
/*
V2 Block
SignerFn is a signer callback function to request a hash to be signed by a
backing account.
type SignerFn func(accounts.Account, []byte) ([]byte, error)
@ -574,7 +576,7 @@ func (x *XDPoS_v2) SyncInfoHandler(chain consensus.ChainReader, syncInfo *types.
}
/*
Vote workflow
Vote workflow
*/
func (x *XDPoS_v2) VerifyVoteMessage(chain consensus.ChainReader, vote *types.Vote) (bool, error) {
/*
@ -596,7 +598,7 @@ func (x *XDPoS_v2) VerifyVoteMessage(chain consensus.ChainReader, vote *types.Vo
log.Error("[VerifyVoteMessage] fail to get snapshot for a vote message", "blockNum", vote.ProposedBlockInfo.Number, "blockHash", vote.ProposedBlockInfo.Hash, "voteHash", vote.Hash(), "error", err.Error())
return false, err
}
verified, _, err := x.verifyMsgSignature(types.VoteSigHash(&types.VoteForSign{
verified, signer, err := x.verifyMsgSignature(types.VoteSigHash(&types.VoteForSign{
ProposedBlockInfo: vote.ProposedBlockInfo,
GapNumber: vote.GapNumber,
}), vote.Signature, snapshot.NextEpochMasterNodes)
@ -605,8 +607,11 @@ func (x *XDPoS_v2) VerifyVoteMessage(chain consensus.ChainReader, vote *types.Vo
log.Warn("[VerifyVoteMessage] Master node list item", "index", i, "Master node", mn.Hex())
}
log.Warn("[VerifyVoteMessage] Error while verifying vote message", "votedBlockNum", vote.ProposedBlockInfo.Number.Uint64(), "votedBlockHash", vote.ProposedBlockInfo.Hash.Hex(), "voteHash", vote.Hash(), "error", err.Error())
return false, err
}
return verified, err
vote.SetSigner(signer)
return verified, nil
}
// Consensus entry point for processing vote message to produce QC
@ -630,23 +635,31 @@ func (x *XDPoS_v2) VoteHandler(chain consensus.ChainReader, voteMsg *types.Vote)
*/
func (x *XDPoS_v2) VerifyTimeoutMessage(chain consensus.ChainReader, timeoutMsg *types.Timeout) (bool, error) {
snap, err := x.getSnapshot(chain, timeoutMsg.GapNumber, true)
if err != nil {
log.Error("[VerifyTimeoutMessage] Fail to get snapshot when verifying timeout message!", "messageGapNumber", timeoutMsg.GapNumber)
if err != nil || snap == nil {
log.Error("[VerifyTimeoutMessage] Fail to get snapshot when verifying timeout message!", "messageGapNumber", timeoutMsg.GapNumber, "err", err)
return false, err
}
if snap == nil || len(snap.NextEpochMasterNodes) == 0 {
log.Error("[VerifyTimeoutMessage] Something wrong with the snapshot from gapNumber", "messageGapNumber", timeoutMsg.GapNumber, "snapshot", snap)
if len(snap.NextEpochMasterNodes) == 0 {
log.Error("[VerifyTimeoutMessage] cannot find nextEpochMasterNodes from snapshot", "messageGapNumber", timeoutMsg.GapNumber)
return false, fmt.Errorf("Empty master node lists from snapshot")
}
verified, _, err := x.verifyMsgSignature(types.TimeoutSigHash(&types.TimeoutForSign{
verified, signer, err := x.verifyMsgSignature(types.TimeoutSigHash(&types.TimeoutForSign{
Round: timeoutMsg.Round,
GapNumber: timeoutMsg.GapNumber,
}), timeoutMsg.Signature, snap.NextEpochMasterNodes)
return verified, err
if err != nil {
log.Warn("[VerifyTimeoutMessage] cannot verify timeout signature", "err", err)
return false, err
}
timeoutMsg.SetSigner(signer)
return verified, nil
}
/*
Entry point for handling timeout message to process below:
Entry point for handling timeout message to process below:
*/
func (x *XDPoS_v2) TimeoutHandler(blockChainReader consensus.ChainReader, timeout *types.Timeout) error {
x.lock.Lock()
@ -655,7 +668,7 @@ func (x *XDPoS_v2) TimeoutHandler(blockChainReader consensus.ChainReader, timeou
}
/*
Proposed Block workflow
Proposed Block workflow
*/
func (x *XDPoS_v2) ProposedBlockHandler(chain consensus.ChainReader, blockHeader *types.Header) error {
x.lock.Lock()
@ -866,17 +879,18 @@ func (x *XDPoS_v2) processQC(blockChainReader consensus.ChainReader, incomingQuo
}
/*
1. Set currentRound = QC round + 1 (or TC round +1)
2. Reset timer
3. Reset vote and timeout Pools
1. Set currentRound = QC round + 1 (or TC round +1)
2. Reset timer
3. Reset vote and timeout Pools
*/
func (x *XDPoS_v2) setNewRound(blockChainReader consensus.ChainReader, round types.Round) {
log.Info("[setNewRound] new round and reset pools and workers", "round", round)
x.currentRound = round
x.timeoutCount = 0
x.timeoutWorker.Reset(blockChainReader)
//TODO: vote pools
x.timeoutPool.Clear()
// don't need to clean vote pool, we have other process to clean and it's not good to clean here, some edge case may break
// for example round gets bump during collecting vote, so we have to keep vote.
}
func (x *XDPoS_v2) broadcastToBftChannel(msg interface{}) {
@ -892,7 +906,7 @@ func (x *XDPoS_v2) getSyncInfo() *types.SyncInfo {
}
}
//Find parent and grandparent, check round number, if so, commit grandparent(grandGrandParent of currentBlock)
// Find parent and grandparent, check round number, if so, commit grandparent(grandGrandParent of currentBlock)
func (x *XDPoS_v2) commitBlocks(blockChainReader consensus.ChainReader, proposedBlockHeader *types.Header, proposedBlockRound *types.Round, incomingQc *types.QuorumCert) (bool, error) {
// XDPoS v1.0 switch to v2.0, skip commit
if big.NewInt(0).Sub(proposedBlockHeader.Number, big.NewInt(2)).Cmp(x.config.V2.SwitchBlock) <= 0 {
@ -964,6 +978,10 @@ func (x *XDPoS_v2) GetMasternodes(chain consensus.ChainReader, header *types.Hea
return epochSwitchInfo.Masternodes
}
func (x *XDPoS_v2) CalcMasternodes(chain consensus.ChainReader, blockNum *big.Int, parentHash common.Hash) ([]common.Address, []common.Address, error) {
return x.calcMasternodes(chain, blockNum, parentHash)
}
func (x *XDPoS_v2) calcMasternodes(chain consensus.ChainReader, blockNum *big.Int, parentHash common.Hash) ([]common.Address, []common.Address, error) {
snap, err := x.getSnapshot(chain, blockNum.Uint64(), false)
if err != nil {

View file

@ -41,11 +41,11 @@ func (x *XDPoS_v2) timeoutHandler(blockChainReader consensus.ChainReader, timeou
}
/*
Function that will be called by timeoutPool when it reached threshold.
In the engine v2, we will need to:
1. Genrate TC
2. processTC()
3. generateSyncInfo()
Function that will be called by timeoutPool when it reached threshold.
In the engine v2, we will need to:
1. Genrate TC
2. processTC()
3. generateSyncInfo()
*/
func (x *XDPoS_v2) onTimeoutPoolThresholdReached(blockChainReader consensus.ChainReader, pooledTimeouts map[common.Hash]utils.PoolObj, currentTimeoutMsg utils.PoolObj, gapNumber uint64) error {
signatures := []types.Signature{}
@ -142,8 +142,8 @@ func (x *XDPoS_v2) verifyTC(chain consensus.ChainReader, timeoutCert *types.Time
}
/*
1. Update highestTC
2. Check TC round >= node's currentRound. If yes, call setNewRound
1. Update highestTC
2. Check TC round >= node's currentRound. If yes, call setNewRound
*/
func (x *XDPoS_v2) processTC(blockChainReader consensus.ChainReader, timeoutCert *types.TimeoutCert) error {
if timeoutCert.Round > x.highestTimeoutCert.Round {
@ -191,7 +191,7 @@ func (x *XDPoS_v2) sendTimeout(chain consensus.ChainReader) error {
GapNumber: gapNumber,
}))
if err != nil {
log.Error("[sendTimeout] signSignature when sending out TC", "Error", err)
log.Error("[sendTimeout] signSignature when sending out TC", "Error", err, "round", x.currentRound, "gap", gapNumber)
return err
}
timeoutMsg := &types.Timeout{
@ -210,8 +210,8 @@ func (x *XDPoS_v2) sendTimeout(chain consensus.ChainReader) error {
}
/*
Function that will be called by timer when countdown reaches its threshold.
In the engine v2, we would need to broadcast timeout messages to other peers
Function that will be called by timer when countdown reaches its threshold.
In the engine v2, we would need to broadcast timeout messages to other peers
*/
func (x *XDPoS_v2) OnCountdownTimeout(time time.Time, chain interface{}) error {
x.lock.Lock()
@ -225,7 +225,7 @@ func (x *XDPoS_v2) OnCountdownTimeout(time time.Time, chain interface{}) error {
err := x.sendTimeout(chain.(consensus.ChainReader))
if err != nil {
log.Error("Error while sending out timeout message at time: ", time)
log.Error("Error while sending out timeout message at time: ", "time", time, "err", err)
return err
}
@ -259,3 +259,7 @@ func (x *XDPoS_v2) hygieneTimeoutPool() {
}
}
}
func (x *XDPoS_v2) ReceivedTimeouts() map[string]map[common.Hash]utils.PoolObj {
return x.timeoutPool.Get()
}

View file

@ -96,7 +96,7 @@ func (x *XDPoS_v2) signSignature(signingHash common.Hash) (types.Signature, erro
signedHash, err := signFn(accounts.Account{Address: signer}, signingHash.Bytes())
if err != nil {
return nil, fmt.Errorf("Error while signing hash")
return nil, fmt.Errorf("Error %v while signing hash", err)
}
return signedHash, nil
}
@ -119,6 +119,7 @@ func (x *XDPoS_v2) verifyMsgSignature(signedHashToBeVerified common.Hash, signat
}
}
log.Warn("[verifyMsgSignature] signer is not part of masternode list", "signer", signerAddress, "masternodes", masternodes)
return false, signerAddress, nil
}

View file

@ -91,6 +91,9 @@ func (x *XDPoS_v2) voteHandler(chain consensus.ChainReader, voteMsg *types.Vote)
if err != nil {
return err
}
x.verifyVotes(chain, pooledVotes, proposedBlockHeader)
err = x.onVotePoolThresholdReached(chain, pooledVotes, voteMsg, proposedBlockHeader)
if err != nil {
return err
@ -103,46 +106,53 @@ func (x *XDPoS_v2) voteHandler(chain consensus.ChainReader, voteMsg *types.Vote)
return nil
}
/*
Function that will be called by votePool when it reached threshold.
In the engine v2, we will need to generate and process QC
*/
func (x *XDPoS_v2) onVotePoolThresholdReached(chain consensus.ChainReader, pooledVotes map[common.Hash]utils.PoolObj, currentVoteMsg utils.PoolObj, proposedBlockHeader *types.Header) error {
masternodes := x.GetMasternodes(chain, proposedBlockHeader)
func (x *XDPoS_v2) verifyVotes(chain consensus.ChainReader, votes map[common.Hash]utils.PoolObj, header *types.Header) {
masternodes := x.GetMasternodes(chain, header)
start := time.Now()
emptySigner := common.Address{}
// Filter out non-Master nodes signatures
var wg sync.WaitGroup
wg.Add(len(pooledVotes))
signatures := make([]types.Signature, len(pooledVotes))
counter := 0
for h, vote := range pooledVotes {
go func(hash common.Hash, v *types.Vote, i int) {
wg.Add(len(votes))
for h, vote := range votes {
go func(hash common.Hash, v *types.Vote) {
defer wg.Done()
if v.GetSigner() != emptySigner {
// verify before
return
}
signedVote := types.VoteSigHash(&types.VoteForSign{
ProposedBlockInfo: v.ProposedBlockInfo,
GapNumber: v.GapNumber,
})
verified, _, err := x.verifyMsgSignature(signedVote, v.Signature, masternodes)
verified, masterNode, err := x.verifyMsgSignature(signedVote, v.Signature, masternodes)
if err != nil {
log.Warn("[onVotePoolThresholdReached] Skip not verified vote signatures when building QC", "error", err.Error())
} else if !verified {
log.Warn("[onVotePoolThresholdReached] Skip not verified vote signatures when building QC", "verified", verified)
} else {
signatures[i] = v.Signature
log.Warn("[verifyVotes] error while verifying vote signature", "error", err.Error())
return
}
}(h, vote.(*types.Vote), counter)
counter++
if !verified {
log.Warn("[verifyVotes] non-verified vote signature", "verified", verified)
return
}
v.SetSigner(masterNode)
}(h, vote.(*types.Vote))
}
wg.Wait()
elapsed := time.Since(start)
log.Debug("[onVotePoolThresholdReached] verify message signatures of vote pool took", "elapsed", elapsed)
log.Debug("[verifyVotes] verify message signatures of vote pool took", "elapsed", elapsed)
}
/*
Function that will be called by votePool when it reached threshold.
In the engine v2, we will need to generate and process QC
*/
func (x *XDPoS_v2) onVotePoolThresholdReached(chain consensus.ChainReader, pooledVotes map[common.Hash]utils.PoolObj, currentVoteMsg utils.PoolObj, proposedBlockHeader *types.Header) error {
// The signature list may contain empty entey. we only care the ones with values
var validSignatures []types.Signature
for _, v := range signatures {
if len(v) != 0 {
validSignatures = append(validSignatures, v)
emptySigner := common.Address{}
for _, vote := range pooledVotes {
if vote.GetSigner() != emptySigner {
validSignatures = append(validSignatures, vote.(*types.Vote).Signature)
}
}
@ -247,3 +257,7 @@ func (x *XDPoS_v2) hygieneVotePool() {
}
}
}
func (x *XDPoS_v2) ReceivedVotes() map[string]map[common.Hash]utils.PoolObj {
return x.votePool.Get()
}

View file

@ -9,6 +9,7 @@ import (
type PoolObj interface {
Hash() common.Hash
PoolKey() string
GetSigner() common.Address
}
type Pool struct {
objList map[string]map[common.Hash]PoolObj
@ -20,6 +21,9 @@ func NewPool() *Pool {
objList: make(map[string]map[common.Hash]PoolObj),
}
}
func (p *Pool) Get() map[string]map[common.Hash]PoolObj {
return p.objList
}
// return true if it has reached threshold
func (p *Pool) Add(obj PoolObj) (int, map[common.Hash]PoolObj) {

View file

@ -248,6 +248,7 @@ func TestShouldVerifyTimeoutMessageForFirstV2Block(t *testing.T) {
}
verified, err := engineV2.VerifyTimeoutMessage(blockchain, timeoutMsg)
assert.Equal(t, timeoutMsg.GetSigner(), signer)
assert.Nil(t, err)
assert.True(t, verified)
@ -263,6 +264,7 @@ func TestShouldVerifyTimeoutMessageForFirstV2Block(t *testing.T) {
}
verified, err = engineV2.VerifyTimeoutMessage(blockchain, timeoutMsg)
assert.Equal(t, timeoutMsg.GetSigner(), signer)
assert.Nil(t, err)
assert.True(t, verified)
}
@ -286,7 +288,7 @@ func TestShouldVerifyTimeoutMessage(t *testing.T) {
assert.True(t, verified)
}
func TestTimeoutPoolKeeyGoodHygiene(t *testing.T) {
func TestTimeoutPoolKeyGoodHygiene(t *testing.T) {
blockchain, _, _, signer, signFn, _ := PrepareXDCTestBlockChainForV2Engine(t, 905, params.TestXDPoSMockChainConfig, nil)
engineV2 := blockchain.Engine().(*XDPoS.XDPoS).EngineV2

View file

@ -136,6 +136,7 @@ func TestVoteMessageHandlerSuccessfullyGeneratedAndProcessQC(t *testing.T) {
assert.Equal(t, types.Round(5), currentRound)
// Create another vote which is signed by someone not from the master node list
randomSigner, randomSignFn, err := backends.SimulateWalletAddressAndSignFn()
assert.Nil(t, err)
randomlySignedHash, err := randomSignFn(accounts.Account{Address: randomSigner}, voteSigningHash.Bytes())
@ -147,6 +148,7 @@ func TestVoteMessageHandlerSuccessfullyGeneratedAndProcessQC(t *testing.T) {
}
err = engineV2.VoteHandler(blockchain, voteMsg)
assert.Nil(t, err)
currentRound, lockQuorumCert, highestQuorumCert, _, _, _ = engineV2.GetPropertiesFaker()
// Still using the initlised value because we did not yet go to the next round
assert.Nil(t, lockQuorumCert)
@ -506,6 +508,7 @@ func TestVerifyVoteMsg(t *testing.T) {
}
verified, err = engineV2.VerifyVoteMessage(blockchain, voteMsg)
assert.Equal(t, voteMsg.GetSigner(), signer)
assert.True(t, verified)
assert.Nil(t, err)
}

View file

@ -21,24 +21,64 @@ type BlockInfo struct {
// Vote message in XDPoS 2.0
type Vote struct {
signer common.Address
ProposedBlockInfo *BlockInfo
Signature Signature
GapNumber uint64
}
func (v *Vote) Hash() common.Hash {
return rlpHash(v)
}
func (v *Vote) PoolKey() string {
// return the voted block hash
return fmt.Sprint(v.ProposedBlockInfo.Round, ":", v.GapNumber, ":", v.ProposedBlockInfo.Number, ":", v.ProposedBlockInfo.Hash.Hex())
}
func (v *Vote) GetSigner() common.Address {
return v.signer
}
func (v *Vote) SetSigner(signer common.Address) {
v.signer = signer
}
// Timeout message in XDPoS 2.0
type Timeout struct {
signer common.Address
Round Round
Signature Signature
GapNumber uint64
}
func (t *Timeout) Hash() common.Hash {
return rlpHash(t)
}
func (t *Timeout) PoolKey() string {
// timeout pool key is round:gapNumber
return fmt.Sprint(t.Round, ":", t.GapNumber)
}
func (t *Timeout) GetSigner() common.Address {
return t.signer
}
func (t *Timeout) SetSigner(signer common.Address) {
t.signer = signer
}
// BFT Sync Info message in XDPoS 2.0
type SyncInfo struct {
HighestQuorumCert *QuorumCert
HighestTimeoutCert *TimeoutCert
}
func (s *SyncInfo) Hash() common.Hash {
return rlpHash(s)
}
// Quorum Certificate struct in XDPoS 2.0
type QuorumCert struct {
ProposedBlockInfo *BlockInfo
@ -60,12 +100,6 @@ type ExtraFields_v2 struct {
QuorumCert *QuorumCert
}
type EpochSwitchInfo struct {
Masternodes []common.Address
EpochSwitchBlockInfo *BlockInfo
EpochSwitchParentBlockInfo *BlockInfo
}
// Encode XDPoS 2.0 extra fields into bytes
func (e *ExtraFields_v2) EncodeToBytes() ([]byte, error) {
bytes, err := rlp.EncodeToBytes(e)
@ -76,16 +110,10 @@ func (e *ExtraFields_v2) EncodeToBytes() ([]byte, error) {
return append(versionByte, bytes...), nil
}
func (m *Vote) Hash() common.Hash {
return rlpHash(m)
}
func (m *Timeout) Hash() common.Hash {
return rlpHash(m)
}
func (m *SyncInfo) Hash() common.Hash {
return rlpHash(m)
type EpochSwitchInfo struct {
Masternodes []common.Address
EpochSwitchBlockInfo *BlockInfo
EpochSwitchParentBlockInfo *BlockInfo
}
type VoteForSign struct {
@ -105,13 +133,3 @@ type TimeoutForSign struct {
func TimeoutSigHash(m *TimeoutForSign) common.Hash {
return rlpHash(m)
}
func (m *Vote) PoolKey() string {
// return the voted block hash
return fmt.Sprint(m.ProposedBlockInfo.Round, ":", m.GapNumber, ":", m.ProposedBlockInfo.Number, ":", m.ProposedBlockInfo.Hash.Hex())
}
func (m *Timeout) PoolKey() string {
// timeout pool key is round:gapNumber
return fmt.Sprint(m.Round, ":", m.GapNumber)
}

View file

@ -427,7 +427,8 @@ func (s *PrivateAccountAPI) SignTransaction(ctx context.Context, args SendTxArgs
// safely used to calculate a signature from.
//
// The hash is calulcated as
// keccak256("\x19Ethereum Signed Message:\n"${message length}${message}).
//
// keccak256("\x19Ethereum Signed Message:\n"${message length}${message}).
//
// This gives context to the signed message and prevents signing of transactions.
func signHash(data []byte) []byte {
@ -1149,6 +1150,7 @@ func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args CallArgs) (h
_, _, failed, err := s.doCall(ctx, args, rpc.LatestBlockNumber, vm.Config{}, 0)
if err != nil || failed {
log.Warn("[EstimateGas] api", "err", err)
return false
}
return true
@ -1323,8 +1325,8 @@ func (s *PublicBlockChainAPI) findNearestSignedBlock(ctx context.Context, b *typ
}
/*
findFinalityOfBlock return finality of a block
Use blocksHashCache for to keep track - refer core/blockchain.go for more detail
findFinalityOfBlock return finality of a block
Use blocksHashCache for to keep track - refer core/blockchain.go for more detail
*/
func (s *PublicBlockChainAPI) findFinalityOfBlock(ctx context.Context, b *types.Block, masternodes []common.Address) (uint, error) {
engine, _ := s.b.GetEngine().(*XDPoS.XDPoS)
@ -1389,7 +1391,7 @@ func (s *PublicBlockChainAPI) findFinalityOfBlock(ctx context.Context, b *types.
}
/*
Extract signers from block
Extract signers from block
*/
func (s *PublicBlockChainAPI) getSigners(ctx context.Context, block *types.Block, engine *XDPoS.XDPoS) ([]common.Address, error) {
var err error
@ -2979,7 +2981,8 @@ func GetSignersFromBlocks(b Backend, blockNumber uint64, blockHash common.Hash,
// GetStakerROI Estimate ROI for stakers using the last epoc reward
// then multiple by epoch per year, if the address is not masternode of last epoch - return 0
// Formular:
// ROI = average_latest_epoch_reward_for_voters*number_of_epoch_per_year/latest_total_cap*100
//
// ROI = average_latest_epoch_reward_for_voters*number_of_epoch_per_year/latest_total_cap*100
func (s *PublicBlockChainAPI) GetStakerROI() float64 {
blockNumber := s.b.CurrentBlock().Number().Uint64()
lastCheckpointNumber := blockNumber - (blockNumber % s.b.ChainConfig().XDPoS.Epoch) - s.b.ChainConfig().XDPoS.Epoch // calculate for 2 epochs ago
@ -3005,7 +3008,8 @@ func (s *PublicBlockChainAPI) GetStakerROI() float64 {
// GetStakerROIMasternode Estimate ROI for stakers of a specific masternode using the last epoc reward
// then multiple by epoch per year, if the address is not masternode of last epoch - return 0
// Formular:
// ROI = latest_epoch_reward_for_voters*number_of_epoch_per_year/latest_total_cap*100
//
// ROI = latest_epoch_reward_for_voters*number_of_epoch_per_year/latest_total_cap*100
func (s *PublicBlockChainAPI) GetStakerROIMasternode(masternode common.Address) float64 {
votersReward := s.b.GetVotersRewards(masternode)
if votersReward == nil {

View file

@ -146,6 +146,16 @@ web3._extend({
params: 1,
inputFormatter: [web3._extend.formatters.inputBlockNumberFormatter]
}),
new web3._extend.Method({
name: 'getMasternodesByNumber',
call: 'XDPoS_getMasternodesByNumber',
params: 1,
inputFormatter: [web3._extend.formatters.inputBlockNumberFormatter]
}),
new web3._extend.Method({
name: 'getLatestPoolStatus',
call: 'XDPoS_getLatestPoolStatus'
}),
],
properties: [
new web3._extend.Property({