github.com/MetalBlockchain/metalgo@v1.11.9/vms/platformvm/validators/manager_benchmark_test.go (about) 1 // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package validators 5 6 import ( 7 "context" 8 "math/rand" 9 "testing" 10 "time" 11 12 "github.com/prometheus/client_golang/prometheus" 13 "github.com/stretchr/testify/require" 14 15 "github.com/MetalBlockchain/metalgo/database/leveldb" 16 "github.com/MetalBlockchain/metalgo/ids" 17 "github.com/MetalBlockchain/metalgo/snow" 18 "github.com/MetalBlockchain/metalgo/snow/validators" 19 "github.com/MetalBlockchain/metalgo/utils/constants" 20 "github.com/MetalBlockchain/metalgo/utils/crypto/bls" 21 "github.com/MetalBlockchain/metalgo/utils/formatting" 22 "github.com/MetalBlockchain/metalgo/utils/formatting/address" 23 "github.com/MetalBlockchain/metalgo/utils/json" 24 "github.com/MetalBlockchain/metalgo/utils/logging" 25 "github.com/MetalBlockchain/metalgo/utils/timer/mockable" 26 "github.com/MetalBlockchain/metalgo/utils/units" 27 "github.com/MetalBlockchain/metalgo/vms/platformvm/api" 28 "github.com/MetalBlockchain/metalgo/vms/platformvm/block" 29 "github.com/MetalBlockchain/metalgo/vms/platformvm/config" 30 "github.com/MetalBlockchain/metalgo/vms/platformvm/metrics" 31 "github.com/MetalBlockchain/metalgo/vms/platformvm/reward" 32 "github.com/MetalBlockchain/metalgo/vms/platformvm/state" 33 "github.com/MetalBlockchain/metalgo/vms/platformvm/txs" 34 ) 35 36 // BenchmarkGetValidatorSet generates 10k diffs and calculates the time to 37 // generate the genesis validator set by applying them. 38 // 39 // This generates a single diff for each height. In practice there could be 40 // multiple or zero diffs at a given height. 41 // 42 // Note: BenchmarkGetValidatorSet gets the validator set of a subnet rather than 43 // the primary network because the primary network performs caching that would 44 // interfere with the benchmark. 45 func BenchmarkGetValidatorSet(b *testing.B) { 46 require := require.New(b) 47 48 db, err := leveldb.New( 49 b.TempDir(), 50 nil, 51 logging.NoLog{}, 52 prometheus.NewRegistry(), 53 ) 54 require.NoError(err) 55 defer func() { 56 require.NoError(db.Close()) 57 }() 58 59 avaxAssetID := ids.GenerateTestID() 60 genesisTime := time.Now().Truncate(time.Second) 61 genesisEndTime := genesisTime.Add(28 * 24 * time.Hour) 62 63 addr, err := address.FormatBech32(constants.UnitTestHRP, ids.GenerateTestShortID().Bytes()) 64 require.NoError(err) 65 66 genesisValidators := []api.GenesisPermissionlessValidator{{ 67 GenesisValidator: api.GenesisValidator{ 68 StartTime: json.Uint64(genesisTime.Unix()), 69 EndTime: json.Uint64(genesisEndTime.Unix()), 70 NodeID: ids.GenerateTestNodeID(), 71 }, 72 RewardOwner: &api.Owner{ 73 Threshold: 1, 74 Addresses: []string{addr}, 75 }, 76 Staked: []api.UTXO{{ 77 Amount: json.Uint64(2 * units.KiloAvax), 78 Address: addr, 79 }}, 80 DelegationFee: reward.PercentDenominator, 81 }} 82 83 buildGenesisArgs := api.BuildGenesisArgs{ 84 NetworkID: json.Uint32(constants.UnitTestID), 85 AvaxAssetID: avaxAssetID, 86 UTXOs: nil, 87 Validators: genesisValidators, 88 Chains: nil, 89 Time: json.Uint64(genesisTime.Unix()), 90 InitialSupply: json.Uint64(360 * units.MegaAvax), 91 Encoding: formatting.Hex, 92 } 93 94 buildGenesisResponse := api.BuildGenesisReply{} 95 platformvmSS := api.StaticService{} 96 require.NoError(platformvmSS.BuildGenesis(nil, &buildGenesisArgs, &buildGenesisResponse)) 97 98 genesisBytes, err := formatting.Decode(buildGenesisResponse.Encoding, buildGenesisResponse.Bytes) 99 require.NoError(err) 100 101 vdrs := validators.NewManager() 102 103 execConfig, err := config.GetExecutionConfig(nil) 104 require.NoError(err) 105 106 metrics, err := metrics.New(prometheus.NewRegistry()) 107 require.NoError(err) 108 109 s, err := state.New( 110 db, 111 genesisBytes, 112 prometheus.NewRegistry(), 113 &config.Config{ 114 Validators: vdrs, 115 }, 116 execConfig, 117 &snow.Context{ 118 NetworkID: constants.UnitTestID, 119 NodeID: ids.GenerateTestNodeID(), 120 Log: logging.NoLog{}, 121 }, 122 metrics, 123 reward.NewCalculator(reward.Config{ 124 MaxConsumptionRate: .12 * reward.PercentDenominator, 125 MinConsumptionRate: .10 * reward.PercentDenominator, 126 MintingPeriod: 365 * 24 * time.Hour, 127 SupplyCap: 720 * units.MegaAvax, 128 }), 129 ) 130 require.NoError(err) 131 132 m := NewManager( 133 logging.NoLog{}, 134 config.Config{ 135 Validators: vdrs, 136 }, 137 s, 138 metrics, 139 new(mockable.Clock), 140 ) 141 142 var ( 143 nodeIDs []ids.NodeID 144 currentHeight uint64 145 ) 146 for i := 0; i < 50; i++ { 147 currentHeight++ 148 nodeID, err := addPrimaryValidator(s, genesisTime, genesisEndTime, currentHeight) 149 require.NoError(err) 150 nodeIDs = append(nodeIDs, nodeID) 151 } 152 subnetID := ids.GenerateTestID() 153 for _, nodeID := range nodeIDs { 154 currentHeight++ 155 require.NoError(addSubnetValidator(s, subnetID, genesisTime, genesisEndTime, nodeID, currentHeight)) 156 } 157 for i := 0; i < 9900; i++ { 158 currentHeight++ 159 require.NoError(addSubnetDelegator(s, subnetID, genesisTime, genesisEndTime, nodeIDs, currentHeight)) 160 } 161 162 ctx := context.Background() 163 height, err := m.GetCurrentHeight(ctx) 164 require.NoError(err) 165 require.Equal(currentHeight, height) 166 167 b.ResetTimer() 168 169 for i := 0; i < b.N; i++ { 170 _, err := m.GetValidatorSet(ctx, 0, subnetID) 171 require.NoError(err) 172 } 173 174 b.StopTimer() 175 } 176 177 func addPrimaryValidator( 178 s state.State, 179 startTime time.Time, 180 endTime time.Time, 181 height uint64, 182 ) (ids.NodeID, error) { 183 sk, err := bls.NewSecretKey() 184 if err != nil { 185 return ids.EmptyNodeID, err 186 } 187 188 nodeID := ids.GenerateTestNodeID() 189 s.PutCurrentValidator(&state.Staker{ 190 TxID: ids.GenerateTestID(), 191 NodeID: nodeID, 192 PublicKey: bls.PublicFromSecretKey(sk), 193 SubnetID: constants.PrimaryNetworkID, 194 Weight: 2 * units.MegaAvax, 195 StartTime: startTime, 196 EndTime: endTime, 197 PotentialReward: 0, 198 NextTime: endTime, 199 Priority: txs.PrimaryNetworkValidatorCurrentPriority, 200 }) 201 202 blk, err := block.NewBanffStandardBlock(startTime, ids.GenerateTestID(), height, nil) 203 if err != nil { 204 return ids.EmptyNodeID, err 205 } 206 207 s.AddStatelessBlock(blk) 208 s.SetHeight(height) 209 return nodeID, s.Commit() 210 } 211 212 func addSubnetValidator( 213 s state.State, 214 subnetID ids.ID, 215 startTime time.Time, 216 endTime time.Time, 217 nodeID ids.NodeID, 218 height uint64, 219 ) error { 220 s.PutCurrentValidator(&state.Staker{ 221 TxID: ids.GenerateTestID(), 222 NodeID: nodeID, 223 SubnetID: subnetID, 224 Weight: 1 * units.Avax, 225 StartTime: startTime, 226 EndTime: endTime, 227 PotentialReward: 0, 228 NextTime: endTime, 229 Priority: txs.SubnetPermissionlessValidatorCurrentPriority, 230 }) 231 232 blk, err := block.NewBanffStandardBlock(startTime, ids.GenerateTestID(), height, nil) 233 if err != nil { 234 return err 235 } 236 237 s.AddStatelessBlock(blk) 238 s.SetHeight(height) 239 return s.Commit() 240 } 241 242 func addSubnetDelegator( 243 s state.State, 244 subnetID ids.ID, 245 startTime time.Time, 246 endTime time.Time, 247 nodeIDs []ids.NodeID, 248 height uint64, 249 ) error { 250 i := rand.Intn(len(nodeIDs)) //#nosec G404 251 nodeID := nodeIDs[i] 252 s.PutCurrentDelegator(&state.Staker{ 253 TxID: ids.GenerateTestID(), 254 NodeID: nodeID, 255 SubnetID: subnetID, 256 Weight: 1 * units.Avax, 257 StartTime: startTime, 258 EndTime: endTime, 259 PotentialReward: 0, 260 NextTime: endTime, 261 Priority: txs.SubnetPermissionlessDelegatorCurrentPriority, 262 }) 263 264 blk, err := block.NewBanffStandardBlock(startTime, ids.GenerateTestID(), height, nil) 265 if err != nil { 266 return err 267 } 268 269 s.AddStatelessBlock(blk) 270 s.SetLastAccepted(blk.ID()) 271 s.SetHeight(height) 272 return s.Commit() 273 }