diff --git a/consensus/XDPoS/XDPoS.go b/consensus/XDPoS/XDPoS.go index bf8a16e1691d..e8878734e504 100644 --- a/consensus/XDPoS/XDPoS.go +++ b/consensus/XDPoS/XDPoS.go @@ -243,7 +243,7 @@ func (x *XDPoS) GetPeriod() uint64 { func (x *XDPoS) IsAuthorisedAddress(header *types.Header, chain consensus.ChainReader, address common.Address) bool { switch x.config.BlockConsensusVersion(header.Number) { case params.ConsensusEngineVersion2: - return true + return x.EngineV2.IsAuthorisedAddress(header, chain, address) default: // Default "v1" return x.EngineV1.IsAuthorisedAddress(header, chain, address) } diff --git a/consensus/XDPoS/engines/engine_v2/engine.go b/consensus/XDPoS/engines/engine_v2/engine.go index 993f8725422a..f69c01878d13 100644 --- a/consensus/XDPoS/engines/engine_v2/engine.go +++ b/consensus/XDPoS/engines/engine_v2/engine.go @@ -324,6 +324,29 @@ func (x *XDPoS_v2) YourTurn(chain consensus.ChainReader, parent *types.Header, s return len(masternodes), preIndex, curIndex, false, nil } +func (x *XDPoS_v2) IsAuthorisedAddress(header *types.Header, chain consensus.ChainReader, address common.Address) bool { + var extraField utils.ExtraFields_v2 + err := utils.DecodeBytesExtraFields(header.Extra, &extraField) + if err != nil { + log.Error("[IsAuthorisedAddress] Fail to decode v2 extra data", "Hash", header.Hash(), "Extra", header.Extra, "Error", err) + return false + } + blockRound := extraField.Round + + masterNodes := x.GetMasternodes(chain, header) + + if len(masterNodes) == 0 { + log.Error("[IsAuthorisedAddress] Fail to find any master nodes from current block round epoch", "Hash", header.Hash(), "Round", blockRound, "Number", header.Number) + return false + } + leaderIndex := uint64(blockRound) % x.config.Epoch % uint64(len(masterNodes)) + if masterNodes[leaderIndex] == address { + return true + } + log.Warn("Not authorised address", "Address", address, "MN", masterNodes, "Hash", header.Hash(), "masterNodes[leaderIndex]", masterNodes[leaderIndex], "Address", address) + return false +} + // Copy from v1 func whoIsCreator(snap *SnapshotV2, header *types.Header) (common.Address, error) { if header.Number.Uint64() == 0 { diff --git a/consensus/tests/authorised_masternode_test.go b/consensus/tests/authorised_masternode_test.go new file mode 100644 index 000000000000..1c899c6f331d --- /dev/null +++ b/consensus/tests/authorised_masternode_test.go @@ -0,0 +1,70 @@ +package tests + +import ( + "math/big" + "testing" + + "github.com/XinFinOrg/XDPoSChain/common" + "github.com/XinFinOrg/XDPoSChain/consensus/XDPoS" + "github.com/XinFinOrg/XDPoSChain/core/types" + "github.com/XinFinOrg/XDPoSChain/params" + "github.com/stretchr/testify/assert" +) + +func TestIsAuthorisedMNForConsensusV1(t *testing.T) { + /* + V1 consensus engine + */ + blockchain, _, parentBlock, _ := PrepareXDCTestBlockChain(t, GAP-2, params.TestXDPoSMockChainConfig) + // Insert first Block 449 + t.Logf("Inserting block with propose at 449...") + blockCoinbaseA := "0xaaa0000000000000000000000000000000000449" + tx, err := voteTX(37117, 0, acc1Addr.String()) + if err != nil { + t.Fatal(err) + } + + //Get from block validator error message + merkleRoot := "46234e9cd7e85a267f7f0435b15256a794a2f6d65cc98cdbd21dcd10a01d9772" + header := &types.Header{ + Root: common.HexToHash(merkleRoot), + Number: big.NewInt(int64(449)), + ParentHash: parentBlock.Hash(), + Coinbase: common.HexToAddress(blockCoinbaseA), + } + block449, err := insertBlockTxs(blockchain, header, []*types.Transaction{tx}) + if err != nil { + t.Fatal(err) + } + parentBlock = block449 + + // At block 449, we should not update signerList. we need to update it till block 450 gap block. + // Acc3 is the default account that is on the signerList + + engine := blockchain.Engine().(*XDPoS.XDPoS) + isAuthorisedMN := engine.IsAuthorisedAddress(block449.Header(), blockchain, acc3Addr) + assert.True(t, isAuthorisedMN) + + isAuthorisedMN = engine.IsAuthorisedAddress(block449.Header(), blockchain, acc1Addr) + assert.False(t, isAuthorisedMN) + + // Now, let's mine another block to trigger the GAP block signerList update + block450CoinbaseAddress := "0xaaa0000000000000000000000000000000000450" + merkleRoot = "46234e9cd7e85a267f7f0435b15256a794a2f6d65cc98cdbd21dcd10a01d9772" + header = &types.Header{ + Root: common.HexToHash(merkleRoot), + Number: big.NewInt(int64(450)), + ParentHash: parentBlock.Hash(), + Coinbase: common.HexToAddress(block450CoinbaseAddress), + } + block450, err := insertBlock(blockchain, header) + if err != nil { + t.Fatal(err) + } + + isAuthorisedMN = engine.IsAuthorisedAddress(block450.Header(), blockchain, acc3Addr) + assert.False(t, isAuthorisedMN) + + isAuthorisedMN = engine.IsAuthorisedAddress(block450.Header(), blockchain, acc1Addr) + assert.True(t, isAuthorisedMN) +}