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