diff --git a/cmd/puppeth/wizard_genesis.go b/cmd/puppeth/wizard_genesis.go index 759c3f362552..9637ef0014dd 100644 --- a/cmd/puppeth/wizard_genesis.go +++ b/cmd/puppeth/wizard_genesis.go @@ -94,6 +94,44 @@ func (w *wizard) loadGenesisInput() *GenesisInput { } // makeGenesis creates a new genesis struct based on some user input. +// masternodeRewards are the per-epoch reward figures derived from the staking +// threshold and the target yield, in whole coins. +type masternodeRewards struct { + TotalPerEpoch uint64 // rewards paid out to the whole masternode set each epoch + MasternodeReward float64 // reward of a single masternode (core validator) + ProtectorReward float64 // reward of a single protector, 80% of a masternode + ObserverReward float64 // reward of a single observer, 40% of a masternode +} + +// calcMasternodeRewards derives the per-epoch rewards from the block period, +// the epoch length, the per-masternode staking threshold and the target reward +// yield in APY%. The per-node rewards are grossed up by the foundation cut, so +// that a masternode still earns the requested yield after the foundation has +// taken its percentage. It reports false when the period and epoch length do +// not add up to at least one epoch per year, in which case there is nothing to +// pay out and the caller should leave the reward config untouched. +func calcMasternodeRewards(period, epoch, threshold, yield uint64, masternodes int) (masternodeRewards, bool) { + if period == 0 || epoch == 0 { + return masternodeRewards{}, false + } + blocksPerYear := 31536000 / period + epochsPerYear := blocksPerYear / epoch + if epochsPerYear == 0 { + return masternodeRewards{}, false + } + rewardsPerYear := float64(threshold) * (float64(yield) / 100) + rewardPerEpochPerMNWithoutFoundation := rewardsPerYear / float64(epochsPerYear) + rewardPerEpochPerMN := rewardPerEpochPerMNWithoutFoundation * 100 / float64(100-common.RewardFoundationPercent) + totalRewardPerEpoch := rewardPerEpochPerMN * float64(masternodes) + + return masternodeRewards{ + TotalPerEpoch: uint64(math.Round(totalRewardPerEpoch)), + MasternodeReward: math.Round(rewardPerEpochPerMN*10000) / 10000, + ProtectorReward: math.Round(rewardPerEpochPerMN*0.8*10000) / 10000, + ObserverReward: math.Round(rewardPerEpochPerMN*0.4*10000) / 10000, + }, true +} + func (w *wizard) makeGenesis() { genesis := &core.Genesis{ Timestamp: uint64(time.Now().Unix()), @@ -267,27 +305,24 @@ func (w *wizard) makeGenesis() { } else { yield = uint64(w.readDefaultInt(10)) } - if genesis.Config.XDPoS.Period > 0 && genesis.Config.XDPoS.Epoch > 0 { - blocksPerYear := 31536000 / genesis.Config.XDPoS.Period - epochsPerYear := blocksPerYear / genesis.Config.XDPoS.Epoch - if epochsPerYear > 0 { - rewardsPerYear := float64(threshold) * (float64(yield) / float64(100)) - rewardPerEpochPerMN := uint64(rewardsPerYear / float64(epochsPerYear)) - totalRewardPerEpoch := rewardPerEpochPerMN * uint64(len(signers)) - fmt.Println() - fmt.Println("Calculated Total Masternode rewards per epoch based on yield: ", totalRewardPerEpoch) - genesis.Config.XDPoS.Reward = totalRewardPerEpoch - genesis.Config.XDPoS.V2.CurrentConfig.MasternodeReward = math.Round(float64(rewardPerEpochPerMN)*1000) / 1000 - genesis.Config.XDPoS.V2.CurrentConfig.ProtectorReward = math.Round(float64(rewardPerEpochPerMN)*0.8*1000) / 1000 - genesis.Config.XDPoS.V2.CurrentConfig.ObserverReward = math.Round(float64(rewardPerEpochPerMN)*0.6*1000) / 1000 - - } + if rewards, ok := calcMasternodeRewards(genesis.Config.XDPoS.Period, genesis.Config.XDPoS.Epoch, threshold, yield, len(signers)); ok { + fmt.Println() + fmt.Println("Calculated Total Masternode rewards per epoch based on yield: ", rewards.TotalPerEpoch) + genesis.Config.XDPoS.Reward = rewards.TotalPerEpoch + genesis.Config.XDPoS.V2.CurrentConfig.MasternodeReward = rewards.MasternodeReward + genesis.Config.XDPoS.V2.CurrentConfig.ProtectorReward = rewards.ProtectorReward + genesis.Config.XDPoS.V2.CurrentConfig.ObserverReward = rewards.ObserverReward } fmt.Println() fmt.Println("What is foundation wallet address (collect 10% of all rewards)? (default = xdc0000000000000000000000000000000000000068)") if input == nil { genesis.Config.XDPoS.FoundationWalletAddr = w.readDefaultAddress(common.FoundationAddrBinary) + } else { + if !common.IsHexAddress(input.FoundationWalletAddress) { + log.Crit("Invalid foundation wallet address", "address", input.FoundationWalletAddress) + } + genesis.Config.XDPoS.FoundationWalletAddr = common.HexToAddress(input.FoundationWalletAddress) } // Validator Smart Contract Code diff --git a/cmd/puppeth/wizard_genesis_reward_test.go b/cmd/puppeth/wizard_genesis_reward_test.go new file mode 100644 index 000000000000..509c63144303 --- /dev/null +++ b/cmd/puppeth/wizard_genesis_reward_test.go @@ -0,0 +1,149 @@ +package main + +import ( + "flag" + "fmt" + "math" + "testing" + + "github.com/XinFinOrg/XDPoSChain/common" +) + +// Flags for TestCalcMasternodeRewardsManual, so the reward numbers for a +// candidate network can be eyeballed without editing the test. Note that +// -v is required: go test discards the output of a passing package without it. +// +// go test ./cmd/puppeth -run TestCalcMasternodeRewardsManual -v \ +// -period=2 -epoch=900 -threshold=10_000_000 -yield=10 -signers=3 +var ( + flagPeriod = flag.Uint64("period", 2, "block period in seconds (manual reward calc)") + flagEpoch = flag.Uint64("epoch", 900, "blocks per epoch (manual reward calc)") + flagThreshold = flag.Uint64("threshold", 10_000_000, "per-masternode staking threshold in whole coins (manual reward calc)") + flagYield = flag.Uint64("yield", 10, "target masternode yield in APY% (manual reward calc)") + flagSigners = flag.Int("signers", 3, "number of initial masternodes (manual reward calc)") +) + +// TestCalcMasternodeRewardsManual prints the reward figures puppeth would bake +// into the genesis config for the flag values above, as a manual check. It +// asserts nothing beyond the calculation being possible at all; the assertions +// live in TestCalcMasternodeRewards. +func TestCalcMasternodeRewardsManual(t *testing.T) { + rewards, ok := calcMasternodeRewards(*flagPeriod, *flagEpoch, *flagThreshold, *flagYield, *flagSigners) + if !ok { + t.Fatalf("period=%d epoch=%d yields less than one epoch per year, no rewards calculated", *flagPeriod, *flagEpoch) + } + epochsPerYear := (31536000 / *flagPeriod) / *flagEpoch + netOfFoundation := float64(100-common.RewardFoundationPercent) / 100 + + fmt.Printf("period=%ds epoch=%d blocks threshold=%d yield=%d%% masternodes=%d (%d epochs/year)", + *flagPeriod, *flagEpoch, *flagThreshold, *flagYield, *flagSigners, epochsPerYear) + fmt.Printf(" reward (total per epoch) = %d\n", rewards.TotalPerEpoch) + fmt.Printf(" masternodeReward = %v\n", rewards.MasternodeReward) + fmt.Printf(" protectorReward = %v\n", rewards.ProtectorReward) + fmt.Printf(" observerReward = %v\n", rewards.ObserverReward) + fmt.Printf(" effective yield per masternode = %.4f%% (net of the %d%% foundation cut)", + rewards.MasternodeReward*netOfFoundation*float64(epochsPerYear)/float64(*flagThreshold)*100, common.RewardFoundationPercent) +} + +// TestCalcMasternodeRewards asserts the reward numbers for a set of fixed +// period/epoch/threshold/yield combinations. Run with -v to see the figures. +func TestCalcMasternodeRewards(t *testing.T) { + tests := []struct { + name string + period uint64 + epoch uint64 + threshold uint64 + yield uint64 + signers int + wantOK bool + wantTotal uint64 + wantMN float64 + wantProt float64 + wantObs float64 + }{ + { + name: "mainnet-like defaults, 3 masternodes", + period: 2, epoch: 900, threshold: 10000000, yield: 10, signers: 3, + wantOK: true, + wantTotal: 190, wantMN: 63.4196, wantProt: 50.7357, wantObs: 25.3678, + }, + { + name: "mainnet-like defaults, full 108 masternode set", + period: 2, epoch: 900, threshold: 10000000, yield: 10, signers: 108, + wantOK: true, + wantTotal: 6849, wantMN: 63.4196, wantProt: 50.7357, wantObs: 25.3678, + }, + { + name: "double threshold at half yield pays the same per node", + period: 2, epoch: 900, threshold: 20000000, yield: 5, signers: 5, + wantOK: true, + wantTotal: 317, wantMN: 63.4196, wantProt: 50.7357, wantObs: 25.3678, + }, + { + name: "15s period, fewer epochs per year, bigger per-epoch reward", + period: 15, epoch: 900, threshold: 10000000, yield: 10, signers: 3, + wantOK: true, + wantTotal: 1427, wantMN: 475.6469, wantProt: 380.5175, wantObs: 190.2588, + }, + { + name: "zero yield pays nothing", + period: 2, epoch: 900, threshold: 10000000, yield: 0, signers: 3, + wantOK: true, + }, + { + name: "zero period is rejected", + period: 0, epoch: 900, threshold: 10000000, yield: 10, signers: 3, + }, + { + name: "zero epoch is rejected", + period: 2, epoch: 0, threshold: 10000000, yield: 10, signers: 3, + }, + { + name: "epoch longer than a year is rejected", + period: 2, epoch: 20000000, threshold: 10000000, yield: 10, signers: 3, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + rewards, ok := calcMasternodeRewards(tt.period, tt.epoch, tt.threshold, tt.yield, tt.signers) + if ok != tt.wantOK { + t.Fatalf("ok = %v, want %v", ok, tt.wantOK) + } + if !ok { + fmt.Printf("period=%ds epoch=%d -> rejected, reward config left untouched", tt.period, tt.epoch) + if rewards != (masternodeRewards{}) { + t.Fatalf("rewards = %+v, want zero value when not ok", rewards) + } + return + } + fmt.Printf("period=%ds epoch=%d threshold=%d yield=%d%% masternodes=%d -> total=%d mn=%v prot=%v obs=%v", + tt.period, tt.epoch, tt.threshold, tt.yield, tt.signers, + rewards.TotalPerEpoch, rewards.MasternodeReward, rewards.ProtectorReward, rewards.ObserverReward) + + if rewards.TotalPerEpoch != tt.wantTotal { + t.Errorf("TotalPerEpoch = %d, want %d", rewards.TotalPerEpoch, tt.wantTotal) + } + if rewards.MasternodeReward != tt.wantMN { + t.Errorf("MasternodeReward = %v, want %v", rewards.MasternodeReward, tt.wantMN) + } + if rewards.ProtectorReward != tt.wantProt { + t.Errorf("ProtectorReward = %v, want %v", rewards.ProtectorReward, tt.wantProt) + } + if rewards.ObserverReward != tt.wantObs { + t.Errorf("ObserverReward = %v, want %v", rewards.ObserverReward, tt.wantObs) + } + if tt.yield == 0 { + return + } + // The requested yield must survive the foundation cut: a masternode + // earning MasternodeReward each epoch, minus the foundation share, + // should end the year on `yield`% of its stake. + epochsPerYear := float64((31536000 / tt.period) / tt.epoch) + netOfFoundation := float64(100-common.RewardFoundationPercent) / 100 + gotYield := rewards.MasternodeReward * netOfFoundation * epochsPerYear / float64(tt.threshold) * 100 + if math.Abs(gotYield-float64(tt.yield)) > 0.001 { + t.Errorf("effective yield = %.4f%%, want %d%%", gotYield, tt.yield) + } + }) + } +} diff --git a/consensus/XDPoS/engines/engine_v2/engine.go b/consensus/XDPoS/engines/engine_v2/engine.go index 331071a1569b..c4c86684b989 100644 --- a/consensus/XDPoS/engines/engine_v2/engine.go +++ b/consensus/XDPoS/engines/engine_v2/engine.go @@ -697,11 +697,17 @@ func (x *XDPoS_v2) VerifySyncInfoMessage(chain consensus.ChainReader, syncInfo * log.Warn("[VerifySyncInfoMessage] SyncInfo message verification failed due to QC", "blockNum", syncInfo.HighestQuorumCert.ProposedBlockInfo.Number, "round", syncInfo.HighestQuorumCert.ProposedBlockInfo.Round, "error", err) return false, err } - err = x.verifyTC(chain, syncInfo.HighestTimeoutCert) - if err != nil { - log.Warn("[VerifySyncInfoMessage] SyncInfo message verification failed due to TC", "gapNum", syncInfo.HighestTimeoutCert.GapNumber, "round", syncInfo.HighestTimeoutCert.Round, "error", err) - return false, err + + if !isBlankTC(syncInfo.HighestTimeoutCert) { + err = x.verifyTC(chain, syncInfo.HighestTimeoutCert) + if err != nil { + log.Warn("[VerifySyncInfoMessage] SyncInfo message verification failed due to TC", "gapNum", syncInfo.HighestTimeoutCert.GapNumber, "round", syncInfo.HighestTimeoutCert.Round, "error", err) + return false, err + } + } else { + log.Debug("[VerifySyncInfoMessage] Detected blank TC, sender has no TC yet (fresh restart or new chain), skipping TC verification", "qcRound", syncInfo.HighestQuorumCert.ProposedBlockInfo.Round, "qcNumber", syncInfo.HighestQuorumCert.ProposedBlockInfo.Number, "qcHash", syncInfo.HighestQuorumCert.ProposedBlockInfo.Hash) } + return true, nil } diff --git a/consensus/XDPoS/engines/engine_v2/timeout.go b/consensus/XDPoS/engines/engine_v2/timeout.go index 2e4a6debf91f..e4ec6102b17b 100644 --- a/consensus/XDPoS/engines/engine_v2/timeout.go +++ b/consensus/XDPoS/engines/engine_v2/timeout.go @@ -146,6 +146,15 @@ func (x *XDPoS_v2) getTCEpochInfo(chain consensus.ChainReader, timeoutRound type } return epochInfo, nil } + +// Round 0 with no signatures is the bootstrap TC installed by New(), not a real +// certificate: a TC only comes into existence once a round has timed out. +// Since TC lives in memory, when a node restarts, it's initialized as a blank. +// Rejecting the blank would discard the whole syncInfo which could contain useful QC. +func isBlankTC(timeoutCert *types.TimeoutCert) bool { + return timeoutCert != nil && timeoutCert.Round == types.Round(0) && len(timeoutCert.Signatures) == 0 +} + func (x *XDPoS_v2) verifyTC(chain consensus.ChainReader, timeoutCert *types.TimeoutCert) error { /* 1. Get epoch master node list by gapNumber diff --git a/consensus/tests/engine_v2_tests/sync_info_test.go b/consensus/tests/engine_v2_tests/sync_info_test.go index 5c17168d8acf..ccaf3d2c48ae 100644 --- a/consensus/tests/engine_v2_tests/sync_info_test.go +++ b/consensus/tests/engine_v2_tests/sync_info_test.go @@ -103,6 +103,87 @@ func TestSkipVerifySyncInfoIfBothQcTcNotQualified(t *testing.T) { assert.Nil(t, err) } +// A node that has never formed a TC holds the bootstrap TC (round 0, no signatures) and +// puts it into every syncInfo it sends. The QC in such a message is the only way for a +// node that missed a QC to catch up, so the placeholder TC must not invalidate it. +func TestVerifySyncInfoWithNewerQCAndBootstrapTC(t *testing.T) { + blockchain, _, currentBlock, _, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 905, params.TestXDPoSMockChainConfig, nil) + engineV2 := blockchain.Engine().(*XDPoS.XDPoS).EngineV2 + + // The incoming syncInfo carries the newer QC, taken from the chain head. + var incoming types.ExtraFields_v2 + if err := utils.DecodeBytesExtraFields(currentBlock.Extra(), &incoming); err != nil { + t.Fatal("Fail to decode extra data", err) + } + + // Our node sits on an older QC and has never seen a TC, exactly like a node whose + // votes fell short of the threshold at network start. + var older types.ExtraFields_v2 + if err := utils.DecodeBytesExtraFields(blockchain.GetBlockByNumber(903).Extra(), &older); err != nil { + t.Fatal("Fail to decode extra data", err) + } + bootstrapTC := &types.TimeoutCert{ + Round: types.Round(0), + Signatures: []types.Signature{}, + } + engineV2.SetPropertiesFaker(older.QuorumCert, bootstrapTC) + + syncInfoMsg := &types.SyncInfo{ + HighestQuorumCert: incoming.QuorumCert, + HighestTimeoutCert: bootstrapTC, + } + + verified, err := engineV2.VerifySyncInfoMessage(blockchain, syncInfoMsg) + assert.Nil(t, err, "the bootstrap TC must not invalidate a syncInfo whose QC is newer and valid") + assert.True(t, verified) +} + +// The exemption is deliberately narrow: it covers only the empty placeholder, and any TC +// that actually carries signatures is still put through verifyTC in full. This pins that +// boundary, so the exemption cannot be widened by sending a TC with a bogus signature set. +// +// The trade-off it also documents: a TC that would never be processed anyway - here one +// staler than the one we hold - still invalidates the whole message, discarding a QC we do +// need. Verifying only the certificate that is ahead of ours would avoid that, at the cost +// of a broader change to the syncInfo path. +func TestVerifySyncInfoStillVerifiesNonEmptyTC(t *testing.T) { + blockchain, _, currentBlock, _, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 905, params.TestXDPoSMockChainConfig, nil) + engineV2 := blockchain.Engine().(*XDPoS.XDPoS).EngineV2 + + var incoming types.ExtraFields_v2 + if err := utils.DecodeBytesExtraFields(currentBlock.Extra(), &incoming); err != nil { + t.Fatal("Fail to decode extra data", err) + } + var older types.ExtraFields_v2 + if err := utils.DecodeBytesExtraFields(blockchain.GetBlockByNumber(903).Extra(), &older); err != nil { + t.Fatal("Fail to decode extra data", err) + } + + // We already hold a newer TC than the one being sent to us. + ourTC := &types.TimeoutCert{ + Round: types.Round(5), + Signatures: []types.Signature{}, + } + engineV2.SetPropertiesFaker(older.QuorumCert, ourTC) + + // Their TC carries a signature, so it is not the placeholder and gets verified: round 1 + // with gap number 0, which has no snapshot here, so verification fails. + staleTC := &types.TimeoutCert{ + Round: types.Round(1), + Signatures: []types.Signature{SignHashByPK(acc1Key, types.TimeoutSigHash(&types.TimeoutForSign{Round: types.Round(1), GapNumber: 0}).Bytes())}, + GapNumber: 0, + } + + syncInfoMsg := &types.SyncInfo{ + HighestQuorumCert: incoming.QuorumCert, + HighestTimeoutCert: staleTC, + } + + verified, err := engineV2.VerifySyncInfoMessage(blockchain, syncInfoMsg) + assert.NotNil(t, err, "a TC carrying signatures must still be verified, not exempted") + assert.False(t, verified) +} + func TestVerifySyncInfoIfTCRoundIsAtNextEpoch(t *testing.T) { blockchain, _, _, _, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 905, params.TestXDPoSMockChainConfig, nil) engineV2 := blockchain.Engine().(*XDPoS.XDPoS).EngineV2 diff --git a/core/genesis_setup_test.go b/core/genesis_setup_test.go index 0bec6e73bf81..3a20fd7b1735 100644 --- a/core/genesis_setup_test.go +++ b/core/genesis_setup_test.go @@ -34,6 +34,10 @@ func TestSetupGenesisNormalizesLocalnetChainConfig(t *testing.T) { TIPXDCXReceiverDisableBlock: big.NewInt(12), EIP1559Block: big.NewInt(12), CancunBlock: big.NewInt(34), + PragueBlock: big.NewInt(34), + DynamicGasLimitBlock: big.NewInt(34), + TIPUpgradeRewardBlock: big.NewInt(34), + TIPUpgradePenaltyBlock: big.NewInt(34), TRC21IssuerSMC: params.LocalnetChainConfig.TRC21IssuerSMC, XDCXListingSMC: params.LocalnetChainConfig.XDCXListingSMC, RelayerRegistrationSMC: params.LocalnetChainConfig.RelayerRegistrationSMC, @@ -73,8 +77,11 @@ func TestSetupGenesisNormalizesLocalnetChainConfig(t *testing.T) { if cfg.Ethash == nil { t.Fatal("expected non-whitelisted fields to be preserved") } - if cfg.PragueBlock != nil || cfg.DynamicGasLimitBlock != nil || cfg.TIPUpgradeRewardBlock != nil { - t.Fatalf("unexpected localnet whitelist fields: Prague=%v DynamicGasLimit=%v TIPUpgradeReward=%v", cfg.PragueBlock, cfg.DynamicGasLimitBlock, cfg.TIPUpgradeRewardBlock) + if cfg.PragueBlock == nil || cfg.PragueBlock.Cmp(big.NewInt(34)) != 0 { + t.Fatalf("unexpected preserved Prague block: have %v want 34", cfg.PragueBlock) + } + if cfg.OsakaBlock != nil || cfg.TIPEpochHalvingBlock != nil { + t.Fatalf("unexpected localnet whitelist fields: Osaka=%v TIPEpochHalving=%v", cfg.OsakaBlock, cfg.TIPEpochHalvingBlock) } if cfg.LondonBlock == nil || cfg.LondonBlock.Cmp(big.NewInt(12)) != 0 { t.Fatalf("unexpected localnet London block: have %v want 12", cfg.LondonBlock) diff --git a/params/config_networks.go b/params/config_networks.go index cbb97f217ab5..0a0537acbcbc 100644 --- a/params/config_networks.go +++ b/params/config_networks.go @@ -200,7 +200,7 @@ var ( LocalnetV2Configs = map[uint64]*V2Config{ defaultV2SwitchRound: { MaxMasternodes: 108, - MaxProtectorNodes: 324, + MaxProtectorNodes: 432, MaxObserverNodes: 2000, SwitchRound: 0, CertThreshold: 0.667, @@ -512,27 +512,23 @@ var ( MergeBlock: big.NewInt(0), ShanghaiBlock: big.NewInt(0), Gas50xBlock: big.NewInt(0), - Gas2500xBlock: big.NewInt(0), + Gas2500xBlock: nil, TIPXDCXMinerDisableBlock: big.NewInt(0), TIPXDCXReceiverDisableBlock: big.NewInt(0), EIP1559Block: big.NewInt(0), CancunBlock: big.NewInt(0), - PragueBlock: nil, - // PragueBlock: big.NewInt(0), - OsakaBlock: nil, - DynamicGasLimitBlock: nil, - // DynamicGasLimitBlock: big.NewInt(0), - TIPUpgradeRewardBlock: nil, - // TIPUpgradeRewardBlock: big.NewInt(0), - TIPUpgradePenaltyBlock: nil, - // TIPUpgradePenaltyBlock: big.NewInt(0), - TIPEpochHalvingBlock: nil, - TRC21IssuerSMC: common.HexToAddress("0x8c0faeb5C6bEd2129b8674F262Fd45c4e9468bee"), - XDCXListingSMC: common.HexToAddress("0xDE34dD0f536170993E8CFF639DdFfCF1A85D3E53"), - RelayerRegistrationSMC: common.HexToAddress("0x16c63b79f9C8784168103C0b74E6A59EC2de4a02"), - LendingRegistrationSMC: common.HexToAddress("0x7d761afd7ff65a79e4173897594a194e3c506e57"), - Clique: nil, - Ethash: nil, + PragueBlock: big.NewInt(0), + OsakaBlock: nil, + DynamicGasLimitBlock: big.NewInt(0), + TIPUpgradeRewardBlock: big.NewInt(0), + TIPUpgradePenaltyBlock: big.NewInt(0), + TIPEpochHalvingBlock: nil, + TRC21IssuerSMC: common.HexToAddress("0x8c0faeb5C6bEd2129b8674F262Fd45c4e9468bee"), + XDCXListingSMC: common.HexToAddress("0xDE34dD0f536170993E8CFF639DdFfCF1A85D3E53"), + RelayerRegistrationSMC: common.HexToAddress("0x16c63b79f9C8784168103C0b74E6A59EC2de4a02"), + LendingRegistrationSMC: common.HexToAddress("0x7d761afd7ff65a79e4173897594a194e3c506e57"), + Clique: nil, + Ethash: nil, XDPoS: &XDPoSConfig{ Period: 2, Epoch: 900, @@ -739,15 +735,15 @@ var ( MergeBlock: big.NewInt(0), ShanghaiBlock: big.NewInt(0), Gas50xBlock: big.NewInt(0), - TIPXDCXMinerDisableBlock: nil, - TIPXDCXReceiverDisableBlock: nil, + TIPXDCXMinerDisableBlock: big.NewInt(0), + TIPXDCXReceiverDisableBlock: big.NewInt(0), EIP1559Block: big.NewInt(0), CancunBlock: big.NewInt(0), PragueBlock: big.NewInt(0), - OsakaBlock: big.NewInt(0), - DynamicGasLimitBlock: nil, - TIPUpgradeRewardBlock: nil, - TIPUpgradePenaltyBlock: nil, + OsakaBlock: nil, + DynamicGasLimitBlock: big.NewInt(0), + TIPUpgradeRewardBlock: big.NewInt(0), + TIPUpgradePenaltyBlock: big.NewInt(0), TIPEpochHalvingBlock: nil, TRC21IssuerSMC: common.HexToAddress("0x8c0faeb5C6bEd2129b8674F262Fd45c4e9468bee"), XDCXListingSMC: common.HexToAddress("0xDE34dD0f536170993E8CFF639DdFfCF1A85D3E53"), diff --git a/params/config_networks_test.go b/params/config_networks_test.go index c8df0f4e71f6..f51cfc5058af 100644 --- a/params/config_networks_test.go +++ b/params/config_networks_test.go @@ -79,7 +79,11 @@ func TestXDPoSMockChainConfigDeclaresModernForks(t *testing.T) { assertBlock("EIP1559Block", config.EIP1559Block) assertBlock("CancunBlock", config.CancunBlock) assertBlock("PragueBlock", config.PragueBlock) - assertBlock("OsakaBlock", config.OsakaBlock) + assertBlock("DynamicGasLimitBlock", config.DynamicGasLimitBlock) + assertBlock("TIPUpgradeRewardBlock", config.TIPUpgradeRewardBlock) + assertBlock("TIPUpgradePenaltyBlock", config.TIPUpgradePenaltyBlock) + // assertBlock("OsakaBlock", config.OsakaBlock) + assert.Nil(t, config.OsakaBlock, "OsakaBlock must stay unscheduled on TestXDPoSMockChainConfig") } func TestXDCChainConfigsDeclareForkBlocks(t *testing.T) { @@ -216,11 +220,11 @@ func TestXDCChainConfigsDeclareForkBlocks(t *testing.T) { tipXDCXReceiverDisable: big.NewInt(0), eip1559Block: big.NewInt(0), cancunBlock: big.NewInt(0), - pragueBlock: nil, + pragueBlock: big.NewInt(0), osakaBlock: nil, - dynamicGasLimitBlock: nil, - tipUpgradeRewardBlock: nil, - tipUpgradePenaltyBlock: nil, + dynamicGasLimitBlock: big.NewInt(0), + tipUpgradeRewardBlock: big.NewInt(0), + tipUpgradePenaltyBlock: big.NewInt(0), tipEpochHalvingBlock: nil, }, }