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 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. // GetSnapshot retrieves the state snapshot at a given block.
func (api *API) GetSnapshot(number *rpc.BlockNumber) (*utils.PublicApiSnapshot, error) { func (api *API) GetSnapshot(number *rpc.BlockNumber) (*utils.PublicApiSnapshot, error) {
// Retrieve the requested block number (or current if none requested) // 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) 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) GetMasternodesByNumber(number *rpc.BlockNumber) MasternodesStatus {
func (api *API) GetLatestCommittedBlockHeader() *types.BlockInfo { var header *types.Header
return api.XDPoS.EngineV2.GetLatestCommittedBlockInfo() 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 { func (api *API) GetV2BlockByHeader(header *types.Header, uncle bool) *V2BlockInfo {
@ -209,3 +260,28 @@ func (api *API) NetworkInformation() NetworkInformation {
} }
return info 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 SignerFn is a signer callback function to request a hash to be signed by a
backing account. backing account.
type SignerFn func(accounts.Account, []byte) ([]byte, error) type SignerFn func(accounts.Account, []byte) ([]byte, 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()) 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 return false, err
} }
verified, _, err := x.verifyMsgSignature(types.VoteSigHash(&types.VoteForSign{ verified, signer, err := x.verifyMsgSignature(types.VoteSigHash(&types.VoteForSign{
ProposedBlockInfo: vote.ProposedBlockInfo, ProposedBlockInfo: vote.ProposedBlockInfo,
GapNumber: vote.GapNumber, GapNumber: vote.GapNumber,
}), vote.Signature, snapshot.NextEpochMasterNodes) }), 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] 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()) 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 // Consensus entry point for processing vote message to produce QC
@ -630,19 +635,27 @@ func (x *XDPoS_v2) VoteHandler(chain consensus.ChainReader, voteMsg *types.Vote)
*/ */
func (x *XDPoS_v2) VerifyTimeoutMessage(chain consensus.ChainReader, timeoutMsg *types.Timeout) (bool, error) { func (x *XDPoS_v2) VerifyTimeoutMessage(chain consensus.ChainReader, timeoutMsg *types.Timeout) (bool, error) {
snap, err := x.getSnapshot(chain, timeoutMsg.GapNumber, true) snap, err := x.getSnapshot(chain, timeoutMsg.GapNumber, true)
if err != nil { if err != nil || snap == nil {
log.Error("[VerifyTimeoutMessage] Fail to get snapshot when verifying timeout message!", "messageGapNumber", timeoutMsg.GapNumber) 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 { if len(snap.NextEpochMasterNodes) == 0 {
log.Error("[VerifyTimeoutMessage] Something wrong with the snapshot from gapNumber", "messageGapNumber", timeoutMsg.GapNumber, "snapshot", snap) log.Error("[VerifyTimeoutMessage] cannot find nextEpochMasterNodes from snapshot", "messageGapNumber", timeoutMsg.GapNumber)
return false, fmt.Errorf("Empty master node lists from snapshot") 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, Round: timeoutMsg.Round,
GapNumber: timeoutMsg.GapNumber, GapNumber: timeoutMsg.GapNumber,
}), timeoutMsg.Signature, snap.NextEpochMasterNodes) }), 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
} }
/* /*
@ -875,8 +888,9 @@ func (x *XDPoS_v2) setNewRound(blockChainReader consensus.ChainReader, round typ
x.currentRound = round x.currentRound = round
x.timeoutCount = 0 x.timeoutCount = 0
x.timeoutWorker.Reset(blockChainReader) x.timeoutWorker.Reset(blockChainReader)
//TODO: vote pools
x.timeoutPool.Clear() 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{}) { func (x *XDPoS_v2) broadcastToBftChannel(msg interface{}) {
@ -964,6 +978,10 @@ func (x *XDPoS_v2) GetMasternodes(chain consensus.ChainReader, header *types.Hea
return epochSwitchInfo.Masternodes 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) { 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) snap, err := x.getSnapshot(chain, blockNum.Uint64(), false)
if err != nil { if err != nil {

View file

@ -191,7 +191,7 @@ func (x *XDPoS_v2) sendTimeout(chain consensus.ChainReader) error {
GapNumber: gapNumber, GapNumber: gapNumber,
})) }))
if err != nil { 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 return err
} }
timeoutMsg := &types.Timeout{ timeoutMsg := &types.Timeout{
@ -225,7 +225,7 @@ func (x *XDPoS_v2) OnCountdownTimeout(time time.Time, chain interface{}) error {
err := x.sendTimeout(chain.(consensus.ChainReader)) err := x.sendTimeout(chain.(consensus.ChainReader))
if err != nil { 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 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()) signedHash, err := signFn(accounts.Account{Address: signer}, signingHash.Bytes())
if err != nil { if err != nil {
return nil, fmt.Errorf("Error while signing hash") return nil, fmt.Errorf("Error %v while signing hash", err)
} }
return signedHash, nil 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 return false, signerAddress, nil
} }

View file

@ -91,6 +91,9 @@ func (x *XDPoS_v2) voteHandler(chain consensus.ChainReader, voteMsg *types.Vote)
if err != nil { if err != nil {
return err return err
} }
x.verifyVotes(chain, pooledVotes, proposedBlockHeader)
err = x.onVotePoolThresholdReached(chain, pooledVotes, voteMsg, proposedBlockHeader) err = x.onVotePoolThresholdReached(chain, pooledVotes, voteMsg, proposedBlockHeader)
if err != nil { if err != nil {
return err return err
@ -103,46 +106,53 @@ func (x *XDPoS_v2) voteHandler(chain consensus.ChainReader, voteMsg *types.Vote)
return nil return nil
} }
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(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, masterNode, err := x.verifyMsgSignature(signedVote, v.Signature, masternodes)
if err != nil {
log.Warn("[verifyVotes] error while verifying vote signature", "error", err.Error())
return
}
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("[verifyVotes] verify message signatures of vote pool took", "elapsed", elapsed)
}
/* /*
Function that will be called by votePool when it reached threshold. Function that will be called by votePool when it reached threshold.
In the engine v2, we will need to generate and process QC 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 { 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)
start := time.Now()
// 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) {
defer wg.Done()
signedVote := types.VoteSigHash(&types.VoteForSign{
ProposedBlockInfo: v.ProposedBlockInfo,
GapNumber: v.GapNumber,
})
verified, _, 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
}
}(h, vote.(*types.Vote), counter)
counter++
}
wg.Wait()
elapsed := time.Since(start)
log.Debug("[onVotePoolThresholdReached] verify message signatures of vote pool took", "elapsed", elapsed)
// The signature list may contain empty entey. we only care the ones with values // The signature list may contain empty entey. we only care the ones with values
var validSignatures []types.Signature var validSignatures []types.Signature
for _, v := range signatures { emptySigner := common.Address{}
if len(v) != 0 { for _, vote := range pooledVotes {
validSignatures = append(validSignatures, v) 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 { type PoolObj interface {
Hash() common.Hash Hash() common.Hash
PoolKey() string PoolKey() string
GetSigner() common.Address
} }
type Pool struct { type Pool struct {
objList map[string]map[common.Hash]PoolObj objList map[string]map[common.Hash]PoolObj
@ -20,6 +21,9 @@ func NewPool() *Pool {
objList: make(map[string]map[common.Hash]PoolObj), 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 // return true if it has reached threshold
func (p *Pool) Add(obj PoolObj) (int, map[common.Hash]PoolObj) { 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) verified, err := engineV2.VerifyTimeoutMessage(blockchain, timeoutMsg)
assert.Equal(t, timeoutMsg.GetSigner(), signer)
assert.Nil(t, err) assert.Nil(t, err)
assert.True(t, verified) assert.True(t, verified)
@ -263,6 +264,7 @@ func TestShouldVerifyTimeoutMessageForFirstV2Block(t *testing.T) {
} }
verified, err = engineV2.VerifyTimeoutMessage(blockchain, timeoutMsg) verified, err = engineV2.VerifyTimeoutMessage(blockchain, timeoutMsg)
assert.Equal(t, timeoutMsg.GetSigner(), signer)
assert.Nil(t, err) assert.Nil(t, err)
assert.True(t, verified) assert.True(t, verified)
} }
@ -286,7 +288,7 @@ func TestShouldVerifyTimeoutMessage(t *testing.T) {
assert.True(t, verified) assert.True(t, verified)
} }
func TestTimeoutPoolKeeyGoodHygiene(t *testing.T) { func TestTimeoutPoolKeyGoodHygiene(t *testing.T) {
blockchain, _, _, signer, signFn, _ := PrepareXDCTestBlockChainForV2Engine(t, 905, params.TestXDPoSMockChainConfig, nil) blockchain, _, _, signer, signFn, _ := PrepareXDCTestBlockChainForV2Engine(t, 905, params.TestXDPoSMockChainConfig, nil)
engineV2 := blockchain.Engine().(*XDPoS.XDPoS).EngineV2 engineV2 := blockchain.Engine().(*XDPoS.XDPoS).EngineV2

View file

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

View file

@ -21,24 +21,64 @@ type BlockInfo struct {
// Vote message in XDPoS 2.0 // Vote message in XDPoS 2.0
type Vote struct { type Vote struct {
signer common.Address
ProposedBlockInfo *BlockInfo ProposedBlockInfo *BlockInfo
Signature Signature Signature Signature
GapNumber uint64 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 // Timeout message in XDPoS 2.0
type Timeout struct { type Timeout struct {
signer common.Address
Round Round Round Round
Signature Signature Signature Signature
GapNumber uint64 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 // BFT Sync Info message in XDPoS 2.0
type SyncInfo struct { type SyncInfo struct {
HighestQuorumCert *QuorumCert HighestQuorumCert *QuorumCert
HighestTimeoutCert *TimeoutCert HighestTimeoutCert *TimeoutCert
} }
func (s *SyncInfo) Hash() common.Hash {
return rlpHash(s)
}
// Quorum Certificate struct in XDPoS 2.0 // Quorum Certificate struct in XDPoS 2.0
type QuorumCert struct { type QuorumCert struct {
ProposedBlockInfo *BlockInfo ProposedBlockInfo *BlockInfo
@ -60,12 +100,6 @@ type ExtraFields_v2 struct {
QuorumCert *QuorumCert QuorumCert *QuorumCert
} }
type EpochSwitchInfo struct {
Masternodes []common.Address
EpochSwitchBlockInfo *BlockInfo
EpochSwitchParentBlockInfo *BlockInfo
}
// Encode XDPoS 2.0 extra fields into bytes // Encode XDPoS 2.0 extra fields into bytes
func (e *ExtraFields_v2) EncodeToBytes() ([]byte, error) { func (e *ExtraFields_v2) EncodeToBytes() ([]byte, error) {
bytes, err := rlp.EncodeToBytes(e) bytes, err := rlp.EncodeToBytes(e)
@ -76,16 +110,10 @@ func (e *ExtraFields_v2) EncodeToBytes() ([]byte, error) {
return append(versionByte, bytes...), nil return append(versionByte, bytes...), nil
} }
func (m *Vote) Hash() common.Hash { type EpochSwitchInfo struct {
return rlpHash(m) Masternodes []common.Address
} EpochSwitchBlockInfo *BlockInfo
EpochSwitchParentBlockInfo *BlockInfo
func (m *Timeout) Hash() common.Hash {
return rlpHash(m)
}
func (m *SyncInfo) Hash() common.Hash {
return rlpHash(m)
} }
type VoteForSign struct { type VoteForSign struct {
@ -105,13 +133,3 @@ type TimeoutForSign struct {
func TimeoutSigHash(m *TimeoutForSign) common.Hash { func TimeoutSigHash(m *TimeoutForSign) common.Hash {
return rlpHash(m) 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,6 +427,7 @@ func (s *PrivateAccountAPI) SignTransaction(ctx context.Context, args SendTxArgs
// safely used to calculate a signature from. // safely used to calculate a signature from.
// //
// The hash is calulcated as // 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. // This gives context to the signed message and prevents signing of transactions.
@ -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) _, _, failed, err := s.doCall(ctx, args, rpc.LatestBlockNumber, vm.Config{}, 0)
if err != nil || failed { if err != nil || failed {
log.Warn("[EstimateGas] api", "err", err)
return false return false
} }
return true return true
@ -2979,6 +2981,7 @@ func GetSignersFromBlocks(b Backend, blockNumber uint64, blockHash common.Hash,
// GetStakerROI Estimate ROI for stakers using the last epoc reward // 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 // then multiple by epoch per year, if the address is not masternode of last epoch - return 0
// Formular: // 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 { func (s *PublicBlockChainAPI) GetStakerROI() float64 {
blockNumber := s.b.CurrentBlock().Number().Uint64() blockNumber := s.b.CurrentBlock().Number().Uint64()
@ -3005,6 +3008,7 @@ func (s *PublicBlockChainAPI) GetStakerROI() float64 {
// GetStakerROIMasternode Estimate ROI for stakers of a specific masternode using the last epoc reward // 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 // then multiple by epoch per year, if the address is not masternode of last epoch - return 0
// Formular: // 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 { func (s *PublicBlockChainAPI) GetStakerROIMasternode(masternode common.Address) float64 {
votersReward := s.b.GetVotersRewards(masternode) votersReward := s.b.GetVotersRewards(masternode)

View file

@ -146,6 +146,16 @@ web3._extend({
params: 1, params: 1,
inputFormatter: [web3._extend.formatters.inputBlockNumberFormatter] 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: [ properties: [
new web3._extend.Property({ new web3._extend.Property({