mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-19 21:31:37 +00:00
api epoch
This commit is contained in:
parent
ec92add428
commit
b43bb5ed1f
6 changed files with 249 additions and 0 deletions
|
|
@ -17,6 +17,7 @@ package XDPoS
|
|||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"math/big"
|
||||
|
||||
"github.com/XinFinOrg/XDPoSChain/common"
|
||||
|
|
@ -320,3 +321,42 @@ func calculateSigners(message map[string]SignerTypes, pool map[string]map[common
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (api *API) GetEpochNumbersBetween(begin, end *rpc.BlockNumber) ([]uint64, error) {
|
||||
beginHeader := api.getHeaderFromApiBlockNum(begin)
|
||||
if beginHeader == nil {
|
||||
return nil, errors.New("illegal begin block number")
|
||||
}
|
||||
endHeader := api.getHeaderFromApiBlockNum(end)
|
||||
if endHeader == nil {
|
||||
return nil, errors.New("illegal end block number")
|
||||
}
|
||||
if beginHeader.Number.Cmp(endHeader.Number) > 0 {
|
||||
return nil, errors.New("illegal begin and end block number, begin > end")
|
||||
}
|
||||
epochSwitchInfos, err := api.XDPoS.GetEpochSwitchInfoBetween(api.chain, beginHeader, endHeader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
epochSwitchNumbers := make([]uint64, len(epochSwitchInfos))
|
||||
for i, info := range epochSwitchInfos {
|
||||
epochSwitchNumbers[i] = info.EpochSwitchBlockInfo.Number.Uint64()
|
||||
}
|
||||
return epochSwitchNumbers, nil
|
||||
}
|
||||
|
||||
/*
|
||||
An API exclusively for V2 consensus, designed to assist in getting rewards of the epoch number.
|
||||
Given the epoch number, search the epoch switch block.
|
||||
*/
|
||||
func (api *API) GetBlockInfoByEpochNum(epochNumber uint64) (*utils.EpochNumInfo, error) {
|
||||
result, err := api.XDPoS.EngineV2.GetBlockByEpochNumber(api.chain, epochNumber)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &utils.EpochNumInfo{
|
||||
EpochBlockHash: result.Hash,
|
||||
EpochRound: result.Round,
|
||||
EpochBlockNumber: result.Number,
|
||||
}, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -157,3 +157,38 @@ func (x *XDPoS_v2) IsEpochSwitch(header *types.Header) (bool, uint64, error) {
|
|||
log.Debug("[IsEpochSwitch]", "is", parentRound < epochStartRound, "parentRound", parentRound, "round", round, "number", header.Number.Uint64(), "epochNum", epochNum, "hash", header.Hash())
|
||||
return parentRound < epochStartRound, epochNum, nil
|
||||
}
|
||||
|
||||
// GetEpochSwitchInfoBetween get epoch switch between begin and end headers
|
||||
// Search backwardly from end number to begin number
|
||||
func (x *XDPoS_v2) GetEpochSwitchInfoBetween(chain consensus.ChainReader, begin, end *types.Header) ([]*types.EpochSwitchInfo, error) {
|
||||
infos := make([]*types.EpochSwitchInfo, 0)
|
||||
// after the first iteration, it becomes nil since epoch switch info does not have header info
|
||||
iteratorHeader := end
|
||||
// after the first iteration, it becomes the parent hash of the epoch switch block
|
||||
iteratorHash := end.Hash()
|
||||
iteratorNum := end.Number
|
||||
// when iterator is strictly > begin number, do the search
|
||||
for iteratorNum.Cmp(begin.Number) > 0 {
|
||||
epochSwitchInfo, err := x.getEpochSwitchInfo(chain, iteratorHeader, iteratorHash)
|
||||
if err != nil {
|
||||
log.Error("[GetEpochSwitchInfoBetween] Adaptor v2 getEpochSwitchInfo has error, potentially bug", "err", err)
|
||||
return nil, err
|
||||
}
|
||||
iteratorHeader = nil
|
||||
// V2 switch epoch switch info has nil parent
|
||||
if epochSwitchInfo.EpochSwitchParentBlockInfo == nil {
|
||||
break
|
||||
}
|
||||
iteratorHash = epochSwitchInfo.EpochSwitchParentBlockInfo.Hash
|
||||
iteratorNum = epochSwitchInfo.EpochSwitchBlockInfo.Number
|
||||
if iteratorNum.Cmp(begin.Number) >= 0 {
|
||||
infos = append(infos, epochSwitchInfo)
|
||||
}
|
||||
|
||||
}
|
||||
// reverse the array
|
||||
for i := 0; i < len(infos)/2; i++ {
|
||||
infos[i], infos[len(infos)-1-i] = infos[len(infos)-1-i], infos[i]
|
||||
}
|
||||
return infos, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package engine_v2
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/XinFinOrg/XDPoSChain/accounts"
|
||||
"github.com/XinFinOrg/XDPoSChain/common"
|
||||
|
|
@ -217,3 +218,40 @@ func (x *XDPoS_v2) CalculateMissingRounds(chain consensus.ChainReader, header *t
|
|||
|
||||
return missedRoundsMetadata, nil
|
||||
}
|
||||
|
||||
func (x *XDPoS_v2) GetBlockByEpochNumber(chain consensus.ChainReader, targetEpochNum uint64) (*types.BlockInfo, error) {
|
||||
currentHeader := chain.CurrentHeader()
|
||||
epochSwitchInfo, err := x.getEpochSwitchInfo(chain, currentHeader, currentHeader.Hash())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
epochNum := x.config.V2.SwitchBlock.Uint64()/x.config.Epoch + uint64(epochSwitchInfo.EpochSwitchBlockInfo.Round)/x.config.Epoch
|
||||
// since below function GetEpochSwitchInfoBetween(chain, start, end) return nil if start == end, we early return the result
|
||||
if targetEpochNum == epochNum {
|
||||
return epochSwitchInfo.EpochSwitchBlockInfo, nil
|
||||
}
|
||||
if targetEpochNum > epochNum {
|
||||
return nil, errors.New("input epoch number > current epoch number")
|
||||
}
|
||||
if targetEpochNum < x.config.V2.SwitchBlock.Uint64()/x.config.Epoch {
|
||||
return nil, errors.New("input epoch number < v2 begin epoch number")
|
||||
}
|
||||
epoch := big.NewInt(int64(x.config.Epoch))
|
||||
estblockNumDiff := new(big.Int).Mul(epoch, big.NewInt(int64(epochNum-targetEpochNum)))
|
||||
estBlockNum := new(big.Int).Sub(epochSwitchInfo.EpochSwitchBlockInfo.Number, estblockNumDiff)
|
||||
if estBlockNum.Cmp(x.config.V2.SwitchBlock) == -1 {
|
||||
estBlockNum.Set(x.config.V2.SwitchBlock)
|
||||
}
|
||||
estBlockHeader := chain.GetHeaderByNumber(estBlockNum.Uint64())
|
||||
epochSwitchInfos, err := x.GetEpochSwitchInfoBetween(chain, estBlockHeader, currentHeader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, info := range epochSwitchInfos {
|
||||
epochNum := x.config.V2.SwitchBlock.Uint64()/x.config.Epoch + uint64(info.EpochSwitchBlockInfo.Round)/x.config.Epoch
|
||||
if epochNum == targetEpochNum {
|
||||
return info.EpochSwitchBlockInfo, nil
|
||||
}
|
||||
}
|
||||
return nil, errors.New("input epoch number not found (all rounds in this epoch are missed, which is very rare)")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,3 +71,10 @@ type PublicApiMissedRoundsMetadata struct {
|
|||
EpochBlockNumber *big.Int
|
||||
MissedRounds []MissedRoundInfo
|
||||
}
|
||||
|
||||
// Given an epoch number, this struct records the epoch switch block (first block in epoch) infos such as block number
|
||||
type EpochNumInfo struct {
|
||||
EpochBlockHash common.Hash `json:"hash"`
|
||||
EpochRound types.Round `json:"round"`
|
||||
EpochBlockNumber *big.Int `json:"number"`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package engine_v2_tests
|
|||
|
||||
import (
|
||||
"math/big"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS"
|
||||
|
|
@ -109,3 +110,120 @@ func TestGetMissedRoundsInEpochByBlockNum(t *testing.T) {
|
|||
|
||||
assert.NotEqual(t, data.MissedRounds[0].Miner, data.MissedRounds[1].Miner)
|
||||
}
|
||||
|
||||
func TestGetEpochNumbersBetween(t *testing.T) {
|
||||
_, bc, _, _, _ := PrepareXDCTestBlockChainWith128Candidates(t, 1802, params.TestXDPoSMockChainConfig)
|
||||
|
||||
engine := bc.GetBlockChain().Engine().(*XDPoS.XDPoS)
|
||||
|
||||
begin := rpc.BlockNumber(1800)
|
||||
end := rpc.BlockNumber(1802)
|
||||
numbers, err := engine.APIs(bc.GetBlockChain())[0].Service.(*XDPoS.API).GetEpochNumbersBetween(&begin, &end)
|
||||
|
||||
assert.True(t, reflect.DeepEqual([]uint64{1800}, numbers))
|
||||
assert.Nil(t, err)
|
||||
|
||||
begin = rpc.BlockNumber(1799)
|
||||
end = rpc.BlockNumber(1802)
|
||||
numbers, err = engine.APIs(bc.GetBlockChain())[0].Service.(*XDPoS.API).GetEpochNumbersBetween(&begin, &end)
|
||||
|
||||
assert.True(t, reflect.DeepEqual([]uint64{1800}, numbers))
|
||||
assert.Nil(t, err)
|
||||
|
||||
begin = rpc.BlockNumber(1799)
|
||||
end = rpc.BlockNumber(1802)
|
||||
numbers, err = engine.APIs(bc.GetBlockChain())[0].Service.(*XDPoS.API).GetEpochNumbersBetween(&begin, &end)
|
||||
|
||||
assert.True(t, reflect.DeepEqual([]uint64{1800}, numbers))
|
||||
assert.Nil(t, err)
|
||||
|
||||
begin = rpc.BlockNumber(901)
|
||||
end = rpc.BlockNumber(1802)
|
||||
numbers, err = engine.APIs(bc.GetBlockChain())[0].Service.(*XDPoS.API).GetEpochNumbersBetween(&begin, &end)
|
||||
|
||||
assert.True(t, reflect.DeepEqual([]uint64{901, 1800}, numbers))
|
||||
assert.Nil(t, err)
|
||||
|
||||
// 900 is V1, not V2, so error
|
||||
begin = rpc.BlockNumber(900)
|
||||
end = rpc.BlockNumber(1802)
|
||||
numbers, err = engine.APIs(bc.GetBlockChain())[0].Service.(*XDPoS.API).GetEpochNumbersBetween(&begin, &end)
|
||||
|
||||
assert.Nil(t, numbers)
|
||||
assert.EqualError(t, err, "not supported in the v1 consensus")
|
||||
|
||||
// 1803 not exist
|
||||
begin = rpc.BlockNumber(901)
|
||||
end = rpc.BlockNumber(1803)
|
||||
numbers, err = engine.APIs(bc.GetBlockChain())[0].Service.(*XDPoS.API).GetEpochNumbersBetween(&begin, &end)
|
||||
|
||||
assert.Nil(t, numbers)
|
||||
assert.EqualError(t, err, "illegal end block number")
|
||||
|
||||
// 1803 not exist
|
||||
begin = rpc.BlockNumber(1803)
|
||||
end = rpc.BlockNumber(1803)
|
||||
numbers, err = engine.APIs(bc.GetBlockChain())[0].Service.(*XDPoS.API).GetEpochNumbersBetween(&begin, &end)
|
||||
|
||||
assert.Nil(t, numbers)
|
||||
assert.EqualError(t, err, "illegal begin block number")
|
||||
}
|
||||
func TestGetBlockByEpochNumber(t *testing.T) {
|
||||
blockchain, _, currentBlock, signer, signFn := PrepareXDCTestBlockChainWithPenaltyForV2Engine(t, 1802, params.TestXDPoSMockChainConfig)
|
||||
|
||||
blockCoinBase := "0x111000000000000000000000000000000123"
|
||||
largeRound := int64(1802)
|
||||
newBlock := CreateBlock(blockchain, params.TestXDPoSMockChainConfig, currentBlock, int(currentBlock.NumberU64())+1, largeRound, blockCoinBase, signer, signFn, nil, nil, currentBlock.Header().Root.Hex())
|
||||
err := blockchain.InsertBlock(newBlock)
|
||||
assert.Nil(t, err)
|
||||
largeRound2 := int64(3603)
|
||||
newBlock2 := CreateBlock(blockchain, params.TestXDPoSMockChainConfig, newBlock, int(newBlock.NumberU64())+1, largeRound2, blockCoinBase, signer, signFn, nil, nil, newBlock.Header().Root.Hex())
|
||||
err = blockchain.InsertBlock(newBlock2)
|
||||
assert.Nil(t, err)
|
||||
|
||||
// block num, round, epoch is as follows
|
||||
// 900,0,1 (v2 switch block, not v2 epoch switch block)
|
||||
// 901,1,1 (1st epoch switch block)
|
||||
// 902,2,1
|
||||
// ...
|
||||
// 1800,900,2 (2nd epoch switch block)
|
||||
// 1801,901,2
|
||||
// 1802,902,2
|
||||
// 1803,1802,3 (epoch switch)
|
||||
// epoch 4 has no block
|
||||
// 1804,3603,5 (epoch switch)
|
||||
engine := blockchain.Engine().(*XDPoS.XDPoS)
|
||||
|
||||
// init the snapshot, otherwise getEpochSwitchInfo would return error
|
||||
checkpointHeader := blockchain.GetHeaderByNumber(blockchain.Config().XDPoS.V2.SwitchBlock.Uint64() + 1)
|
||||
err = engine.Initial(blockchain, checkpointHeader)
|
||||
assert.Nil(t, err)
|
||||
|
||||
info, err := engine.APIs(blockchain)[0].Service.(*XDPoS.API).GetBlockInfoByEpochNum(0)
|
||||
assert.NotNil(t, err)
|
||||
assert.Nil(t, info)
|
||||
|
||||
info, err = engine.APIs(blockchain)[0].Service.(*XDPoS.API).GetBlockInfoByEpochNum(1)
|
||||
assert.Equal(t, info.EpochRound, types.Round(1))
|
||||
assert.Nil(t, err)
|
||||
|
||||
info, err = engine.APIs(blockchain)[0].Service.(*XDPoS.API).GetBlockInfoByEpochNum(2)
|
||||
assert.Equal(t, info.EpochRound, types.Round(900))
|
||||
assert.Nil(t, err)
|
||||
|
||||
info, err = engine.APIs(blockchain)[0].Service.(*XDPoS.API).GetBlockInfoByEpochNum(3)
|
||||
assert.Equal(t, info.EpochRound, types.Round(largeRound))
|
||||
assert.Nil(t, err)
|
||||
|
||||
info, err = engine.APIs(blockchain)[0].Service.(*XDPoS.API).GetBlockInfoByEpochNum(4)
|
||||
assert.NotNil(t, err)
|
||||
assert.Nil(t, info)
|
||||
|
||||
info, err = engine.APIs(blockchain)[0].Service.(*XDPoS.API).GetBlockInfoByEpochNum(5)
|
||||
assert.Equal(t, info.EpochRound, types.Round(largeRound2))
|
||||
assert.Nil(t, err)
|
||||
|
||||
info, err = engine.APIs(blockchain)[0].Service.(*XDPoS.API).GetBlockInfoByEpochNum(6)
|
||||
assert.NotNil(t, err)
|
||||
assert.Nil(t, info)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -162,6 +162,17 @@ web3._extend({
|
|||
params: 1,
|
||||
inputFormatter: [web3._extend.formatters.inputBlockNumberFormatter]
|
||||
}),
|
||||
new web3._extend.Method({
|
||||
name: 'getEpochNumbersBetween',
|
||||
call: 'XDPoS_getEpochNumbersBetween',
|
||||
params: 2,
|
||||
inputFormatter: [web3._extend.formatters.inputBlockNumberFormatter, web3._extend.formatters.inputBlockNumberFormatter]
|
||||
}),
|
||||
new web3._extend.Method({
|
||||
name: 'getBlockInfoByEpochNum',
|
||||
call: 'XDPoS_getBlockInfoByEpochNum',
|
||||
params: 1,
|
||||
}),
|
||||
],
|
||||
properties: [
|
||||
new web3._extend.Property({
|
||||
|
|
|
|||
Loading…
Reference in a new issue