From 47bfdf7635da553eed05ab753751e347c97f6a8b Mon Sep 17 00:00:00 2001 From: Liam Date: Wed, 29 Nov 2023 11:11:58 +1100 Subject: [PATCH] Move masternode in v2 config (#372) * move masternode in v2 config * update number to meet 7 vote for current setup * add test * update all failed test * fix test * remove comment * remove comment * fix test --- XDCx/XDCx.go | 8 ++--- common/constants.go | 2 +- common/constants/constants.go.devnet | 2 +- common/constants/constants.go.testnet | 2 +- consensus/XDPoS/engines/engine_v2/engine.go | 8 ++--- consensus/XDPoS/engines/engine_v2/mining.go | 14 ++++----- consensus/XDPoS/engines/engine_v2/timeout.go | 2 +- .../engine_v1_tests/block_signer_test.go | 4 +-- .../authorised_masternode_test.go | 6 ++-- consensus/tests/engine_v2_tests/mine_test.go | 13 ++++++++- .../engine_v2_tests/verify_header_test.go | 2 +- internal/ethapi/api.go | 24 +++++++++++++-- params/config.go | 29 ++++++++++++++----- params/config_test.go | 8 ++--- 14 files changed, 85 insertions(+), 39 deletions(-) diff --git a/XDCx/XDCx.go b/XDCx/XDCx.go index 2a8d9b299a..e605b69ad0 100644 --- a/XDCx/XDCx.go +++ b/XDCx/XDCx.go @@ -310,10 +310,10 @@ func (XDCx *XDCX) ConvertXDCToToken(chain consensus.ChainContext, statedb *state } // there are 3 tasks need to complete to update data in SDK nodes after matching -// 1. txMatchData.Order: order has been processed. This order should be put to `orders` collection with status sdktypes.OrderStatusOpen -// 2. txMatchData.Trades: includes information of matched orders. -// a. PutObject them to `trades` collection -// b. Update status of regrading orders to sdktypes.OrderStatusFilled +// 1. txMatchData.Order: order has been processed. This order should be put to `orders` collection with status sdktypes.OrderStatusOpen +// 2. txMatchData.Trades: includes information of matched orders. +// a. PutObject them to `trades` collection +// b. Update status of regrading orders to sdktypes.OrderStatusFilled func (XDCx *XDCX) SyncDataToSDKNode(takerOrderInTx *tradingstate.OrderItem, txHash common.Hash, txMatchTime time.Time, statedb *state.StateDB, trades []map[string]string, rejectedOrders []*tradingstate.OrderItem, dirtyOrderCount *uint64) error { var ( // originTakerOrder: order get from db, nil if it doesn't exist diff --git a/common/constants.go b/common/constants.go index 812e260d1d..71b1093cf0 100644 --- a/common/constants.go +++ b/common/constants.go @@ -15,7 +15,7 @@ const ( EpocBlockOpening = 850 EpocBlockRandomize = 900 MaxMasternodes = 18 - MaxMasternodesV2 = 108 + MaxMasternodesV2 = 108 // Last v1 masternodes LimitPenaltyEpoch = 4 LimitPenaltyEpochV2 = 0 BlocksPerYearTest = uint64(200000) diff --git a/common/constants/constants.go.devnet b/common/constants/constants.go.devnet index 2cd660802f..c121d30523 100644 --- a/common/constants/constants.go.devnet +++ b/common/constants/constants.go.devnet @@ -15,7 +15,7 @@ const ( EpocBlockOpening = 850 EpocBlockRandomize = 900 MaxMasternodes = 18 - MaxMasternodesV2 = 108 + MaxMasternodesV2 = 108 // Last v1 masternodes LimitPenaltyEpoch = 4 LimitPenaltyEpochV2 = 0 BlocksPerYearTest = uint64(200000) diff --git a/common/constants/constants.go.testnet b/common/constants/constants.go.testnet index 66541fa03c..0c1db046cf 100644 --- a/common/constants/constants.go.testnet +++ b/common/constants/constants.go.testnet @@ -15,7 +15,7 @@ const ( EpocBlockOpening = 850 EpocBlockRandomize = 900 MaxMasternodes = 18 - MaxMasternodesV2 = 15 + MaxMasternodesV2 = 15 // Last v1 masternodes LimitPenaltyEpoch = 4 LimitPenaltyEpochV2 = 0 BlocksPerYearTest = uint64(200000) diff --git a/consensus/XDPoS/engines/engine_v2/engine.go b/consensus/XDPoS/engines/engine_v2/engine.go index 86f22905d0..62a34d1a09 100644 --- a/consensus/XDPoS/engines/engine_v2/engine.go +++ b/consensus/XDPoS/engines/engine_v2/engine.go @@ -264,8 +264,7 @@ func (x *XDPoS_v2) YourTurn(chain consensus.ChainReader, parent *types.Header, s } waitedTime := time.Now().Unix() - parent.Time.Int64() - _, parentRound, _, err := x.getExtraFields(parent) - minePeriod := x.config.V2.Config(uint64(parentRound) + 1).MinePeriod // plus 1 means current block + minePeriod := x.config.V2.Config(uint64(x.currentRound)).MinePeriod if waitedTime < int64(minePeriod) { log.Trace("[YourTurn] wait after mine period", "minePeriod", minePeriod, "waitedTime", waitedTime) return false, nil @@ -794,7 +793,7 @@ func (x *XDPoS_v2) verifyQC(blockChainReader consensus.ChainReader, quorumCert * certThreshold := x.config.V2.Config(uint64(qcRound)).CertThreshold if (qcRound > 0) && (signatures == nil || float64(len(signatures)) < float64(epochInfo.MasternodesLen)*certThreshold) { //First V2 Block QC, QC Signatures is initial nil - log.Warn("[verifyHeader] Invalid QC Signature is nil or less then config", "QC", quorumCert, "QCNumber", quorumCert.ProposedBlockInfo.Number, "Signatures len", len(signatures), "CertThreshold", float64(epochInfo.MasternodesLen)*certThreshold) + log.Warn("[verifyHeader] Invalid QC Signature is nil or less then config", "QCNumber", quorumCert.ProposedBlockInfo.Number, "LenSignatures", len(signatures), "CertThreshold", float64(epochInfo.MasternodesLen)*certThreshold) return utils.ErrInvalidQCSignatures } start := time.Now() @@ -1000,8 +999,7 @@ func (x *XDPoS_v2) GetStandbynodes(chain consensus.ChainReader, header *types.He // Calculate masternodes for a block number and parent hash. In V2, truncating candidates[:MaxMasternodes] is done in this function. func (x *XDPoS_v2) calcMasternodes(chain consensus.ChainReader, blockNum *big.Int, parentHash common.Hash) ([]common.Address, []common.Address, error) { // using new max masterndoes - maxMasternodes := common.MaxMasternodesV2 - + maxMasternodes := x.config.V2.Config(uint64(x.currentRound)).MaxMasternodes snap, err := x.getSnapshot(chain, blockNum.Uint64(), false) if err != nil { log.Error("[calcMasternodes] Adaptor v2 getSnapshot has error", "err", err) diff --git a/consensus/XDPoS/engines/engine_v2/mining.go b/consensus/XDPoS/engines/engine_v2/mining.go index b12e430d93..72722de75e 100644 --- a/consensus/XDPoS/engines/engine_v2/mining.go +++ b/consensus/XDPoS/engines/engine_v2/mining.go @@ -40,20 +40,20 @@ func (x *XDPoS_v2) yourturn(chain consensus.ChainReader, round types.Round, pare return false, errors.New("masternodes not found") } - curIndex := utils.Position(masterNodes, signer) - if curIndex == -1 { - log.Warn("[yourturn] I am not in masternodes list", "Hash", parent.Hash(), "signer", signer) - return false, nil - } - for i, s := range masterNodes { log.Debug("[yourturn] Masternode:", "index", i, "address", s.String(), "parentBlockNum", parent.Number) } + curIndex := utils.Position(masterNodes, signer) + if curIndex == -1 { + log.Warn("[yourturn] I am not in masternodes list", "Hash", parent.Hash().Hex(), "signer", signer.Hex()) + return false, nil + } + leaderIndex := uint64(round) % x.config.Epoch % uint64(len(masterNodes)) x.whosTurn = masterNodes[leaderIndex] if x.whosTurn != signer { - log.Info("[yourturn] Not my turn", "curIndex", curIndex, "leaderIndex", leaderIndex, "Hash", parent.Hash().Hex(), "whosTurn", x.whosTurn, "myaddr", signer) + log.Info("[yourturn] Not my turn", "curIndex", curIndex, "leaderIndex", leaderIndex, "Hash", parent.Hash().Hex(), "whosTurn", x.whosTurn.Hex(), "myaddr", signer.Hex()) return false, nil } diff --git a/consensus/XDPoS/engines/engine_v2/timeout.go b/consensus/XDPoS/engines/engine_v2/timeout.go index bb9f54aeb0..d03f2d656a 100644 --- a/consensus/XDPoS/engines/engine_v2/timeout.go +++ b/consensus/XDPoS/engines/engine_v2/timeout.go @@ -34,7 +34,7 @@ func (x *XDPoS_v2) timeoutHandler(blockChainReader consensus.ChainReader, timeou } // Threshold reached - certThreshold := x.config.V2.Config(uint64(x.currentRound)).CertThreshold + certThreshold := x.config.V2.Config(uint64(timeout.Round)).CertThreshold isThresholdReached := float64(numberOfTimeoutsInPool) >= float64(epochInfo.MasternodesLen)*certThreshold if isThresholdReached { log.Info(fmt.Sprintf("Timeout pool threashold reached: %v, number of items in the pool: %v", isThresholdReached, numberOfTimeoutsInPool)) diff --git a/consensus/tests/engine_v1_tests/block_signer_test.go b/consensus/tests/engine_v1_tests/block_signer_test.go index 673c23b1bc..459511ec2b 100644 --- a/consensus/tests/engine_v1_tests/block_signer_test.go +++ b/consensus/tests/engine_v1_tests/block_signer_test.go @@ -92,7 +92,7 @@ func TestNotChangeSingerListIfNothingProposedOrVoted(t *testing.T) { } } -//Should call updateM1 at gap block, and update the snapshot if there are SM transactions involved +// Should call updateM1 at gap block, and update the snapshot if there are SM transactions involved func TestUpdateSignerListIfVotedBeforeGap(t *testing.T) { blockchain, backend, parentBlock, signer, signFn := PrepareXDCTestBlockChain(t, GAP-2, params.TestXDPoSMockChainConfig) @@ -166,7 +166,7 @@ func TestUpdateSignerListIfVotedBeforeGap(t *testing.T) { } } -//Should call updateM1 before gap block, and update the snapshot if there are SM transactions involved +// Should call updateM1 before gap block, and update the snapshot if there are SM transactions involved func TestCallUpdateM1WithSmartContractTranscation(t *testing.T) { blockchain, backend, currentBlock, signer, signFn := PrepareXDCTestBlockChain(t, GAP-1, params.TestXDPoSMockChainConfig) diff --git a/consensus/tests/engine_v2_tests/authorised_masternode_test.go b/consensus/tests/engine_v2_tests/authorised_masternode_test.go index 1fd672bcc7..8f39886ec6 100644 --- a/consensus/tests/engine_v2_tests/authorised_masternode_test.go +++ b/consensus/tests/engine_v2_tests/authorised_masternode_test.go @@ -7,6 +7,7 @@ import ( "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" ) @@ -95,10 +96,11 @@ func TestIsYourTurnConsensusV2CrossConfig(t *testing.T) { currentBlockHeader := currentBlock.Header() currentBlockHeader.Time = big.NewInt(time.Now().Unix()) err := blockchain.InsertBlock(currentBlock) + adaptor.EngineV2.SetNewRoundFaker(blockchain, types.Round(10), false) assert.Nil(t, err) // after first mine period time.Sleep(time.Duration(firstMinePeriod) * time.Second) - isYourTurn, err := adaptor.YourTurn(blockchain, currentBlockHeader, common.HexToAddress("xdc0D3ab14BBaD3D99F4203bd7a11aCB94882050E7e")) + isYourTurn, err := adaptor.YourTurn(blockchain, currentBlockHeader, common.HexToAddress("xdc703c4b2bD70c169f5717101CaeE543299Fc946C7")) assert.Nil(t, err) assert.False(t, isYourTurn) @@ -108,7 +110,7 @@ func TestIsYourTurnConsensusV2CrossConfig(t *testing.T) { secondMinePeriod := blockchain.Config().XDPoS.V2.CurrentConfig.MinePeriod time.Sleep(time.Duration(secondMinePeriod-firstMinePeriod) * time.Second) - isYourTurn, err = adaptor.YourTurn(blockchain, currentBlockHeader, common.HexToAddress("xdc0D3ab14BBaD3D99F4203bd7a11aCB94882050E7e")) + isYourTurn, err = adaptor.YourTurn(blockchain, currentBlockHeader, common.HexToAddress("xdc703c4b2bD70c169f5717101CaeE543299Fc946C7")) assert.Nil(t, err) assert.True(t, isYourTurn) } diff --git a/consensus/tests/engine_v2_tests/mine_test.go b/consensus/tests/engine_v2_tests/mine_test.go index 4ed5bd2c96..ad08fa98b3 100644 --- a/consensus/tests/engine_v2_tests/mine_test.go +++ b/consensus/tests/engine_v2_tests/mine_test.go @@ -223,6 +223,17 @@ func TestPrepareHappyPath(t *testing.T) { assert.Equal(t, types.Round(0), decodedExtraField.QuorumCert.ProposedBlockInfo.Round) } +func TestPrepareDifferentMasternode(t *testing.T) { + config := params.TestXDPoSMockChainConfig + blockchain, _, currentBlock, _, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 1799, config, nil) + adaptor := blockchain.Engine().(*XDPoS.XDPoS) + // trigger initial + adaptor.EngineV2.SetNewRoundFaker(blockchain, types.Round(919), false) + myturn, err := adaptor.YourTurn(blockchain, currentBlock.Header(), acc1Addr) + assert.Nil(t, err) + assert.True(t, myturn) +} + // test if we have 128 candidates, then snapshot will store all of them, and when preparing (and verifying) candidates is truncated to MaxMasternodes func TestUpdateMultipleMasterNodes(t *testing.T) { config := params.TestXDPoSMockChainConfig @@ -279,6 +290,6 @@ func TestUpdateMultipleMasterNodes(t *testing.T) { adaptor.EngineV2.AuthorizeFaker(voterAddr) err = adaptor.Prepare(blockchain, header1800) assert.Nil(t, err) - assert.Equal(t, common.MaxMasternodesV2, len(header1800.Validators)/common.AddressLength) // although 128 masternode candidates, we can only pick MaxMasternodes + assert.Equal(t, blockchain.Config().XDPoS.V2.Config(900).MaxMasternodes, len(header1800.Validators)/common.AddressLength) assert.Equal(t, 0, len(header1800.Penalties)/common.AddressLength) } diff --git a/consensus/tests/engine_v2_tests/verify_header_test.go b/consensus/tests/engine_v2_tests/verify_header_test.go index 1c54bccf96..a1936d44a1 100644 --- a/consensus/tests/engine_v2_tests/verify_header_test.go +++ b/consensus/tests/engine_v2_tests/verify_header_test.go @@ -212,7 +212,7 @@ func TestConfigSwitchOnDifferentCertThreshold(t *testing.T) { } extraInBytes, _ := extra.EncodeToBytes() - // after 910 require 5 signs, but we only give 3 signs + // after 910 require 4 signs, but we only give 3 signs block912 := blockchain.GetBlockByNumber(912).Header() block912.Extra = extraInBytes err = adaptor.VerifyHeader(blockchain, block912, true) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 6bdd345a01..57627d6669 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -767,7 +767,17 @@ func (s *PublicBlockChainAPI) GetCandidateStatus(ctx context.Context, coinbaseAd } var maxMasternodes int - if s.b.ChainConfig().IsTIPIncreaseMasternodes(block.Number()) { + if header.Number.Cmp(s.b.ChainConfig().XDPoS.V2.SwitchBlock) == 1 { + if engine, ok := s.b.GetEngine().(*XDPoS.XDPoS); ok { + round, err := engine.EngineV2.GetRoundNumber(header) + if err != nil { + return result, err + } + maxMasternodes = s.b.ChainConfig().XDPoS.V2.Config(uint64(round)).MaxMasternodes + } else { + return result, fmt.Errorf("undefined XDPoS consensus engine") + } + } else if s.b.ChainConfig().IsTIPIncreaseMasternodes(block.Number()) { maxMasternodes = common.MaxMasternodesV2 } else { maxMasternodes = common.MaxMasternodes @@ -948,7 +958,17 @@ func (s *PublicBlockChainAPI) GetCandidates(ctx context.Context, epoch rpc.Epoch } var maxMasternodes int - if s.b.ChainConfig().IsTIPIncreaseMasternodes(block.Number()) { + if header.Number.Cmp(s.b.ChainConfig().XDPoS.V2.SwitchBlock) == 1 { + if engine, ok := s.b.GetEngine().(*XDPoS.XDPoS); ok { + round, err := engine.EngineV2.GetRoundNumber(header) + if err != nil { + return result, err + } + maxMasternodes = s.b.ChainConfig().XDPoS.V2.Config(uint64(round)).MaxMasternodes + } else { + return result, fmt.Errorf("undefined XDPoS consensus engine") + } + } else if s.b.ChainConfig().IsTIPIncreaseMasternodes(block.Number()) { maxMasternodes = common.MaxMasternodesV2 } else { maxMasternodes = common.MaxMasternodes diff --git a/params/config.go b/params/config.go index 30ca5fd1bc..4411c46766 100644 --- a/params/config.go +++ b/params/config.go @@ -41,26 +41,37 @@ var ( var ( MainnetV2Configs = map[uint64]*V2Config{ Default: { + MaxMasternodes: 108, SwitchRound: 0, CertThreshold: 0.667, TimeoutSyncThreshold: 3, - TimeoutPeriod: 60, + TimeoutPeriod: 20, MinePeriod: 2, }, } TestnetV2Configs = map[uint64]*V2Config{ Default: { + MaxMasternodes: 15, SwitchRound: 0, + CertThreshold: 0.45, + TimeoutSyncThreshold: 3, + TimeoutPeriod: 20, + MinePeriod: 2, + }, + 900000: { + MaxMasternodes: 108, + SwitchRound: 900000, CertThreshold: 0.667, TimeoutSyncThreshold: 3, - TimeoutPeriod: 60, + TimeoutPeriod: 20, MinePeriod: 2, }, } DevnetV2Configs = map[uint64]*V2Config{ Default: { + MaxMasternodes: 108, SwitchRound: 0, CertThreshold: 0.667, TimeoutSyncThreshold: 5, @@ -71,6 +82,7 @@ var ( UnitTestV2Configs = map[uint64]*V2Config{ Default: { + MaxMasternodes: 18, SwitchRound: 0, CertThreshold: 0.667, TimeoutSyncThreshold: 2, @@ -78,15 +90,17 @@ var ( MinePeriod: 2, }, 10: { + MaxMasternodes: 18, SwitchRound: 10, - CertThreshold: 1, + CertThreshold: 0.667, TimeoutSyncThreshold: 2, TimeoutPeriod: 4, MinePeriod: 3, }, - 899: { - SwitchRound: 899, - CertThreshold: 1, + 900: { + MaxMasternodes: 20, + SwitchRound: 900, + CertThreshold: 0.667, TimeoutSyncThreshold: 4, TimeoutPeriod: 5, MinePeriod: 2, @@ -325,6 +339,7 @@ type V2 struct { } type V2Config struct { + MaxMasternodes int `json:"maxMasternodes"` // v2 max masternodes SwitchRound uint64 `json:"switchRound"` // v1 to v2 switch block number MinePeriod int `json:"minePeriod"` // Miner mine period to mine a block TimeoutSyncThreshold int `json:"timeoutSyncThreshold"` // send syncInfo after number of timeout @@ -362,7 +377,7 @@ func (v *V2) UpdateConfig(round uint64) { } func (v *V2) Config(round uint64) *V2Config { - configRound := round - 1 //start from next block from SwitchRound number + configRound := round var index uint64 //find the right config diff --git a/params/config_test.go b/params/config_test.go index 063d1c187f..3b18db4b59 100644 --- a/params/config_test.go +++ b/params/config_test.go @@ -89,9 +89,9 @@ func TestUpdateV2Config(t *testing.T) { TestXDPoSMockChainConfig.XDPoS.V2.UpdateConfig(10) c = TestXDPoSMockChainConfig.XDPoS.V2.CurrentConfig - assert.Equal(t, float64(1), c.CertThreshold) + assert.Equal(t, float64(0.667), c.CertThreshold) - TestXDPoSMockChainConfig.XDPoS.V2.UpdateConfig(899) + TestXDPoSMockChainConfig.XDPoS.V2.UpdateConfig(900) c = TestXDPoSMockChainConfig.XDPoS.V2.CurrentConfig assert.Equal(t, 4, c.TimeoutSyncThreshold) } @@ -108,12 +108,12 @@ func TestV2Config(t *testing.T) { assert.Equal(t, 0.667, c.CertThreshold) c = TestXDPoSMockChainConfig.XDPoS.V2.Config(11) - assert.Equal(t, float64(1), c.CertThreshold) + assert.Equal(t, float64(0.667), c.CertThreshold) } func TestBuildConfigIndex(t *testing.T) { TestXDPoSMockChainConfig.XDPoS.V2.BuildConfigIndex() index := TestXDPoSMockChainConfig.XDPoS.V2.ConfigIndex() - expected := []uint64{899, 10, 0} + expected := []uint64{900, 10, 0} assert.Equal(t, expected, index) }