github.com/ava-labs/avalanchego@v1.11.11/vms/platformvm/block/builder/helpers_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 builder 5 6 import ( 7 "context" 8 "testing" 9 "time" 10 11 "github.com/prometheus/client_golang/prometheus" 12 "github.com/stretchr/testify/require" 13 14 "github.com/ava-labs/avalanchego/chains" 15 "github.com/ava-labs/avalanchego/chains/atomic" 16 "github.com/ava-labs/avalanchego/codec" 17 "github.com/ava-labs/avalanchego/codec/linearcodec" 18 "github.com/ava-labs/avalanchego/database/memdb" 19 "github.com/ava-labs/avalanchego/database/prefixdb" 20 "github.com/ava-labs/avalanchego/database/versiondb" 21 "github.com/ava-labs/avalanchego/ids" 22 "github.com/ava-labs/avalanchego/snow" 23 "github.com/ava-labs/avalanchego/snow/engine/common" 24 "github.com/ava-labs/avalanchego/snow/engine/enginetest" 25 "github.com/ava-labs/avalanchego/snow/snowtest" 26 "github.com/ava-labs/avalanchego/snow/uptime" 27 "github.com/ava-labs/avalanchego/snow/validators" 28 "github.com/ava-labs/avalanchego/upgrade/upgradetest" 29 "github.com/ava-labs/avalanchego/utils" 30 "github.com/ava-labs/avalanchego/utils/constants" 31 "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" 32 "github.com/ava-labs/avalanchego/utils/logging" 33 "github.com/ava-labs/avalanchego/utils/timer/mockable" 34 "github.com/ava-labs/avalanchego/utils/units" 35 "github.com/ava-labs/avalanchego/vms/platformvm/config" 36 "github.com/ava-labs/avalanchego/vms/platformvm/fx" 37 "github.com/ava-labs/avalanchego/vms/platformvm/genesis/genesistest" 38 "github.com/ava-labs/avalanchego/vms/platformvm/metrics" 39 "github.com/ava-labs/avalanchego/vms/platformvm/network" 40 "github.com/ava-labs/avalanchego/vms/platformvm/reward" 41 "github.com/ava-labs/avalanchego/vms/platformvm/state" 42 "github.com/ava-labs/avalanchego/vms/platformvm/state/statetest" 43 "github.com/ava-labs/avalanchego/vms/platformvm/status" 44 "github.com/ava-labs/avalanchego/vms/platformvm/txs" 45 "github.com/ava-labs/avalanchego/vms/platformvm/txs/fee" 46 "github.com/ava-labs/avalanchego/vms/platformvm/txs/mempool" 47 "github.com/ava-labs/avalanchego/vms/platformvm/txs/txstest" 48 "github.com/ava-labs/avalanchego/vms/platformvm/utxo" 49 "github.com/ava-labs/avalanchego/vms/secp256k1fx" 50 "github.com/ava-labs/avalanchego/wallet/chain/p/wallet" 51 52 blockexecutor "github.com/ava-labs/avalanchego/vms/platformvm/block/executor" 53 txexecutor "github.com/ava-labs/avalanchego/vms/platformvm/txs/executor" 54 pvalidators "github.com/ava-labs/avalanchego/vms/platformvm/validators" 55 ) 56 57 const ( 58 defaultMinStakingDuration = 24 * time.Hour 59 defaultMaxStakingDuration = 365 * 24 * time.Hour 60 61 defaultTxFee = 100 * units.NanoAvax 62 ) 63 64 var testSubnet1 *txs.Tx 65 66 type mutableSharedMemory struct { 67 atomic.SharedMemory 68 } 69 70 type environment struct { 71 Builder 72 blkManager blockexecutor.Manager 73 mempool mempool.Mempool 74 network *network.Network 75 sender *enginetest.Sender 76 77 isBootstrapped *utils.Atomic[bool] 78 config *config.Config 79 clk *mockable.Clock 80 baseDB *versiondb.Database 81 ctx *snow.Context 82 msm *mutableSharedMemory 83 fx fx.Fx 84 state state.State 85 uptimes uptime.Manager 86 utxosVerifier utxo.Verifier 87 backend txexecutor.Backend 88 } 89 90 func newEnvironment(t *testing.T, f upgradetest.Fork) *environment { //nolint:unparam 91 require := require.New(t) 92 93 res := &environment{ 94 isBootstrapped: &utils.Atomic[bool]{}, 95 config: defaultConfig(f), 96 clk: defaultClock(), 97 } 98 res.isBootstrapped.Set(true) 99 100 res.baseDB = versiondb.New(memdb.New()) 101 atomicDB := prefixdb.New([]byte{1}, res.baseDB) 102 m := atomic.NewMemory(atomicDB) 103 104 res.ctx = snowtest.Context(t, snowtest.PChainID) 105 res.msm = &mutableSharedMemory{ 106 SharedMemory: m.NewSharedMemory(res.ctx.ChainID), 107 } 108 res.ctx.SharedMemory = res.msm 109 110 res.ctx.Lock.Lock() 111 defer res.ctx.Lock.Unlock() 112 113 res.fx = defaultFx(t, res.clk, res.ctx.Log, res.isBootstrapped.Get()) 114 115 rewardsCalc := reward.NewCalculator(res.config.RewardConfig) 116 res.state = statetest.New(t, statetest.Config{ 117 DB: res.baseDB, 118 Genesis: genesistest.NewBytes(t, genesistest.Config{}), 119 Validators: res.config.Validators, 120 Context: res.ctx, 121 Rewards: rewardsCalc, 122 }) 123 124 res.uptimes = uptime.NewManager(res.state, res.clk) 125 res.utxosVerifier = utxo.NewVerifier(res.ctx, res.clk, res.fx) 126 127 genesisID := res.state.GetLastAccepted() 128 res.backend = txexecutor.Backend{ 129 Config: res.config, 130 Ctx: res.ctx, 131 Clk: res.clk, 132 Bootstrapped: res.isBootstrapped, 133 Fx: res.fx, 134 FlowChecker: res.utxosVerifier, 135 Uptimes: res.uptimes, 136 Rewards: rewardsCalc, 137 } 138 139 registerer := prometheus.NewRegistry() 140 res.sender = &enginetest.Sender{T: t} 141 res.sender.SendAppGossipF = func(context.Context, common.SendConfig, []byte) error { 142 return nil 143 } 144 145 metrics, err := metrics.New(registerer) 146 require.NoError(err) 147 148 res.mempool, err = mempool.New("mempool", registerer, nil) 149 require.NoError(err) 150 151 res.blkManager = blockexecutor.NewManager( 152 res.mempool, 153 metrics, 154 res.state, 155 &res.backend, 156 pvalidators.TestManager, 157 ) 158 159 txVerifier := network.NewLockedTxVerifier(&res.ctx.Lock, res.blkManager) 160 res.network, err = network.New( 161 res.backend.Ctx.Log, 162 res.backend.Ctx.NodeID, 163 res.backend.Ctx.SubnetID, 164 res.backend.Ctx.ValidatorState, 165 txVerifier, 166 res.mempool, 167 res.backend.Config.PartialSyncPrimaryNetwork, 168 res.sender, 169 registerer, 170 network.DefaultConfig, 171 ) 172 require.NoError(err) 173 174 res.Builder = New( 175 res.mempool, 176 &res.backend, 177 res.blkManager, 178 ) 179 res.Builder.StartBlockTimer() 180 181 res.blkManager.SetPreference(genesisID) 182 addSubnet(t, res) 183 184 t.Cleanup(func() { 185 res.ctx.Lock.Lock() 186 defer res.ctx.Lock.Unlock() 187 188 res.Builder.ShutdownBlockTimer() 189 190 if res.isBootstrapped.Get() { 191 validatorIDs := res.config.Validators.GetValidatorIDs(constants.PrimaryNetworkID) 192 193 require.NoError(res.uptimes.StopTracking(validatorIDs, constants.PrimaryNetworkID)) 194 195 require.NoError(res.state.Commit()) 196 } 197 198 require.NoError(res.state.Close()) 199 require.NoError(res.baseDB.Close()) 200 }) 201 202 return res 203 } 204 205 type walletConfig struct { 206 keys []*secp256k1.PrivateKey 207 subnetIDs []ids.ID 208 } 209 210 func newWallet(t testing.TB, e *environment, c walletConfig) wallet.Wallet { 211 if len(c.keys) == 0 { 212 c.keys = genesistest.DefaultFundedKeys 213 } 214 return txstest.NewWallet( 215 t, 216 e.ctx, 217 e.config, 218 e.state, 219 secp256k1fx.NewKeychain(c.keys...), 220 c.subnetIDs, 221 []ids.ID{e.ctx.CChainID, e.ctx.XChainID}, 222 ) 223 } 224 225 func addSubnet(t *testing.T, env *environment) { 226 require := require.New(t) 227 228 wallet := newWallet(t, env, walletConfig{ 229 keys: genesistest.DefaultFundedKeys[:1], 230 }) 231 232 var err error 233 testSubnet1, err = wallet.IssueCreateSubnetTx( 234 &secp256k1fx.OutputOwners{ 235 Threshold: 2, 236 Addrs: []ids.ShortID{ 237 genesistest.DefaultFundedKeys[0].Address(), 238 genesistest.DefaultFundedKeys[1].Address(), 239 genesistest.DefaultFundedKeys[2].Address(), 240 }, 241 }, 242 ) 243 require.NoError(err) 244 245 genesisID := env.state.GetLastAccepted() 246 stateDiff, err := state.NewDiff(genesisID, env.blkManager) 247 require.NoError(err) 248 249 feeCalculator := state.PickFeeCalculator(env.config, stateDiff) 250 executor := txexecutor.StandardTxExecutor{ 251 Backend: &env.backend, 252 State: stateDiff, 253 FeeCalculator: feeCalculator, 254 Tx: testSubnet1, 255 } 256 require.NoError(testSubnet1.Unsigned.Visit(&executor)) 257 258 stateDiff.AddTx(testSubnet1, status.Committed) 259 require.NoError(stateDiff.Apply(env.state)) 260 require.NoError(env.state.Commit()) 261 } 262 263 func defaultConfig(f upgradetest.Fork) *config.Config { 264 upgrades := upgradetest.GetConfigWithUpgradeTime(f, time.Time{}) 265 // This package neglects fork ordering 266 upgradetest.SetTimesTo( 267 &upgrades, 268 min(f, upgradetest.ApricotPhase5), 269 genesistest.DefaultValidatorEndTime, 270 ) 271 272 return &config.Config{ 273 Chains: chains.TestManager, 274 UptimeLockedCalculator: uptime.NewLockedCalculator(), 275 Validators: validators.NewManager(), 276 StaticFeeConfig: fee.StaticConfig{ 277 TxFee: defaultTxFee, 278 CreateSubnetTxFee: 100 * defaultTxFee, 279 CreateBlockchainTxFee: 100 * defaultTxFee, 280 }, 281 MinValidatorStake: 5 * units.MilliAvax, 282 MaxValidatorStake: 500 * units.MilliAvax, 283 MinDelegatorStake: 1 * units.MilliAvax, 284 MinStakeDuration: defaultMinStakingDuration, 285 MaxStakeDuration: defaultMaxStakingDuration, 286 RewardConfig: reward.Config{ 287 MaxConsumptionRate: .12 * reward.PercentDenominator, 288 MinConsumptionRate: .10 * reward.PercentDenominator, 289 MintingPeriod: 365 * 24 * time.Hour, 290 SupplyCap: 720 * units.MegaAvax, 291 }, 292 UpgradeConfig: upgrades, 293 } 294 } 295 296 func defaultClock() *mockable.Clock { 297 // set time after Banff fork (and before default nextStakerTime) 298 clk := &mockable.Clock{} 299 clk.Set(genesistest.DefaultValidatorStartTime) 300 return clk 301 } 302 303 type fxVMInt struct { 304 registry codec.Registry 305 clk *mockable.Clock 306 log logging.Logger 307 } 308 309 func (fvi *fxVMInt) CodecRegistry() codec.Registry { 310 return fvi.registry 311 } 312 313 func (fvi *fxVMInt) Clock() *mockable.Clock { 314 return fvi.clk 315 } 316 317 func (fvi *fxVMInt) Logger() logging.Logger { 318 return fvi.log 319 } 320 321 func defaultFx(t *testing.T, clk *mockable.Clock, log logging.Logger, isBootstrapped bool) fx.Fx { 322 require := require.New(t) 323 324 fxVMInt := &fxVMInt{ 325 registry: linearcodec.NewDefault(), 326 clk: clk, 327 log: log, 328 } 329 res := &secp256k1fx.Fx{} 330 require.NoError(res.Initialize(fxVMInt)) 331 if isBootstrapped { 332 require.NoError(res.Bootstrapped()) 333 } 334 return res 335 }