diff --git a/tests/e2e/p/permissionless_subnets.go b/tests/e2e/p/permissionless_subnets.go index 4e91569e9256..ba9c46b2903f 100644 --- a/tests/e2e/p/permissionless_subnets.go +++ b/tests/e2e/p/permissionless_subnets.go @@ -63,9 +63,9 @@ var _ = e2e.DescribePChain("[Permissionless Subnets]", func() { owner, e2e.WithDefaultContext(), ) - - subnetID = subnetTx.ID() require.NoError(err) + subnetID = subnetTx.ID() + require.NotEqual(subnetID, constants.PrimaryNetworkID) }) diff --git a/tests/e2e/p/staking_rewards.go b/tests/e2e/p/staking_rewards.go index 7e8178c53a32..05b387f56e5e 100644 --- a/tests/e2e/p/staking_rewards.go +++ b/tests/e2e/p/staking_rewards.go @@ -240,6 +240,17 @@ var _ = ginkgo.Describe("[Staking Rewards]", func() { delegatorData := data[0].Delegators[0] actualGammaDelegationPeriod := time.Duration(delegatorData.EndTime-delegatorData.StartTime) * time.Second + preRewardBalances := make(map[ids.ShortID]uint64, len(rewardKeys)) + for _, rewardKey := range rewardKeys { + keychain := secp256k1fx.NewKeychain(rewardKey) + baseWallet := e2e.NewWallet(keychain, nodeURI) + pWallet := baseWallet.P() + balances, err := pWallet.Builder().GetBalance() + require.NoError(err) + preRewardBalances[rewardKey.Address()] = balances[pWallet.Builder().Context().AVAXAssetID] + } + require.Len(preRewardBalances, len(rewardKeys)) + ginkgo.By("waiting until all validation periods are over") // The beta validator was the last added and so has the latest end time. The // delegation periods are shorter than the validation periods. @@ -293,12 +304,12 @@ var _ = ginkgo.Describe("[Staking Rewards]", func() { ginkgo.By("checking expected rewards against actual rewards") expectedRewardBalances := map[ids.ShortID]uint64{ - alphaValidationRewardKey.Address(): expectedValidationReward, - alphaDelegationRewardKey.Address(): expectedDelegationFee, - betaValidationRewardKey.Address(): 0, // Validator didn't meet uptime requirement - betaDelegationRewardKey.Address(): 0, // Validator didn't meet uptime requirement - gammaDelegationRewardKey.Address(): expectedDelegatorReward, - deltaDelegationRewardKey.Address(): 0, // Validator didn't meet uptime requirement + alphaValidationRewardKey.Address(): preRewardBalances[alphaValidationRewardKey.Address()] + expectedValidationReward, + alphaDelegationRewardKey.Address(): preRewardBalances[alphaDelegationRewardKey.Address()] + expectedDelegationFee, + betaValidationRewardKey.Address(): preRewardBalances[betaValidationRewardKey.Address()] + 0, // Validator didn't meet uptime requirement + betaDelegationRewardKey.Address(): preRewardBalances[betaDelegationRewardKey.Address()] + 0, // Validator didn't meet uptime requirement + gammaDelegationRewardKey.Address(): preRewardBalances[gammaDelegationRewardKey.Address()] + expectedDelegatorReward, + deltaDelegationRewardKey.Address(): preRewardBalances[deltaDelegationRewardKey.Address()] + 0, // Validator didn't meet uptime requirement } for address := range expectedRewardBalances { require.Equal(expectedRewardBalances[address], rewardBalances[address]) diff --git a/tests/e2e/p/workflow.go b/tests/e2e/p/workflow.go index c4e597d27263..6ab1816fcc03 100644 --- a/tests/e2e/p/workflow.go +++ b/tests/e2e/p/workflow.go @@ -22,8 +22,10 @@ import ( "github.com/ava-labs/avalanchego/vms/platformvm" "github.com/ava-labs/avalanchego/vms/platformvm/signer" "github.com/ava-labs/avalanchego/vms/platformvm/txs" + "github.com/ava-labs/avalanchego/vms/platformvm/txs/fee" "github.com/ava-labs/avalanchego/vms/secp256k1fx" + commonfee "github.com/ava-labs/avalanchego/vms/components/fee" ginkgo "github.com/onsi/ginkgo/v2" ) @@ -57,25 +59,24 @@ var _ = e2e.DescribePChain("[Workflow]", func() { tests.Outf("{{green}} minimal validator stake: %d {{/}}\n", minValStake) tests.Outf("{{green}} minimal delegator stake: %d {{/}}\n", minDelStake) - tests.Outf("{{blue}} fetching tx fee {{/}}\n") + tests.Outf("{{blue}} fetching minimal stake amounts {{/}}\n") + feeCfg, err := pChainClient.GetDynamicFeeConfig(e2e.DefaultContext()) + require.NoError(err) + tests.Outf("{{green}} fee config: %v {{/}}\n", feeCfg) + + tests.Outf("{{blue}} fetching X-chain tx fee {{/}}\n") infoClient := info.NewClient(nodeURI.URI) - fees, err := infoClient.GetTxFee(e2e.DefaultContext()) + staticFees, err := infoClient.GetTxFee(e2e.DefaultContext()) require.NoError(err) - txFees := uint64(fees.TxFee) - tests.Outf("{{green}} txFee: %d {{/}}\n", txFees) + + xChainTxFees := uint64(staticFees.TxFee) + tests.Outf("{{green}} X-chain TxFee: %d {{/}}\n", xChainTxFees) // amount to transfer from P to X chain toTransfer := 1 * units.Avax pShortAddr := keychain.Keys[0].Address() xTargetAddr := keychain.Keys[1].Address() - ginkgo.By("check selected keys have sufficient funds", func() { - pBalances, err := pWallet.Builder().GetBalance() - pBalance := pBalances[avaxAssetID] - minBalance := minValStake + txFees + minDelStake + txFees + toTransfer + txFees - require.NoError(err) - require.GreaterOrEqual(pBalance, minBalance) - }) // Use a random node ID to ensure that repeated test runs // will succeed against a network that persists across runs. @@ -145,8 +146,12 @@ var _ = e2e.DescribePChain("[Workflow]", func() { OutputOwners: outputOwner, } + pChainExportFee := uint64(0) ginkgo.By("export avax from P to X chain", func() { - _, err := pWallet.IssueExportTx( + nextGasPrice, nextGasCap, err := pChainClient.GetNextGasData(e2e.DefaultContext()) + require.NoError(err) + + tx, err := pWallet.IssueExportTx( xContext.BlockchainID, []*avax.TransferableOutput{ { @@ -159,6 +164,11 @@ var _ = e2e.DescribePChain("[Workflow]", func() { e2e.WithDefaultContext(), ) require.NoError(err) + + // retrieve fees paid for the tx + feeCalc := fee.NewDynamicCalculator(commonfee.NewCalculator(feeCfg.FeeDimensionWeights, nextGasPrice, nextGasCap)) + pChainExportFee, err = feeCalc.CalculateFee(tx) + require.NoError(err) }) // check balances post export @@ -173,7 +183,7 @@ var _ = e2e.DescribePChain("[Workflow]", func() { tests.Outf("{{blue}} X-chain balance after P->X export: %d {{/}}\n", xPreImportBalance) require.Equal(xPreImportBalance, xStartBalance) // import not performed yet - require.Equal(pPreImportBalance, pStartBalance-toTransfer-txFees) + require.Equal(pPreImportBalance, pStartBalance-toTransfer-pChainExportFee) ginkgo.By("import avax from P into X chain", func() { _, err := xWallet.IssueImportTx( @@ -195,7 +205,7 @@ var _ = e2e.DescribePChain("[Workflow]", func() { xFinalBalance := xBalances[avaxAssetID] tests.Outf("{{blue}} X-chain balance after P->X import: %d {{/}}\n", xFinalBalance) - require.Equal(xFinalBalance, xPreImportBalance+toTransfer-txFees) // import not performed yet + require.Equal(xFinalBalance, xPreImportBalance+toTransfer-xChainTxFees) // import not performed yet require.Equal(pFinalBalance, pPreImportBalance) }) }) diff --git a/vms/platformvm/block/builder/builder.go b/vms/platformvm/block/builder/builder.go index 28fb4958bb57..0fd6810f0320 100644 --- a/vms/platformvm/block/builder/builder.go +++ b/vms/platformvm/block/builder/builder.go @@ -331,7 +331,7 @@ func packBlockTxs( return nil, err } - feeCalculator, err := state.PickFeeCalculator(backend.Config, stateDiff) + feeCalculator, err := state.PickFeeCalculator(backend.Config, stateDiff, parentState.GetTimestamp()) if err != nil { return nil, err } diff --git a/vms/platformvm/block/builder/helpers_test.go b/vms/platformvm/block/builder/helpers_test.go index c9c744dffec8..3b126b8748a0 100644 --- a/vms/platformvm/block/builder/helpers_test.go +++ b/vms/platformvm/block/builder/helpers_test.go @@ -262,7 +262,7 @@ func addSubnet(t *testing.T, env *environment) { stateDiff, err := state.NewDiff(genesisID, env.blkManager) require.NoError(err) - feeCalculator, err := state.PickFeeCalculator(env.config, stateDiff) + feeCalculator, err := state.PickFeeCalculator(env.config, stateDiff, stateDiff.GetTimestamp()) require.NoError(err) executor := txexecutor.StandardTxExecutor{ diff --git a/vms/platformvm/block/executor/acceptor.go b/vms/platformvm/block/executor/acceptor.go index cc2bcef0521f..a3bc81fa6d95 100644 --- a/vms/platformvm/block/executor/acceptor.go +++ b/vms/platformvm/block/executor/acceptor.go @@ -79,6 +79,8 @@ func (a *acceptor) ApricotAtomicBlock(b *block.ApricotAtomicBlock) error { return fmt.Errorf("%w %s", errMissingBlockState, blkID) } + a.metrics.SetBlockGas(blkState.blockGas) + // Update the state to reflect the changes made in [onAcceptState]. if err := blkState.onAcceptState.Apply(a.state); err != nil { return err @@ -136,6 +138,8 @@ func (a *acceptor) optionBlock(b block.Block, blockType string) error { return err } + a.metrics.SetBlockGas(parentState.blockGas) + if err := a.commonAccept(b); err != nil { return err } @@ -150,6 +154,10 @@ func (a *acceptor) optionBlock(b block.Block, blockType string) error { if !ok { return fmt.Errorf("%w %s", errMissingBlockState, blkID) } + + // we set option complexity at its parent block's one. + a.metrics.SetBlockGas(parentState.blockGas) + if err := blkState.onAcceptState.Apply(a.state); err != nil { return err } @@ -228,6 +236,8 @@ func (a *acceptor) standardBlock(b block.Block, blockType string) error { return fmt.Errorf("%w %s", errMissingBlockState, blkID) } + a.metrics.SetBlockGas(blkState.blockGas) + // Update the state to reflect the changes made in [onAcceptState]. if err := blkState.onAcceptState.Apply(a.state); err != nil { return err diff --git a/vms/platformvm/block/executor/block_state.go b/vms/platformvm/block/executor/block_state.go index 9d6b377c2644..2c12c867f207 100644 --- a/vms/platformvm/block/executor/block_state.go +++ b/vms/platformvm/block/executor/block_state.go @@ -11,6 +11,8 @@ import ( "github.com/ava-labs/avalanchego/utils/set" "github.com/ava-labs/avalanchego/vms/platformvm/block" "github.com/ava-labs/avalanchego/vms/platformvm/state" + + commonfee "github.com/ava-labs/avalanchego/vms/components/fee" ) type proposalBlockState struct { @@ -30,5 +32,6 @@ type blockState struct { inputs set.Set[ids.ID] timestamp time.Time + blockGas commonfee.Gas atomicRequests map[ids.ID]*atomic.Requests } diff --git a/vms/platformvm/block/executor/helpers_test.go b/vms/platformvm/block/executor/helpers_test.go index 61e33e0f4325..b36f49443439 100644 --- a/vms/platformvm/block/executor/helpers_test.go +++ b/vms/platformvm/block/executor/helpers_test.go @@ -6,6 +6,7 @@ package executor import ( "context" "fmt" + "math/rand" "testing" "time" @@ -36,6 +37,7 @@ import ( "github.com/ava-labs/avalanchego/utils/logging" "github.com/ava-labs/avalanchego/utils/timer/mockable" "github.com/ava-labs/avalanchego/utils/units" + "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/platformvm/api" "github.com/ava-labs/avalanchego/vms/platformvm/config" "github.com/ava-labs/avalanchego/vms/platformvm/fx" @@ -61,15 +63,14 @@ const ( pending stakerStatus = iota current - defaultWeight = 10000 - trackChecksum = false - apricotPhase3 fork = iota apricotPhase5 banff cortina durango eUpgrade + + latestFork = eUpgrade ) var ( @@ -78,17 +79,24 @@ var ( defaultGenesisTime = time.Date(1997, 1, 1, 0, 0, 0, 0, time.UTC) defaultValidateStartTime = defaultGenesisTime defaultValidateEndTime = defaultValidateStartTime.Add(10 * defaultMinStakingDuration) - defaultMinValidatorStake = 5 * units.MilliAvax - defaultBalance = 100 * defaultMinValidatorStake - preFundedKeys = secp256k1.TestKeys() - avaxAssetID = ids.ID{'y', 'e', 'e', 't'} - defaultTxFee = uint64(100) + + defaultMinValidatorStake = 5 * units.MilliAvax + defaultMaxValidatorStake = 500 * units.MilliAvax + defaultMinDelegatorStake = 1 * units.MilliAvax + defaultBalance = 100 * defaultMinValidatorStake + defaultWeight = defaultBalance / 2 + + preFundedKeys = secp256k1.TestKeys() + avaxAssetID = ids.ID{'y', 'e', 'e', 't'} + defaultTxFee = uint64(100) genesisBlkID ids.ID testSubnet1 *txs.Tx // Node IDs of genesis validators. Initialized in init function genesisNodeIDs []ids.NodeID + + fundedSharedMemoryCalls byte ) func init() { @@ -102,6 +110,10 @@ type stakerStatus uint type fork uint8 +type mutableSharedMemory struct { + atomic.SharedMemory +} + type staker struct { nodeID ids.NodeID rewardAddress ids.ShortID @@ -127,6 +139,7 @@ type environment struct { clk *mockable.Clock baseDB *versiondb.Database ctx *snow.Context + msm *mutableSharedMemory fx fx.Fx state state.State mockedState *state.MockState @@ -152,6 +165,12 @@ func newEnvironment(t *testing.T, ctrl *gomock.Controller, f fork) *environment res.ctx.AVAXAssetID = avaxAssetID res.ctx.SharedMemory = m.NewSharedMemory(res.ctx.ChainID) + msm := &mutableSharedMemory{ + SharedMemory: m.NewSharedMemory(res.ctx.ChainID), + } + res.ctx.SharedMemory = msm + res.msm = msm + res.fx = defaultFx(res.clk, res.ctx.Log, res.isBootstrapped.Get()) rewardsCalc := reward.NewCalculator(res.config.RewardConfig) @@ -288,7 +307,7 @@ func addSubnet(env *environment) { if err != nil { panic(err) } - feeCalculator, err := state.PickFeeCalculator(env.config, stateDiff) + feeCalculator, err := state.PickFeeCalculator(env.config, stateDiff, stateDiff.GetTimestamp()) if err != nil { panic(err) } @@ -354,9 +373,9 @@ func defaultConfig(t *testing.T, f fork) *config.Config { CreateSubnetTxFee: 100 * defaultTxFee, CreateBlockchainTxFee: 100 * defaultTxFee, }, - MinValidatorStake: 5 * units.MilliAvax, - MaxValidatorStake: 500 * units.MilliAvax, - MinDelegatorStake: 1 * units.MilliAvax, + MinValidatorStake: defaultMinValidatorStake, + MaxValidatorStake: defaultMaxValidatorStake, + MinDelegatorStake: defaultMinDelegatorStake, MinStakeDuration: defaultMinStakingDuration, MaxStakeDuration: defaultMaxStakingDuration, RewardConfig: reward.Config{ @@ -557,3 +576,56 @@ func addPendingValidator( } return addPendingValidatorTx, nil } + +// Returns a shared memory where GetDatabase returns a database +// where [recipientKey] has a balance of [amt] +func fundedSharedMemory( + t *testing.T, + env *environment, + sourceKey *secp256k1.PrivateKey, + peerChain ids.ID, + assets map[ids.ID]uint64, +) atomic.SharedMemory { + fundedSharedMemoryCalls++ + m := atomic.NewMemory(prefixdb.New([]byte{fundedSharedMemoryCalls}, env.baseDB)) + + sm := m.NewSharedMemory(env.ctx.ChainID) + peerSharedMemory := m.NewSharedMemory(peerChain) + + for assetID, amt := range assets { + utxo := &avax.UTXO{ + UTXOID: avax.UTXOID{ + TxID: ids.GenerateTestID(), + OutputIndex: rand.Uint32(), // #nosec G404 + }, + Asset: avax.Asset{ID: assetID}, + Out: &secp256k1fx.TransferOutput{ + Amt: amt, + OutputOwners: secp256k1fx.OutputOwners{ + Locktime: 0, + Addrs: []ids.ShortID{sourceKey.PublicKey().Address()}, + Threshold: 1, + }, + }, + } + utxoBytes, err := txs.Codec.Marshal(txs.CodecVersion, utxo) + require.NoError(t, err) + + inputID := utxo.InputID() + require.NoError(t, peerSharedMemory.Apply(map[ids.ID]*atomic.Requests{ + env.ctx.ChainID: { + PutRequests: []*atomic.Element{ + { + Key: inputID[:], + Value: utxoBytes, + Traits: [][]byte{ + sourceKey.PublicKey().Address().Bytes(), + }, + }, + }, + }, + })) + } + + return sm +} diff --git a/vms/platformvm/block/executor/manager.go b/vms/platformvm/block/executor/manager.go index 82580c3b52b9..f287f202cf89 100644 --- a/vms/platformvm/block/executor/manager.go +++ b/vms/platformvm/block/executor/manager.go @@ -132,6 +132,8 @@ func (m *manager) VerifyTx(tx *txs.Tx) error { return err } + parentBlkTime := stateDiff.GetTimestamp() + nextBlkTime, _, err := state.NextBlockTime(stateDiff, m.txExecutorBackend.Clk) if err != nil { return err @@ -142,7 +144,7 @@ func (m *manager) VerifyTx(tx *txs.Tx) error { return err } - feeCalculator, err := state.PickFeeCalculator(m.txExecutorBackend.Config, stateDiff) + feeCalculator, err := state.PickFeeCalculator(m.txExecutorBackend.Config, stateDiff, parentBlkTime) if err != nil { return err } diff --git a/vms/platformvm/block/executor/proposal_block_test.go b/vms/platformvm/block/executor/proposal_block_test.go index ce05c963da49..9b7a684fb762 100644 --- a/vms/platformvm/block/executor/proposal_block_test.go +++ b/vms/platformvm/block/executor/proposal_block_test.go @@ -29,6 +29,7 @@ import ( "github.com/ava-labs/avalanchego/vms/platformvm/txs/executor" "github.com/ava-labs/avalanchego/vms/secp256k1fx" + commonfee "github.com/ava-labs/avalanchego/vms/components/fee" walletsigner "github.com/ava-labs/avalanchego/wallet/chain/p/signer" walletcommon "github.com/ava-labs/avalanchego/wallet/subnet/primary/common" ) @@ -88,6 +89,7 @@ func TestApricotProposalBlockTimeVerification(t *testing.T) { // setup state to validate proposal block transaction onParentAccept.EXPECT().GetTimestamp().Return(chainTime).AnyTimes() + onParentAccept.EXPECT().GetCurrentGasCap().Return(commonfee.Gas(1_000_000), nil) currentStakersIt := state.NewMockStakerIterator(ctrl) currentStakersIt.EXPECT().Next().Return(true) @@ -160,6 +162,7 @@ func TestBanffProposalBlockTimeVerification(t *testing.T) { onParentAccept := state.NewMockDiff(ctrl) onParentAccept.EXPECT().GetTimestamp().Return(parentTime).AnyTimes() + onParentAccept.EXPECT().GetCurrentGasCap().Return(commonfee.Gas(1_000_000), nil).AnyTimes() onParentAccept.EXPECT().GetCurrentSupply(constants.PrimaryNetworkID).Return(uint64(1000), nil).AnyTimes() env.blkManager.(*manager).blkIDToState[parentID] = &blockState{ diff --git a/vms/platformvm/block/executor/standard_block_test.go b/vms/platformvm/block/executor/standard_block_test.go index 4fa833b62d01..496cd38f032e 100644 --- a/vms/platformvm/block/executor/standard_block_test.go +++ b/vms/platformvm/block/executor/standard_block_test.go @@ -24,6 +24,7 @@ import ( "github.com/ava-labs/avalanchego/vms/platformvm/txs/executor" "github.com/ava-labs/avalanchego/vms/secp256k1fx" + commonfee "github.com/ava-labs/avalanchego/vms/components/fee" walletsigner "github.com/ava-labs/avalanchego/wallet/chain/p/signer" ) @@ -57,6 +58,7 @@ func TestApricotStandardBlockTimeVerification(t *testing.T) { env.mockedState.EXPECT().GetLastAccepted().Return(parentID).AnyTimes() env.mockedState.EXPECT().GetTimestamp().Return(chainTime).AnyTimes() onParentAccept.EXPECT().GetTimestamp().Return(chainTime).AnyTimes() + onParentAccept.EXPECT().GetCurrentGasCap().Return(commonfee.ZeroGas, nil).AnyTimes() // wrong height apricotChildBlk, err := block.NewApricotStandardBlock( @@ -150,6 +152,7 @@ func TestBanffStandardBlockTimeVerification(t *testing.T) { } utxoID := utxo.InputID() onParentAccept.EXPECT().GetUTXO(utxoID).Return(utxo, nil).AnyTimes() + onParentAccept.EXPECT().GetCurrentGasCap().Return(commonfee.ZeroGas, nil).AnyTimes() // Create the tx utx := &txs.CreateSubnetTx{ diff --git a/vms/platformvm/block/executor/verifier.go b/vms/platformvm/block/executor/verifier.go index fcd38a9d72be..ef45b1115a07 100644 --- a/vms/platformvm/block/executor/verifier.go +++ b/vms/platformvm/block/executor/verifier.go @@ -16,6 +16,8 @@ import ( "github.com/ava-labs/avalanchego/vms/platformvm/txs" "github.com/ava-labs/avalanchego/vms/platformvm/txs/executor" "github.com/ava-labs/avalanchego/vms/platformvm/txs/fee" + + commonfee "github.com/ava-labs/avalanchego/vms/components/fee" ) var ( @@ -61,13 +63,16 @@ func (v *verifier) BanffProposalBlock(b *block.BanffProposalBlock) error { return err } + // retrieve parent block time before moving time forward + parentBlkTime := onDecisionState.GetTimestamp() + // Advance the time to [nextChainTime]. nextChainTime := b.Timestamp() if _, err := executor.AdvanceTimeTo(v.txExecutorBackend, onDecisionState, nextChainTime); err != nil { return err } - feeCalculator, err := state.PickFeeCalculator(v.txExecutorBackend.Config, onDecisionState) + feeCalculator, err := state.PickFeeCalculator(v.txExecutorBackend.Config, onDecisionState, parentBlkTime) if err != nil { return err } @@ -115,6 +120,9 @@ func (v *verifier) BanffStandardBlock(b *block.BanffStandardBlock) error { return err } + // retrieve parent block time before moving time forward + parentBlkTime := onAcceptState.GetTimestamp() + // Advance the time to [b.Timestamp()]. changed, err := executor.AdvanceTimeTo( v.txExecutorBackend, @@ -131,7 +139,7 @@ func (v *verifier) BanffStandardBlock(b *block.BanffStandardBlock) error { return errBanffStandardBlockWithoutChanges } - feeCalculator, err := state.PickFeeCalculator(v.txExecutorBackend.Config, onAcceptState) + feeCalculator, err := state.PickFeeCalculator(v.txExecutorBackend.Config, onAcceptState, parentBlkTime) if err != nil { return err } @@ -246,6 +254,7 @@ func (v *verifier) ApricotAtomicBlock(b *block.ApricotAtomicBlock) error { inputs: atomicExecutor.Inputs, timestamp: atomicExecutor.OnAccept.GetTimestamp(), + blockGas: commonfee.ZeroGas, atomicRequests: atomicExecutor.AtomicRequests, } return nil @@ -391,6 +400,11 @@ func (v *verifier) proposalBlock( atomicRequests map[ids.ID]*atomic.Requests, onAcceptFunc func(), ) error { + currentGasCap, err := onCommitState.GetCurrentGasCap() + if err != nil { + return err + } + txExecutor := executor.ProposalTxExecutor{ OnCommitState: onCommitState, OnAbortState: onAbortState, @@ -405,6 +419,17 @@ func (v *verifier) proposalBlock( return err } + blkGas, err := feeCalculator.GetBlockGas() + if err != nil { + return err + } + + if feeCalculator.IsEActive() { + nextGasCap := commonfee.UpdateGasCap(currentGasCap, blkGas) + onCommitState.SetCurrentGasCap(nextGasCap) + onAbortState.SetCurrentGasCap(nextGasCap) + } + onCommitState.AddTx(b.Tx, status.Committed) onAbortState.AddTx(b.Tx, status.Aborted) @@ -427,6 +452,7 @@ func (v *verifier) proposalBlock( // never be modified by an Apricot Abort block and the timestamp will // always be the same as the Banff Proposal Block. timestamp: onAbortState.GetTimestamp(), + blockGas: blkGas, atomicRequests: atomicRequests, } return nil @@ -438,6 +464,11 @@ func (v *verifier) standardBlock( feeCalculator fee.Calculator, onAcceptState state.Diff, ) error { + currentGasCap, err := onAcceptState.GetCurrentGasCap() + if err != nil { + return err + } + inputs, atomicRequests, onAcceptFunc, err := v.processStandardTxs(b.Transactions, feeCalculator, onAcceptState, b.Parent()) if err != nil { return err @@ -446,6 +477,17 @@ func (v *verifier) standardBlock( v.Mempool.Remove(b.Transactions...) blkID := b.ID() + + blkGas, err := feeCalculator.GetBlockGas() + if err != nil { + return err + } + + if feeCalculator.IsEActive() { + nextGasCap := commonfee.UpdateGasCap(currentGasCap, blkGas) + onAcceptState.SetCurrentGasCap(nextGasCap) + } + v.blkIDToState[blkID] = &blockState{ statelessBlock: b, @@ -453,13 +495,19 @@ func (v *verifier) standardBlock( onAcceptFunc: onAcceptFunc, timestamp: onAcceptState.GetTimestamp(), + blockGas: blkGas, inputs: inputs, atomicRequests: atomicRequests, } return nil } -func (v *verifier) processStandardTxs(txs []*txs.Tx, feeCalculator fee.Calculator, state state.Diff, parentID ids.ID) ( +func (v *verifier) processStandardTxs( + txs []*txs.Tx, + feeCalculator fee.Calculator, + state state.Diff, + parentID ids.ID, +) ( set.Set[ids.ID], map[ids.ID]*atomic.Requests, func(), diff --git a/vms/platformvm/block/executor/verifier_test.go b/vms/platformvm/block/executor/verifier_test.go index 34d8a0d7432e..42b1cb110b74 100644 --- a/vms/platformvm/block/executor/verifier_test.go +++ b/vms/platformvm/block/executor/verifier_test.go @@ -15,20 +15,542 @@ import ( "github.com/ava-labs/avalanchego/database" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/snow" + "github.com/ava-labs/avalanchego/utils/constants" + "github.com/ava-labs/avalanchego/utils/crypto/bls" "github.com/ava-labs/avalanchego/utils/logging" "github.com/ava-labs/avalanchego/utils/set" "github.com/ava-labs/avalanchego/utils/timer/mockable" + "github.com/ava-labs/avalanchego/utils/units" + "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/components/verify" "github.com/ava-labs/avalanchego/vms/platformvm/block" "github.com/ava-labs/avalanchego/vms/platformvm/config" + "github.com/ava-labs/avalanchego/vms/platformvm/reward" + "github.com/ava-labs/avalanchego/vms/platformvm/signer" "github.com/ava-labs/avalanchego/vms/platformvm/state" "github.com/ava-labs/avalanchego/vms/platformvm/status" "github.com/ava-labs/avalanchego/vms/platformvm/txs" "github.com/ava-labs/avalanchego/vms/platformvm/txs/executor" + "github.com/ava-labs/avalanchego/vms/platformvm/txs/fee" "github.com/ava-labs/avalanchego/vms/platformvm/txs/mempool" "github.com/ava-labs/avalanchego/vms/platformvm/upgrade" + "github.com/ava-labs/avalanchego/vms/secp256k1fx" + "github.com/ava-labs/avalanchego/wallet/subnet/primary/common" + + commonfee "github.com/ava-labs/avalanchego/vms/components/fee" + walletsigner "github.com/ava-labs/avalanchego/wallet/chain/p/signer" ) +// Check that gas consumed by a standard blocks is duly calculated once block is verified +// Only transactions active post E upgrade are considered and tested pre and post E upgrade. +func TestStandardBlockGas(t *testing.T) { + type test struct { + name string + setupTest func(env *environment) *txs.Tx + } + + tests := []test{ + { + name: "AddPermissionlessValidatorTx", + setupTest: func(env *environment) *txs.Tx { + var ( + nodeID = ids.GenerateTestNodeID() + chainTime = env.state.GetTimestamp() + endTime = chainTime.Add(defaultMaxStakingDuration) + ) + sk, err := bls.NewSecretKey() + require.NoError(t, err) + + builder, s, feeCalc, err := env.factory.NewWallet(preFundedKeys...) + require.NoError(t, err) + utx, err := builder.NewAddPermissionlessValidatorTx( + &txs.SubnetValidator{ + Validator: txs.Validator{ + NodeID: nodeID, + End: uint64(endTime.Unix()), + Wght: env.config.MinValidatorStake, + }, + Subnet: constants.PrimaryNetworkID, + }, + signer.NewProofOfPossession(sk), + env.ctx.AVAXAssetID, + &secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{ids.ShortEmpty}, + }, + &secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{ids.ShortEmpty}, + }, + reward.PercentDenominator, + feeCalc, + common.WithChangeOwner(&secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{ + preFundedKeys[0].PublicKey().Address(), + }, + }), + ) + require.NoError(t, err) + tx, err := walletsigner.SignUnsigned(context.Background(), s, utx) + require.NoError(t, err) + + return tx + }, + }, + { + name: "AddPermissionlessDelegatorTx", + setupTest: func(env *environment) *txs.Tx { + var primaryValidator *state.Staker + it, err := env.state.GetCurrentStakerIterator() + require.NoError(t, err) + for it.Next() { + staker := it.Value() + if staker.Priority != txs.PrimaryNetworkValidatorCurrentPriority { + continue + } + primaryValidator = staker + break + } + it.Release() + + builder, signer, feeCalc, err := env.factory.NewWallet(preFundedKeys...) + require.NoError(t, err) + utx, err := builder.NewAddPermissionlessDelegatorTx( + &txs.SubnetValidator{ + Validator: txs.Validator{ + NodeID: primaryValidator.NodeID, + End: uint64(primaryValidator.EndTime.Unix()), + Wght: env.config.MinDelegatorStake, + }, + Subnet: constants.PrimaryNetworkID, + }, + env.ctx.AVAXAssetID, + &secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{ids.ShortEmpty}, + }, + feeCalc, + common.WithChangeOwner(&secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{ + preFundedKeys[0].PublicKey().Address(), + }, + }), + ) + require.NoError(t, err) + tx, err := walletsigner.SignUnsigned(context.Background(), signer, utx) + require.NoError(t, err) + + return tx + }, + }, + { + name: "AddSubnetValidatorTx", + setupTest: func(env *environment) *txs.Tx { + var primaryValidator *state.Staker + it, err := env.state.GetCurrentStakerIterator() + require.NoError(t, err) + for it.Next() { + staker := it.Value() + if staker.Priority != txs.PrimaryNetworkValidatorCurrentPriority { + continue + } + primaryValidator = staker + break + } + it.Release() + + builder, signer, feeCalc, err := env.factory.NewWallet(preFundedKeys...) + require.NoError(t, err) + utx, err := builder.NewAddSubnetValidatorTx( + &txs.SubnetValidator{ + Validator: txs.Validator{ + NodeID: primaryValidator.NodeID, + End: uint64(primaryValidator.EndTime.Unix()), + Wght: defaultMinValidatorStake, + }, + Subnet: testSubnet1.TxID, + }, + feeCalc, + common.WithChangeOwner(&secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{ + preFundedKeys[0].PublicKey().Address(), + }, + }), + ) + require.NoError(t, err) + tx, err := walletsigner.SignUnsigned(context.Background(), signer, utx) + require.NoError(t, err) + + return tx + }, + }, + { + name: "CreateChainTx", + setupTest: func(env *environment) *txs.Tx { + builder, signer, feeCalc, err := env.factory.NewWallet(preFundedKeys...) + require.NoError(t, err) + utx, err := builder.NewCreateChainTx( + testSubnet1.TxID, + []byte{}, // genesisData + ids.GenerateTestID(), // vmID + []ids.ID{}, // fxIDs + "aaa", // chain name + feeCalc, + common.WithChangeOwner(&secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{ + preFundedKeys[0].PublicKey().Address(), + }, + }), + ) + require.NoError(t, err) + tx, err := walletsigner.SignUnsigned(context.Background(), signer, utx) + require.NoError(t, err) + return tx + }, + }, + { + name: "CreateSubnetTx", + setupTest: func(env *environment) *txs.Tx { + builder, signer, feeCalc, err := env.factory.NewWallet(preFundedKeys...) + require.NoError(t, err) + utx, err := builder.NewCreateSubnetTx( + &secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{ids.GenerateTestShortID()}, + }, + feeCalc, + common.WithChangeOwner(&secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{ + preFundedKeys[0].PublicKey().Address(), + }, + }), + ) + require.NoError(t, err) + tx, err := walletsigner.SignUnsigned(context.Background(), signer, utx) + require.NoError(t, err) + return tx + }, + }, + { + name: "RemoveSubnetValidatorTx", + setupTest: func(env *environment) *txs.Tx { + var primaryValidator *state.Staker + it, err := env.state.GetCurrentStakerIterator() + require.NoError(t, err) + for it.Next() { + staker := it.Value() + if staker.Priority != txs.PrimaryNetworkValidatorCurrentPriority { + continue + } + primaryValidator = staker + break + } + it.Release() + + endTime := primaryValidator.EndTime + + builder, signer, feeCalc, err := env.factory.NewWallet(preFundedKeys...) + require.NoError(t, err) + uSubnetValTx, err := builder.NewAddSubnetValidatorTx( + &txs.SubnetValidator{ + Validator: txs.Validator{ + NodeID: primaryValidator.NodeID, + Start: 0, + End: uint64(endTime.Unix()), + Wght: defaultWeight, + }, + Subnet: testSubnet1.ID(), + }, + feeCalc, + common.WithChangeOwner(&secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{ + preFundedKeys[0].PublicKey().Address(), + }, + }), + ) + require.NoError(t, err) + subnetValTx, err := walletsigner.SignUnsigned(context.Background(), signer, uSubnetValTx) + require.NoError(t, err) + + onAcceptState, err := state.NewDiffOn(env.state) + require.NoError(t, err) + + feeCalculator, err := state.PickFeeCalculator(env.config, onAcceptState, onAcceptState.GetTimestamp()) + require.NoError(t, err) + + require.NoError(t, subnetValTx.Unsigned.Visit(&executor.StandardTxExecutor{ + Backend: env.backend, + State: onAcceptState, + FeeCalculator: feeCalculator, + Tx: subnetValTx, + })) + + require.NoError(t, onAcceptState.Apply(env.state)) + require.NoError(t, env.state.Commit()) + + utx, err := builder.NewRemoveSubnetValidatorTx( + primaryValidator.NodeID, + testSubnet1.ID(), + feeCalc, + common.WithChangeOwner(&secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{ + preFundedKeys[0].PublicKey().Address(), + }, + }), + ) + require.NoError(t, err) + tx, err := walletsigner.SignUnsigned(context.Background(), signer, utx) + require.NoError(t, err) + + return tx + }, + }, + { + name: "TransformSubnetTx", + setupTest: func(env *environment) *txs.Tx { + builder, signer, feeCalc, err := env.factory.NewWallet(preFundedKeys...) + require.NoError(t, err) + utx, err := builder.NewTransformSubnetTx( + testSubnet1.TxID, // subnetID + ids.GenerateTestID(), // assetID + 10, // initial supply + 10, // max supply + 0, // min consumption rate + reward.PercentDenominator, // max consumption rate + 2, // min validator stake + 10, // max validator stake + time.Minute, // min stake duration + time.Hour, // max stake duration + 1, // min delegation fees + 10, // min delegator stake + 1, // max validator weight factor + 80, // uptime requirement + feeCalc, + common.WithChangeOwner(&secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{ + preFundedKeys[0].PublicKey().Address(), + }, + }), + ) + require.NoError(t, err) + tx, err := walletsigner.SignUnsigned(context.Background(), signer, utx) + require.NoError(t, err) + return tx + }, + }, + { + name: "TransferSubnetOwnershipTx", + setupTest: func(env *environment) *txs.Tx { + builder, signer, feeCalc, err := env.factory.NewWallet(preFundedKeys...) + require.NoError(t, err) + utx, err := builder.NewTransferSubnetOwnershipTx( + testSubnet1.TxID, + &secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{ids.ShortEmpty}, + }, + feeCalc, + common.WithChangeOwner(&secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{ + preFundedKeys[0].PublicKey().Address(), + }, + }), + ) + require.NoError(t, err) + tx, err := walletsigner.SignUnsigned(context.Background(), signer, utx) + require.NoError(t, err) + + return tx + }, + }, + { + name: "ImportTx", + setupTest: func(env *environment) *txs.Tx { + // Skip shared memory checks + env.backend.Bootstrapped.Set(false) + + var ( + sourceChain = env.ctx.XChainID + sourceKey = preFundedKeys[1] + sourceAmount = 10 * units.Avax + ) + + sharedMemory := fundedSharedMemory( + t, + env, + sourceKey, + sourceChain, + map[ids.ID]uint64{ + env.ctx.AVAXAssetID: sourceAmount, + }, + ) + env.msm.SharedMemory = sharedMemory + + builder, signer, feeCalc, err := env.factory.NewWallet(preFundedKeys...) + require.NoError(t, err) + utx, err := builder.NewImportTx( + sourceChain, + &secp256k1fx.OutputOwners{ + Locktime: 0, + Threshold: 1, + Addrs: []ids.ShortID{sourceKey.PublicKey().Address()}, + }, + feeCalc, + common.WithChangeOwner(&secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{ + preFundedKeys[0].PublicKey().Address(), + }, + }), + ) + require.NoError(t, err) + tx, err := walletsigner.SignUnsigned(context.Background(), signer, utx) + require.NoError(t, err) + + // reactivate checks + env.backend.Bootstrapped.Set(true) + return tx + }, + }, + { + name: "ExportTx", + setupTest: func(env *environment) *txs.Tx { + builder, signer, feeCalc, err := env.factory.NewWallet(preFundedKeys...) + require.NoError(t, err) + utx, err := builder.NewExportTx( + env.ctx.XChainID, + []*avax.TransferableOutput{{ + Asset: avax.Asset{ID: env.ctx.AVAXAssetID}, + Out: &secp256k1fx.TransferOutput{ + Amt: units.Avax, + OutputOwners: secp256k1fx.OutputOwners{ + Locktime: 0, + Threshold: 1, + Addrs: []ids.ShortID{ids.GenerateTestShortID()}, + }, + }, + }}, + feeCalc, + common.WithChangeOwner(&secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{ + preFundedKeys[0].PublicKey().Address(), + }, + }), + ) + require.NoError(t, err) + tx, err := walletsigner.SignUnsigned(context.Background(), signer, utx) + require.NoError(t, err) + + return tx + }, + }, + { + name: "BaseTx", + setupTest: func(env *environment) *txs.Tx { + builder, signer, feeCalc, err := env.factory.NewWallet(preFundedKeys...) + require.NoError(t, err) + utx, err := builder.NewBaseTx( + []*avax.TransferableOutput{ + { + Asset: avax.Asset{ID: env.ctx.AVAXAssetID}, + Out: &secp256k1fx.TransferOutput{ + Amt: 1, + OutputOwners: secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{ids.ShortEmpty}, + }, + }, + }, + }, + feeCalc, + common.WithChangeOwner(&secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{ + preFundedKeys[0].PublicKey().Address(), + }, + }), + ) + require.NoError(t, err) + tx, err := walletsigner.SignUnsigned(context.Background(), signer, utx) + require.NoError(t, err) + return tx + }, + }, + } + + for _, tt := range tests { + for _, dynamicFeesActive := range []bool{false, true} { + t.Run(tt.name, func(t *testing.T) { + require := require.New(t) + + f := latestFork + if !dynamicFeesActive { + f = durango + } + env := newEnvironment(t, nil, f) + env.ctx.Lock.Lock() + defer env.ctx.Lock.Unlock() + + tx := tt.setupTest(env) + + nextBlkTime, _, err := state.NextBlockTime(env.state, env.clk) + require.NoError(err) + + parentBlkID := env.state.GetLastAccepted() + parentBlk, err := env.state.GetStatelessBlock(parentBlkID) + require.NoError(err) + + statelessBlk, err := block.NewBanffStandardBlock( + nextBlkTime, + parentBlkID, + parentBlk.Height()+1, + []*txs.Tx{tx}, + ) + require.NoError(err) + + blk := env.blkManager.NewBlock(statelessBlk) + require.NoError(blk.Verify(context.Background())) + + // check that metered complexity is non-zero post E upgrade and zero pre E upgrade + blkState, found := env.blkManager.(*manager).blkIDToState[blk.ID()] + require.True(found) + + if dynamicFeesActive { + require.NotEqual(commonfee.ZeroGas, blkState.blockGas) + + gasCap, err := blkState.onAcceptState.GetCurrentGasCap() + require.NoError(err) + require.Greater(gasCap, commonfee.ZeroGas) + + feeCfg, err := fee.GetDynamicConfig(dynamicFeesActive) + require.NoError(err) + require.Less(gasCap, feeCfg.MaxGasPerSecond) + } else { + require.Equal(commonfee.ZeroGas, blkState.blockGas) + + // GasCap unchanged wrt parent state + parentGasCap, err := env.state.GetCurrentGasCap() + require.NoError(err) + + gasCap, err := blkState.onAcceptState.GetCurrentGasCap() + require.NoError(err) + require.Equal(parentGasCap, gasCap) + } + }) + } + } +} + func TestVerifierVisitProposalBlock(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) @@ -41,6 +563,7 @@ func TestVerifierVisitProposalBlock(t *testing.T) { timestamp := time.Now() // One call for each of onCommitState and onAbortState. parentOnAcceptState.EXPECT().GetTimestamp().Return(timestamp).Times(2) + parentOnAcceptState.EXPECT().GetCurrentGasCap().Return(commonfee.Gas(1_000_000), nil) backend := &backend{ lastAccepted: parentID, @@ -237,6 +760,9 @@ func TestVerifierVisitStandardBlock(t *testing.T) { UpgradeConfig: upgrade.Config{ ApricotPhase5Time: time.Now().Add(time.Hour), BanffTime: mockable.MaxTime, // banff is not activated + CortinaTime: mockable.MaxTime, + DurangoTime: mockable.MaxTime, + EUpgradeTime: mockable.MaxTime, }, }, Clk: &mockable.Clock{}, @@ -290,8 +816,9 @@ func TestVerifierVisitStandardBlock(t *testing.T) { // Set expectations for dependencies. timestamp := time.Now() - parentState.EXPECT().GetTimestamp().Return(timestamp).Times(1) - parentStatelessBlk.EXPECT().Height().Return(uint64(1)).Times(1) + parentState.EXPECT().GetTimestamp().Return(timestamp) + parentState.EXPECT().GetCurrentGasCap().Return(commonfee.Gas(1_000_000), nil) + parentStatelessBlk.EXPECT().Height().Return(uint64(1)) mempool.EXPECT().Remove(apricotBlk.Txs()).Times(1) blk := manager.NewBlock(apricotBlk) @@ -731,6 +1258,9 @@ func TestVerifierVisitStandardBlockWithDuplicateInputs(t *testing.T) { UpgradeConfig: upgrade.Config{ ApricotPhase5Time: time.Now().Add(time.Hour), BanffTime: mockable.MaxTime, // banff is not activated + CortinaTime: mockable.MaxTime, + DurangoTime: mockable.MaxTime, + EUpgradeTime: mockable.MaxTime, }, }, Clk: &mockable.Clock{}, @@ -780,8 +1310,10 @@ func TestVerifierVisitStandardBlockWithDuplicateInputs(t *testing.T) { // Set expectations for dependencies. timestamp := time.Now() - parentStatelessBlk.EXPECT().Height().Return(uint64(1)).Times(1) - parentState.EXPECT().GetTimestamp().Return(timestamp).Times(1) + parentStatelessBlk.EXPECT().Height().Return(uint64(1)) + parentState.EXPECT().GetTimestamp().Return(timestamp) + parentState.EXPECT().GetCurrentGasCap().Return(commonfee.Gas(1_000_000), nil) + parentStatelessBlk.EXPECT().Parent().Return(grandParentID).Times(1) err = verifier.ApricotStandardBlock(blk) diff --git a/vms/platformvm/config/execution_config.go b/vms/platformvm/config/execution_config.go index e182758e0c50..4b1a0716f948 100644 --- a/vms/platformvm/config/execution_config.go +++ b/vms/platformvm/config/execution_config.go @@ -9,6 +9,8 @@ import ( "github.com/ava-labs/avalanchego/utils/units" "github.com/ava-labs/avalanchego/vms/platformvm/network" + + commonfee "github.com/ava-labs/avalanchego/vms/components/fee" ) var DefaultExecutionConfig = ExecutionConfig{ @@ -38,6 +40,9 @@ type ExecutionConfig struct { FxOwnerCacheSize int `json:"fx-owner-cache-size"` ChecksumsEnabled bool `json:"checksums-enabled"` MempoolPruneFrequency time.Duration `json:"mempool-prune-frequency"` + + // test nets are allow to configure ad-hoc dynamic fees configuration + DynamicFeesConfig *commonfee.DynamicFeesConfig `json:"dynamic-fees-config"` } // GetExecutionConfig returns an ExecutionConfig diff --git a/vms/platformvm/config/execution_config_test.go b/vms/platformvm/config/execution_config_test.go index f3fe8e4c6082..abce623658c5 100644 --- a/vms/platformvm/config/execution_config_test.go +++ b/vms/platformvm/config/execution_config_test.go @@ -12,6 +12,8 @@ import ( "github.com/stretchr/testify/require" "github.com/ava-labs/avalanchego/vms/platformvm/network" + + commonfee "github.com/ava-labs/avalanchego/vms/components/fee" ) // Requires all values in a struct to be initialized @@ -91,6 +93,12 @@ func TestExecutionConfigUnmarshal(t *testing.T) { FxOwnerCacheSize: 9, ChecksumsEnabled: true, MempoolPruneFrequency: time.Minute, + DynamicFeesConfig: &commonfee.DynamicFeesConfig{ + GasPrice: commonfee.GasPrice(1234), + FeeDimensionWeights: commonfee.Dimensions{1, 2, 3, 4}, + MaxGasPerSecond: commonfee.Gas(12), + LeakGasCoeff: commonfee.Gas(34), + }, } verifyInitializedStruct(t, *expected) verifyInitializedStruct(t, expected.Network) diff --git a/vms/platformvm/metrics/metrics.go b/vms/platformvm/metrics/metrics.go index 82b51dc8c34c..f82675ca4671 100644 --- a/vms/platformvm/metrics/metrics.go +++ b/vms/platformvm/metrics/metrics.go @@ -12,6 +12,8 @@ import ( "github.com/ava-labs/avalanchego/utils/metric" "github.com/ava-labs/avalanchego/utils/wrappers" "github.com/ava-labs/avalanchego/vms/platformvm/block" + + commonfee "github.com/ava-labs/avalanchego/vms/components/fee" ) var _ Metrics = (*metrics)(nil) @@ -38,6 +40,8 @@ type Metrics interface { SetTimeUntilUnstake(time.Duration) // Mark when this node will unstake from a subnet. SetTimeUntilSubnetUnstake(subnetID ids.ID, timeUntilUnstake time.Duration) + // Mark gas cumulated across txs of last accepted block + SetBlockGas(commonfee.Gas) } func New(registerer prometheus.Registerer) (Metrics, error) { @@ -80,6 +84,10 @@ func New(registerer prometheus.Registerer) (Metrics, error) { Name: "validator_sets_duration_sum", Help: "Total amount of time generating validator sets in nanoseconds", }), + blockGas: prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "block_gas", + Help: "Cumulated gas over last accepted block", + }), } errs := wrappers.Errs{Err: err} @@ -96,6 +104,7 @@ func New(registerer prometheus.Registerer) (Metrics, error) { registerer.Register(m.validatorSetsCached), registerer.Register(m.validatorSetsHeightDiff), registerer.Register(m.validatorSetsDuration), + registerer.Register(m.blockGas), ) return m, errs.Err @@ -115,6 +124,8 @@ type metrics struct { validatorSetsCreated prometheus.Counter validatorSetsHeightDiff prometheus.Gauge validatorSetsDuration prometheus.Gauge + + blockGas prometheus.Gauge } func (m *metrics) MarkAccepted(b block.Block) error { @@ -152,3 +163,7 @@ func (m *metrics) SetTimeUntilUnstake(timeUntilUnstake time.Duration) { func (m *metrics) SetTimeUntilSubnetUnstake(subnetID ids.ID, timeUntilUnstake time.Duration) { m.timeUntilSubnetUnstake.WithLabelValues(subnetID.String()).Set(float64(timeUntilUnstake)) } + +func (m *metrics) SetBlockGas(g commonfee.Gas) { + m.blockGas.Set(float64(g)) +} diff --git a/vms/platformvm/metrics/no_op.go b/vms/platformvm/metrics/no_op.go index 770e30c961a1..0fe89903ca6b 100644 --- a/vms/platformvm/metrics/no_op.go +++ b/vms/platformvm/metrics/no_op.go @@ -11,6 +11,8 @@ import ( "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/vms/platformvm/block" + + commonfee "github.com/ava-labs/avalanchego/vms/components/fee" ) var Noop Metrics = noopMetrics{} @@ -50,3 +52,5 @@ func (noopMetrics) SetTimeUntilSubnetUnstake(ids.ID, time.Duration) {} func (noopMetrics) SetSubnetPercentConnected(ids.ID, float64) {} func (noopMetrics) SetPercentConnected(float64) {} + +func (noopMetrics) SetBlockGas(commonfee.Gas) {} diff --git a/vms/platformvm/service.go b/vms/platformvm/service.go index 7cd5d026ed23..d0cd3da96f53 100644 --- a/vms/platformvm/service.go +++ b/vms/platformvm/service.go @@ -1882,7 +1882,19 @@ func (s *Service) GetNextGasData(_ *http.Request, _ *struct{}, reply *GetGasPric return fmt.Errorf("could not retrieve state for block %s", preferredID) } - feeCalculator, err := state.PickFeeCalculator(&s.vm.Config, onAccept) + currentChainTime := onAccept.GetTimestamp() + nextTimestamp, _, err := state.NextBlockTime(onAccept, &s.vm.clock) + if err != nil { + return fmt.Errorf("could not calculate next staker change time: %w", err) + } + + stateDiff, err := state.NewDiffOn(onAccept) + if err != nil { + return err + } + stateDiff.SetTimestamp(nextTimestamp) + + feeCalculator, err := state.PickFeeCalculator(&s.vm.Config, stateDiff, currentChainTime) if err != nil { return err } diff --git a/vms/platformvm/service_test.go b/vms/platformvm/service_test.go index dbb79367f8ad..82fb34a823b9 100644 --- a/vms/platformvm/service_test.go +++ b/vms/platformvm/service_test.go @@ -34,15 +34,18 @@ import ( "github.com/ava-labs/avalanchego/utils/logging" "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/platformvm/block" + "github.com/ava-labs/avalanchego/vms/platformvm/config" "github.com/ava-labs/avalanchego/vms/platformvm/signer" "github.com/ava-labs/avalanchego/vms/platformvm/state" "github.com/ava-labs/avalanchego/vms/platformvm/status" "github.com/ava-labs/avalanchego/vms/platformvm/txs" + "github.com/ava-labs/avalanchego/vms/platformvm/txs/fee" "github.com/ava-labs/avalanchego/vms/platformvm/txs/txstest" "github.com/ava-labs/avalanchego/vms/secp256k1fx" "github.com/ava-labs/avalanchego/wallet/subnet/primary/common" avajson "github.com/ava-labs/avalanchego/utils/json" + commonfee "github.com/ava-labs/avalanchego/vms/components/fee" vmkeystore "github.com/ava-labs/avalanchego/vms/components/keystore" pchainapi "github.com/ava-labs/avalanchego/vms/platformvm/api" blockbuilder "github.com/ava-labs/avalanchego/vms/platformvm/block/builder" @@ -75,6 +78,31 @@ var ( } ) +func testReplayFeeCalculator(cfg *config.Config, parentBlkTime time.Time, state state.Chain) (fee.Calculator, error) { + var ( + childBlkTime = state.GetTimestamp() + isEActive = cfg.UpgradeConfig.IsEActivated(childBlkTime) + ) + + if !isEActive { + return fee.NewStaticCalculator(cfg.StaticFeeConfig, cfg.UpgradeConfig, childBlkTime), nil + } + + feesCfg, err := fee.GetDynamicConfig(isEActive) + if err != nil { + return nil, fmt.Errorf("failed retrieving dynamic fees config: %w", err) + } + currentGasCap, err := state.GetCurrentGasCap() + if err != nil { + return nil, fmt.Errorf("failed retrieving current gas cap: %w", err) + } + gasCap, err := commonfee.GasCap(feesCfg, currentGasCap, parentBlkTime, childBlkTime) + if err != nil { + return nil, fmt.Errorf("failed updating gas cap: %w", err) + } + return fee.NewDynamicCalculator(commonfee.NewCalculator(feesCfg.FeeDimensionWeights, feesCfg.GasPrice, gasCap)), nil +} + func defaultService(t *testing.T) (*Service, *mutableSharedMemory, *txstest.WalletFactory) { vm, factory, _, mutableSharedMemory := defaultVM(t, latestFork) @@ -402,7 +430,7 @@ func TestGetBalance(t *testing.T) { if idx == 0 { // we use the first key to fund a subnet creation in [defaultGenesis]. // As such we need to account for the subnet creation fee - feeCalc, err := state.PickFeeCalculator(&service.vm.Config, service.vm.state) + feeCalc, err := testReplayFeeCalculator(&service.vm.Config, defaultGenesisTime, service.vm.state) require.NoError(err) fee, err := feeCalc.CalculateFee(&txs.Tx{Unsigned: testSubnet1.Unsigned, Creds: testSubnet1.Creds}) require.NoError(err) diff --git a/vms/platformvm/state/chain_time_helpers.go b/vms/platformvm/state/chain_time_helpers.go index 22fa97a7ac3c..22fce7794e8e 100644 --- a/vms/platformvm/state/chain_time_helpers.go +++ b/vms/platformvm/state/chain_time_helpers.go @@ -11,6 +11,8 @@ import ( "github.com/ava-labs/avalanchego/utils/timer/mockable" "github.com/ava-labs/avalanchego/vms/platformvm/config" "github.com/ava-labs/avalanchego/vms/platformvm/txs/fee" + + commonfee "github.com/ava-labs/avalanchego/vms/components/fee" ) func NextBlockTime(state Chain, clk *mockable.Clock) (time.Time, bool, error) { @@ -75,7 +77,40 @@ func GetNextStakerChangeTime(state Chain) (time.Time, error) { // depending on the active upgrade. // // PickFeeCalculator does not modify [state]. -func PickFeeCalculator(cfg *config.Config, state Chain) (fee.Calculator, error) { - timestamp := state.GetTimestamp() - return fee.NewStaticCalculator(cfg.StaticFeeConfig, cfg.UpgradeConfig, timestamp), nil +func PickFeeCalculator(cfg *config.Config, state Chain, parentBlkTime time.Time) (fee.Calculator, error) { + return pickFeeCalculator(cfg, state, parentBlkTime, false) +} + +func PickBuildingFeeCalculator(cfg *config.Config, state Chain, parentBlkTime time.Time) (fee.Calculator, error) { + return pickFeeCalculator(cfg, state, parentBlkTime, true) +} + +func pickFeeCalculator(cfg *config.Config, state Chain, parentBlkTime time.Time, building bool) (fee.Calculator, error) { + var ( + childBlkTime = state.GetTimestamp() + isEActive = cfg.UpgradeConfig.IsEActivated(childBlkTime) + ) + + if !isEActive { + return fee.NewStaticCalculator(cfg.StaticFeeConfig, cfg.UpgradeConfig, childBlkTime), nil + } + + feesCfg, err := fee.GetDynamicConfig(isEActive) + if err != nil { + return nil, fmt.Errorf("failed retrieving dynamic fees config: %w", err) + } + currentGasCap, err := state.GetCurrentGasCap() + if err != nil { + return nil, fmt.Errorf("failed retrieving gas cap: %w", err) + } + gasCap, err := commonfee.GasCap(feesCfg, currentGasCap, parentBlkTime, childBlkTime) + if err != nil { + return nil, fmt.Errorf("failed updating gas cap: %w", err) + } + + commonFeeCalc := commonfee.NewCalculator(feesCfg.FeeDimensionWeights, feesCfg.GasPrice, gasCap) + if building { + return fee.NewBuildingDynamicCalculator(commonFeeCalc), nil + } + return fee.NewDynamicCalculator(commonFeeCalc), nil } diff --git a/vms/platformvm/state/diff.go b/vms/platformvm/state/diff.go index 91fb01d08fc9..f4fa883288ed 100644 --- a/vms/platformvm/state/diff.go +++ b/vms/platformvm/state/diff.go @@ -14,6 +14,8 @@ import ( "github.com/ava-labs/avalanchego/vms/platformvm/fx" "github.com/ava-labs/avalanchego/vms/platformvm/status" "github.com/ava-labs/avalanchego/vms/platformvm/txs" + + commonfee "github.com/ava-labs/avalanchego/vms/components/fee" ) var ( @@ -35,6 +37,8 @@ type diff struct { timestamp time.Time + currentGasCap *commonfee.Gas + // Subnet ID --> supply of native asset of the subnet currentSupply map[ids.ID]uint64 @@ -89,6 +93,31 @@ func NewDiffOn(parentState Chain) (Diff, error) { }) } +func (d *diff) GetCurrentGasCap() (commonfee.Gas, error) { + if d.currentGasCap == nil { + parentState, ok := d.stateVersions.GetState(d.parentID) + if !ok { + return commonfee.ZeroGas, fmt.Errorf("%w: %s", ErrMissingParentState, d.parentID) + } + parentCurrentGasCap, err := parentState.GetCurrentGasCap() + if err != nil { + return commonfee.ZeroGas, err + } + + d.currentGasCap = new(commonfee.Gas) + *d.currentGasCap = parentCurrentGasCap + } + + return *d.currentGasCap, nil +} + +func (d *diff) SetCurrentGasCap(gasCap commonfee.Gas) { + if d.currentGasCap == nil { + d.currentGasCap = new(commonfee.Gas) + } + *d.currentGasCap = gasCap +} + func (d *diff) GetTimestamp() time.Time { return d.timestamp } @@ -401,6 +430,9 @@ func (d *diff) DeleteUTXO(utxoID ids.ID) { func (d *diff) Apply(baseState Chain) error { baseState.SetTimestamp(d.timestamp) + if d.currentGasCap != nil { + baseState.SetCurrentGasCap(*d.currentGasCap) + } for subnetID, supply := range d.currentSupply { baseState.SetCurrentSupply(subnetID, supply) } diff --git a/vms/platformvm/state/mock_state.go b/vms/platformvm/state/mock_state.go index c1321567e6a9..dd2401056237 100644 --- a/vms/platformvm/state/mock_state.go +++ b/vms/platformvm/state/mock_state.go @@ -20,6 +20,7 @@ import ( validators "github.com/ava-labs/avalanchego/snow/validators" logging "github.com/ava-labs/avalanchego/utils/logging" avax "github.com/ava-labs/avalanchego/vms/components/avax" + fee "github.com/ava-labs/avalanchego/vms/components/fee" block "github.com/ava-labs/avalanchego/vms/platformvm/block" fx "github.com/ava-labs/avalanchego/vms/platformvm/fx" status "github.com/ava-labs/avalanchego/vms/platformvm/status" @@ -197,6 +198,21 @@ func (mr *MockChainMockRecorder) GetCurrentDelegatorIterator(arg0, arg1 any) *go return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCurrentDelegatorIterator", reflect.TypeOf((*MockChain)(nil).GetCurrentDelegatorIterator), arg0, arg1) } +// GetCurrentGasCap mocks base method. +func (m *MockChain) GetCurrentGasCap() (fee.Gas, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetCurrentGasCap") + ret0, _ := ret[0].(fee.Gas) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetCurrentGasCap indicates an expected call of GetCurrentGasCap. +func (mr *MockChainMockRecorder) GetCurrentGasCap() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCurrentGasCap", reflect.TypeOf((*MockChain)(nil).GetCurrentGasCap)) +} + // GetCurrentStakerIterator mocks base method. func (m *MockChain) GetCurrentStakerIterator() (StakerIterator, error) { m.ctrl.T.Helper() @@ -425,6 +441,18 @@ func (mr *MockChainMockRecorder) PutPendingValidator(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PutPendingValidator", reflect.TypeOf((*MockChain)(nil).PutPendingValidator), arg0) } +// SetCurrentGasCap mocks base method. +func (m *MockChain) SetCurrentGasCap(arg0 fee.Gas) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetCurrentGasCap", arg0) +} + +// SetCurrentGasCap indicates an expected call of SetCurrentGasCap. +func (mr *MockChainMockRecorder) SetCurrentGasCap(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetCurrentGasCap", reflect.TypeOf((*MockChain)(nil).SetCurrentGasCap), arg0) +} + // SetCurrentSupply mocks base method. func (m *MockChain) SetCurrentSupply(arg0 ids.ID, arg1 uint64) { m.ctrl.T.Helper() @@ -659,6 +687,21 @@ func (mr *MockDiffMockRecorder) GetCurrentDelegatorIterator(arg0, arg1 any) *gom return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCurrentDelegatorIterator", reflect.TypeOf((*MockDiff)(nil).GetCurrentDelegatorIterator), arg0, arg1) } +// GetCurrentGasCap mocks base method. +func (m *MockDiff) GetCurrentGasCap() (fee.Gas, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetCurrentGasCap") + ret0, _ := ret[0].(fee.Gas) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetCurrentGasCap indicates an expected call of GetCurrentGasCap. +func (mr *MockDiffMockRecorder) GetCurrentGasCap() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCurrentGasCap", reflect.TypeOf((*MockDiff)(nil).GetCurrentGasCap)) +} + // GetCurrentStakerIterator mocks base method. func (m *MockDiff) GetCurrentStakerIterator() (StakerIterator, error) { m.ctrl.T.Helper() @@ -887,6 +930,18 @@ func (mr *MockDiffMockRecorder) PutPendingValidator(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PutPendingValidator", reflect.TypeOf((*MockDiff)(nil).PutPendingValidator), arg0) } +// SetCurrentGasCap mocks base method. +func (m *MockDiff) SetCurrentGasCap(arg0 fee.Gas) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetCurrentGasCap", arg0) +} + +// SetCurrentGasCap indicates an expected call of SetCurrentGasCap. +func (mr *MockDiffMockRecorder) SetCurrentGasCap(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetCurrentGasCap", reflect.TypeOf((*MockDiff)(nil).SetCurrentGasCap), arg0) +} + // SetCurrentSupply mocks base method. func (m *MockDiff) SetCurrentSupply(arg0 ids.ID, arg1 uint64) { m.ctrl.T.Helper() @@ -1246,6 +1301,21 @@ func (mr *MockStateMockRecorder) GetCurrentDelegatorIterator(arg0, arg1 any) *go return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCurrentDelegatorIterator", reflect.TypeOf((*MockState)(nil).GetCurrentDelegatorIterator), arg0, arg1) } +// GetCurrentGasCap mocks base method. +func (m *MockState) GetCurrentGasCap() (fee.Gas, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetCurrentGasCap") + ret0, _ := ret[0].(fee.Gas) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetCurrentGasCap indicates an expected call of GetCurrentGasCap. +func (mr *MockStateMockRecorder) GetCurrentGasCap() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCurrentGasCap", reflect.TypeOf((*MockState)(nil).GetCurrentGasCap)) +} + // GetCurrentStakerIterator mocks base method. func (m *MockState) GetCurrentStakerIterator() (StakerIterator, error) { m.ctrl.T.Helper() @@ -1578,6 +1648,18 @@ func (mr *MockStateMockRecorder) ReindexBlocks(arg0, arg1 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReindexBlocks", reflect.TypeOf((*MockState)(nil).ReindexBlocks), arg0, arg1) } +// SetCurrentGasCap mocks base method. +func (m *MockState) SetCurrentGasCap(arg0 fee.Gas) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetCurrentGasCap", arg0) +} + +// SetCurrentGasCap indicates an expected call of SetCurrentGasCap. +func (mr *MockStateMockRecorder) SetCurrentGasCap(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetCurrentGasCap", reflect.TypeOf((*MockState)(nil).SetCurrentGasCap), arg0) +} + // SetCurrentSupply mocks base method. func (m *MockState) SetCurrentSupply(arg0 ids.ID, arg1 uint64) { m.ctrl.T.Helper() diff --git a/vms/platformvm/state/state.go b/vms/platformvm/state/state.go index 74b71dadf8a2..e40ed93d1269 100644 --- a/vms/platformvm/state/state.go +++ b/vms/platformvm/state/state.go @@ -41,8 +41,10 @@ import ( "github.com/ava-labs/avalanchego/vms/platformvm/reward" "github.com/ava-labs/avalanchego/vms/platformvm/status" "github.com/ava-labs/avalanchego/vms/platformvm/txs" + "github.com/ava-labs/avalanchego/vms/platformvm/txs/fee" safemath "github.com/ava-labs/avalanchego/utils/math" + commonfee "github.com/ava-labs/avalanchego/vms/components/fee" ) const ( @@ -83,6 +85,7 @@ var ( CurrentSupplyKey = []byte("current supply") LastAcceptedKey = []byte("last accepted") HeightsIndexedKey = []byte("heights indexed") + CurrentGasCapKey = []byte("gas cap") InitializedKey = []byte("initialized") BlocksReindexedKey = []byte("blocks reindexed") ) @@ -95,6 +98,9 @@ type Chain interface { avax.UTXOGetter avax.UTXODeleter + GetCurrentGasCap() (commonfee.Gas, error) + SetCurrentGasCap(commonfee.Gas) + GetTimestamp() time.Time SetTimestamp(tm time.Time) @@ -353,6 +359,7 @@ type state struct { // The persisted fields represent the current database value timestamp, persistedTimestamp time.Time + currentGasCap *commonfee.Gas currentSupply, persistedCurrentSupply uint64 // [lastAccepted] is the most recently accepted block. lastAccepted, persistedLastAccepted ids.ID @@ -997,6 +1004,20 @@ func (s *state) GetStartTime(nodeID ids.NodeID, subnetID ids.ID) (time.Time, err return staker.StartTime, nil } +func (s *state) GetCurrentGasCap() (commonfee.Gas, error) { + if s.currentGasCap == nil { + return commonfee.ZeroGas, nil + } + return *s.currentGasCap, nil +} + +func (s *state) SetCurrentGasCap(gasCap commonfee.Gas) { + if s.currentGasCap == nil { + s.currentGasCap = new(commonfee.Gas) + } + *s.currentGasCap = gasCap +} + func (s *state) GetTimestamp() time.Time { return s.timestamp } @@ -1287,6 +1308,30 @@ func (s *state) loadMetadata() error { s.persistedTimestamp = timestamp s.SetTimestamp(timestamp) + switch currentGasCapBytes, err := s.singletonDB.Get(CurrentGasCapKey); err { + case nil: + gas, err := database.ParseUInt64(currentGasCapBytes) + if err != nil { + return err + } + s.currentGasCap = new(commonfee.Gas) + *s.currentGasCap = commonfee.Gas(gas) + + case database.ErrNotFound: + // fork introducing dynamic fees may not be active yet, + // hence we may have never stored fees windows. Set to nil + // TODO: remove once fork is active + feesCfg, err := fee.GetDynamicConfig(true /*isEActive*/) + if err != nil { + return fmt.Errorf("failed retrieving dynamic fees config: %w", err) + } + s.currentGasCap = new(commonfee.Gas) + *s.currentGasCap = feesCfg.MaxGasPerSecond + + default: + return err + } + currentSupply, err := database.GetUInt64(s.singletonDB, CurrentSupplyKey) if err != nil { return err @@ -2261,6 +2306,13 @@ func (s *state) writeMetadata() error { } s.persistedTimestamp = s.timestamp } + + if s.currentGasCap != nil { + if err := database.PutUInt64(s.singletonDB, CurrentGasCapKey, uint64(*s.currentGasCap)); err != nil { + return fmt.Errorf("failed to write current gas cap: %w", err) + } + } + if s.persistedCurrentSupply != s.currentSupply { if err := database.PutUInt64(s.singletonDB, CurrentSupplyKey, s.currentSupply); err != nil { return fmt.Errorf("failed to write current supply: %w", err) diff --git a/vms/platformvm/txs/executor/advance_time_test.go b/vms/platformvm/txs/executor/advance_time_test.go index dcf366fa7cad..90ff022b21b3 100644 --- a/vms/platformvm/txs/executor/advance_time_test.go +++ b/vms/platformvm/txs/executor/advance_time_test.go @@ -66,7 +66,7 @@ func TestAdvanceTimeTxUpdatePrimaryNetworkStakers(t *testing.T) { onAbortState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState) + feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState, onCommitState.GetTimestamp()) require.NoError(err) executor := ProposalTxExecutor{ @@ -116,7 +116,7 @@ func TestAdvanceTimeTxTimestampTooEarly(t *testing.T) { onAbortState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState) + feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState, onCommitState.GetTimestamp()) require.NoError(err) executor := ProposalTxExecutor{ @@ -155,7 +155,7 @@ func TestAdvanceTimeTxTimestampTooLate(t *testing.T) { onAbortState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState) + feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState, onCommitState.GetTimestamp()) require.NoError(err) executor := ProposalTxExecutor{ @@ -188,7 +188,7 @@ func TestAdvanceTimeTxTimestampTooLate(t *testing.T) { onAbortState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState) + feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState, onCommitState.GetTimestamp()) require.NoError(err) executor := ProposalTxExecutor{ @@ -437,7 +437,7 @@ func TestAdvanceTimeTxUpdateStakers(t *testing.T) { onAbortState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState) + feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState, onCommitState.GetTimestamp()) require.NoError(err) executor := ProposalTxExecutor{ @@ -579,7 +579,7 @@ func TestAdvanceTimeTxRemoveSubnetValidator(t *testing.T) { onAbortState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState) + feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState, onCommitState.GetTimestamp()) require.NoError(err) executor := ProposalTxExecutor{ @@ -664,7 +664,7 @@ func TestTrackedSubnet(t *testing.T) { onAbortState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState) + feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState, onCommitState.GetTimestamp()) require.NoError(err) executor := ProposalTxExecutor{ @@ -716,7 +716,7 @@ func TestAdvanceTimeTxDelegatorStakerWeight(t *testing.T) { onAbortState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState) + feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState, onCommitState.GetTimestamp()) require.NoError(err) executor := ProposalTxExecutor{ @@ -825,7 +825,7 @@ func TestAdvanceTimeTxDelegatorStakers(t *testing.T) { onAbortState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState) + feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState, onCommitState.GetTimestamp()) require.NoError(err) executor := ProposalTxExecutor{ @@ -929,7 +929,7 @@ func TestAdvanceTimeTxAfterBanff(t *testing.T) { onAbortState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState) + feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState, onCommitState.GetTimestamp()) require.NoError(err) executor := ProposalTxExecutor{ diff --git a/vms/platformvm/txs/executor/create_chain_test.go b/vms/platformvm/txs/executor/create_chain_test.go index ce7ed5084a4d..253f0abf14cd 100644 --- a/vms/platformvm/txs/executor/create_chain_test.go +++ b/vms/platformvm/txs/executor/create_chain_test.go @@ -29,7 +29,7 @@ import ( // Ensure Execute fails when there are not enough control sigs func TestCreateChainTxInsufficientControlSigs(t *testing.T) { require := require.New(t) - env := newEnvironment(t, banff) + env := newEnvironment(t, eUpgrade) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() @@ -49,7 +49,7 @@ func TestCreateChainTxInsufficientControlSigs(t *testing.T) { require.NoError(err) // Remove a signature - tx.Creds[0].(*secp256k1fx.Credential).Sigs = tx.Creds[0].(*secp256k1fx.Credential).Sigs[1:] + tx.Creds[1].(*secp256k1fx.Credential).Sigs = tx.Creds[1].(*secp256k1fx.Credential).Sigs[1:] stateDiff, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) @@ -67,7 +67,7 @@ func TestCreateChainTxInsufficientControlSigs(t *testing.T) { // Ensure Execute fails when an incorrect control signature is given func TestCreateChainTxWrongControlSig(t *testing.T) { require := require.New(t) - env := newEnvironment(t, banff) + env := newEnvironment(t, eUpgrade) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() @@ -92,7 +92,7 @@ func TestCreateChainTxWrongControlSig(t *testing.T) { // Replace a valid signature with one from another key sig, err := key.SignHash(hashing.ComputeHash256(tx.Unsigned.Bytes())) require.NoError(err) - copy(tx.Creds[0].(*secp256k1fx.Credential).Sigs[0][:], sig) + copy(tx.Creds[1].(*secp256k1fx.Credential).Sigs[0][:], sig) stateDiff, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) @@ -111,7 +111,7 @@ func TestCreateChainTxWrongControlSig(t *testing.T) { // its validator set doesn't exist func TestCreateChainTxNoSuchSubnet(t *testing.T) { require := require.New(t) - env := newEnvironment(t, banff) + env := newEnvironment(t, eUpgrade) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() @@ -134,9 +134,15 @@ func TestCreateChainTxNoSuchSubnet(t *testing.T) { stateDiff, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) + parentBlkTime := stateDiff.GetTimestamp() + builderDiff, err := state.NewDiffOn(stateDiff) require.NoError(err) - feeCalculator, err := state.PickFeeCalculator(env.config, builderDiff) + nextBlkTime, _, err := state.NextBlockTime(stateDiff, env.clk) + require.NoError(err) + builderDiff.SetTimestamp(nextBlkTime) + + feeCalculator, err := state.PickFeeCalculator(env.config, builderDiff, parentBlkTime) require.NoError(err) executor := StandardTxExecutor{ @@ -152,7 +158,7 @@ func TestCreateChainTxNoSuchSubnet(t *testing.T) { // Ensure valid tx passes semanticVerify func TestCreateChainTxValid(t *testing.T) { require := require.New(t) - env := newEnvironment(t, banff) + env := newEnvironment(t, eUpgrade) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() @@ -173,9 +179,15 @@ func TestCreateChainTxValid(t *testing.T) { stateDiff, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) + parentBlkTime := stateDiff.GetTimestamp() + builderDiff, err := state.NewDiffOn(stateDiff) require.NoError(err) - feeCalculator, err := state.PickFeeCalculator(env.config, builderDiff) + nextBlkTime, _, err := state.NextBlockTime(stateDiff, env.clk) + require.NoError(err) + builderDiff.SetTimestamp(nextBlkTime) + + feeCalculator, err := state.PickFeeCalculator(env.config, builderDiff, parentBlkTime) require.NoError(err) executor := StandardTxExecutor{ @@ -252,7 +264,7 @@ func TestCreateChainTxAP3FeeChange(t *testing.T) { stateDiff.SetTimestamp(test.time) - feeCalculator, err := state.PickFeeCalculator(env.config, stateDiff) + feeCalculator, err := state.PickFeeCalculator(env.config, stateDiff, stateDiff.GetTimestamp()) require.NoError(err) executor := StandardTxExecutor{ diff --git a/vms/platformvm/txs/executor/create_subnet_test.go b/vms/platformvm/txs/executor/create_subnet_test.go index 524a6528dfdc..2c7931bf3fd0 100644 --- a/vms/platformvm/txs/executor/create_subnet_test.go +++ b/vms/platformvm/txs/executor/create_subnet_test.go @@ -83,7 +83,7 @@ func TestCreateSubnetTxAP3FeeChange(t *testing.T) { stateDiff.SetTimestamp(test.time) - feeCalculator, err := state.PickFeeCalculator(env.config, stateDiff) + feeCalculator, err := state.PickFeeCalculator(env.config, stateDiff, stateDiff.GetTimestamp()) require.NoError(err) executor := StandardTxExecutor{ diff --git a/vms/platformvm/txs/executor/helpers_test.go b/vms/platformvm/txs/executor/helpers_test.go index 56f20b546b8e..30f28865f0e5 100644 --- a/vms/platformvm/txs/executor/helpers_test.go +++ b/vms/platformvm/txs/executor/helpers_test.go @@ -233,6 +233,8 @@ func addSubnet(t *testing.T, env *environment) { stateDiff, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) + _, _, feeCalc, err = env.factory.NewWallet(preFundedKeys[0]) + require.NoError(err) executor := StandardTxExecutor{ Backend: &env.backend, FeeCalculator: feeCalc, diff --git a/vms/platformvm/txs/executor/import_test.go b/vms/platformvm/txs/executor/import_test.go index 8cde5756bd09..80b6947a6c4b 100644 --- a/vms/platformvm/txs/executor/import_test.go +++ b/vms/platformvm/txs/executor/import_test.go @@ -163,7 +163,7 @@ func TestNewImportTx(t *testing.T) { stateDiff.SetTimestamp(tt.timestamp) - feeCalculator, err := state.PickFeeCalculator(env.config, stateDiff) + feeCalculator, err := state.PickFeeCalculator(env.config, stateDiff, stateDiff.GetTimestamp()) require.NoError(err) verifier := StandardTxExecutor{ diff --git a/vms/platformvm/txs/executor/proposal_tx_executor_test.go b/vms/platformvm/txs/executor/proposal_tx_executor_test.go index 6415d7e5c4d4..31f934d8f10e 100644 --- a/vms/platformvm/txs/executor/proposal_tx_executor_test.go +++ b/vms/platformvm/txs/executor/proposal_tx_executor_test.go @@ -280,8 +280,9 @@ func TestProposalTxExecuteAddDelegator(t *testing.T) { onAbortState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState) + feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState, onCommitState.GetTimestamp()) require.NoError(err) + executor := ProposalTxExecutor{ OnCommitState: onCommitState, OnAbortState: onAbortState, @@ -330,7 +331,7 @@ func TestProposalTxExecuteAddSubnetValidator(t *testing.T) { onAbortState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState) + feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState, onCommitState.GetTimestamp()) require.NoError(err) executor := ProposalTxExecutor{ OnCommitState: onCommitState, @@ -372,7 +373,7 @@ func TestProposalTxExecuteAddSubnetValidator(t *testing.T) { onAbortState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState) + feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState, onCommitState.GetTimestamp()) require.NoError(err) executor := ProposalTxExecutor{ OnCommitState: onCommitState, @@ -437,7 +438,7 @@ func TestProposalTxExecuteAddSubnetValidator(t *testing.T) { onAbortState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState) + feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState, onCommitState.GetTimestamp()) require.NoError(err) executor := ProposalTxExecutor{ OnCommitState: onCommitState, @@ -494,7 +495,7 @@ func TestProposalTxExecuteAddSubnetValidator(t *testing.T) { onAbortState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState) + feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState, onCommitState.GetTimestamp()) require.NoError(err) executor := ProposalTxExecutor{ OnCommitState: onCommitState, @@ -534,7 +535,7 @@ func TestProposalTxExecuteAddSubnetValidator(t *testing.T) { onAbortState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState) + feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState, onCommitState.GetTimestamp()) require.NoError(err) executor := ProposalTxExecutor{ OnCommitState: onCommitState, @@ -574,7 +575,7 @@ func TestProposalTxExecuteAddSubnetValidator(t *testing.T) { onAbortState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState) + feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState, onCommitState.GetTimestamp()) require.NoError(err) executor := ProposalTxExecutor{ OnCommitState: onCommitState, @@ -616,7 +617,7 @@ func TestProposalTxExecuteAddSubnetValidator(t *testing.T) { onAbortState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState) + feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState, onCommitState.GetTimestamp()) require.NoError(err) executor := ProposalTxExecutor{ OnCommitState: onCommitState, @@ -693,7 +694,7 @@ func TestProposalTxExecuteAddSubnetValidator(t *testing.T) { onAbortState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState) + feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState, onCommitState.GetTimestamp()) require.NoError(err) executor := ProposalTxExecutor{ OnCommitState: onCommitState, @@ -743,7 +744,7 @@ func TestProposalTxExecuteAddSubnetValidator(t *testing.T) { onAbortState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState) + feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState, onCommitState.GetTimestamp()) require.NoError(err) executor := ProposalTxExecutor{ OnCommitState: onCommitState, @@ -788,7 +789,7 @@ func TestProposalTxExecuteAddSubnetValidator(t *testing.T) { onAbortState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState) + feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState, onCommitState.GetTimestamp()) require.NoError(err) executor := ProposalTxExecutor{ OnCommitState: onCommitState, @@ -842,7 +843,7 @@ func TestProposalTxExecuteAddSubnetValidator(t *testing.T) { onAbortState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState) + feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState, onCommitState.GetTimestamp()) require.NoError(err) executor := ProposalTxExecutor{ OnCommitState: onCommitState, @@ -894,8 +895,9 @@ func TestProposalTxExecuteAddValidator(t *testing.T) { onAbortState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState) + feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState, onCommitState.GetTimestamp()) require.NoError(err) + executor := ProposalTxExecutor{ OnCommitState: onCommitState, OnAbortState: onAbortState, @@ -938,8 +940,9 @@ func TestProposalTxExecuteAddValidator(t *testing.T) { onAbortState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState) + feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState, onCommitState.GetTimestamp()) require.NoError(err) + executor := ProposalTxExecutor{ OnCommitState: onCommitState, OnAbortState: onAbortState, @@ -996,8 +999,9 @@ func TestProposalTxExecuteAddValidator(t *testing.T) { onAbortState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState) + feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState, onCommitState.GetTimestamp()) require.NoError(err) + executor := ProposalTxExecutor{ OnCommitState: onCommitState, OnAbortState: onAbortState, @@ -1046,8 +1050,9 @@ func TestProposalTxExecuteAddValidator(t *testing.T) { onAbortState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState) + feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState, onCommitState.GetTimestamp()) require.NoError(err) + executor := ProposalTxExecutor{ OnCommitState: onCommitState, OnAbortState: onAbortState, diff --git a/vms/platformvm/txs/executor/reward_validator_test.go b/vms/platformvm/txs/executor/reward_validator_test.go index 06496220f95f..8166ecc77306 100644 --- a/vms/platformvm/txs/executor/reward_validator_test.go +++ b/vms/platformvm/txs/executor/reward_validator_test.go @@ -61,8 +61,9 @@ func TestRewardValidatorTxExecuteOnCommit(t *testing.T) { onAbortState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCalculator, err := state.PickFeeCalculator(env.config, onAbortState) + feeCalculator, err := state.PickFeeCalculator(env.config, onAbortState, onAbortState.GetTimestamp()) require.NoError(err) + txExecutor := ProposalTxExecutor{ OnCommitState: onCommitState, OnAbortState: onAbortState, @@ -166,7 +167,7 @@ func TestRewardValidatorTxExecuteOnAbort(t *testing.T) { onAbortState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCalculator, err := state.PickFeeCalculator(env.config, onAbortState) + feeCalculator, err := state.PickFeeCalculator(env.config, onAbortState, onAbortState.GetTimestamp()) require.NoError(err) txExecutor := ProposalTxExecutor{ OnCommitState: onCommitState, @@ -330,7 +331,7 @@ func TestRewardDelegatorTxExecuteOnCommitPreDelegateeDeferral(t *testing.T) { onAbortState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState) + feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState, onCommitState.GetTimestamp()) require.NoError(err) txExecutor := ProposalTxExecutor{ OnCommitState: onCommitState, @@ -479,7 +480,7 @@ func TestRewardDelegatorTxExecuteOnCommitPostDelegateeDeferral(t *testing.T) { onAbortState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState) + feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState, onCommitState.GetTimestamp()) require.NoError(err) txExecutor := ProposalTxExecutor{ OnCommitState: onCommitState, @@ -709,8 +710,9 @@ func TestRewardDelegatorTxAndValidatorTxExecuteOnCommitPostDelegateeDeferral(t * delOnAbortState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCalculator, err := state.PickFeeCalculator(env.config, delOnCommitState) + feeCalculator, err := state.PickFeeCalculator(env.config, delOnCommitState, delOnCommitState.GetTimestamp()) require.NoError(err) + txExecutor := ProposalTxExecutor{ OnCommitState: delOnCommitState, OnAbortState: delOnAbortState, @@ -878,7 +880,7 @@ func TestRewardDelegatorTxExecuteOnAbort(t *testing.T) { onAbortState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState) + feeCalculator, err := state.PickFeeCalculator(env.config, onCommitState, onCommitState.GetTimestamp()) require.NoError(err) txExecutor := ProposalTxExecutor{ OnCommitState: onCommitState, diff --git a/vms/platformvm/txs/executor/staker_tx_verification_test.go b/vms/platformvm/txs/executor/staker_tx_verification_test.go index deaf22435f77..7b38a798f9ee 100644 --- a/vms/platformvm/txs/executor/staker_tx_verification_test.go +++ b/vms/platformvm/txs/executor/staker_tx_verification_test.go @@ -102,7 +102,10 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { Creds: []verify.Verifiable{}, } ) - verifiedSignedTx.SetBytes([]byte{1}, []byte{2}) + + unsignedBytes := []byte{1} + signedBytes := []byte{2} + verifiedSignedTx.SetBytes(unsignedBytes, signedBytes) tests := []test{ { @@ -115,7 +118,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { }, stateF: func(ctrl *gomock.Controller) state.Chain { mockState := state.NewMockChain(ctrl) - mockState.EXPECT().GetTimestamp().Return(now) + mockState.EXPECT().GetTimestamp().Return(now).Times(2) return mockState }, sTxF: func() *txs.Tx { @@ -137,7 +140,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { }, stateF: func(ctrl *gomock.Controller) state.Chain { mockState := state.NewMockChain(ctrl) - mockState.EXPECT().GetTimestamp().Return(now).Times(2) // chain time is after Durango fork activation since now.After(activeForkTime) + mockState.EXPECT().GetTimestamp().Return(now).Times(3) // chain time is after Durango fork activation since now.After(activeForkTime) return mockState }, sTxF: func() *txs.Tx { @@ -161,7 +164,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { }, stateF: func(ctrl *gomock.Controller) state.Chain { state := state.NewMockChain(ctrl) - state.EXPECT().GetTimestamp().Return(verifiedTx.StartTime()).Times(2) + state.EXPECT().GetTimestamp().Return(verifiedTx.StartTime()).Times(3) return state }, sTxF: func() *txs.Tx { @@ -185,7 +188,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { }, stateF: func(ctrl *gomock.Controller) state.Chain { state := state.NewMockChain(ctrl) - state.EXPECT().GetTimestamp().Return(now).Times(2) // chain time is after latest fork activation since now.After(activeForkTime) + state.EXPECT().GetTimestamp().Return(now).Times(3) // chain time is after latest fork activation since now.After(activeForkTime) state.EXPECT().GetSubnetTransformation(subnetID).Return(&transformTx, nil) return state }, @@ -212,7 +215,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { }, stateF: func(ctrl *gomock.Controller) state.Chain { state := state.NewMockChain(ctrl) - state.EXPECT().GetTimestamp().Return(now).Times(2) // chain time is after latest fork activation since now.After(activeForkTime) + state.EXPECT().GetTimestamp().Return(now).Times(3) // chain time is after latest fork activation since now.After(activeForkTime) state.EXPECT().GetSubnetTransformation(subnetID).Return(&transformTx, nil) return state }, @@ -239,7 +242,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { }, stateF: func(ctrl *gomock.Controller) state.Chain { state := state.NewMockChain(ctrl) - state.EXPECT().GetTimestamp().Return(now).Times(2) // chain time is after latest fork activation since now.After(activeForkTime) + state.EXPECT().GetTimestamp().Return(now).Times(3) // chain time is after latest fork activation since now.After(activeForkTime) state.EXPECT().GetSubnetTransformation(subnetID).Return(&transformTx, nil) return state }, @@ -267,7 +270,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { }, stateF: func(ctrl *gomock.Controller) state.Chain { state := state.NewMockChain(ctrl) - state.EXPECT().GetTimestamp().Return(now).Times(2) // chain time is after latest fork activation since now.After(activeForkTime) + state.EXPECT().GetTimestamp().Return(now).Times(3) // chain time is after latest fork activation since now.After(activeForkTime) state.EXPECT().GetSubnetTransformation(subnetID).Return(&transformTx, nil) return state }, @@ -298,7 +301,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { }, stateF: func(ctrl *gomock.Controller) state.Chain { state := state.NewMockChain(ctrl) - state.EXPECT().GetTimestamp().Return(time.Unix(1, 0)).Times(2) // chain time is after fork activation since time.Unix(1, 0).After(activeForkTime) + state.EXPECT().GetTimestamp().Return(time.Unix(1, 0)).Times(3) // chain time is after fork activation since time.Unix(1, 0).After(activeForkTime) state.EXPECT().GetSubnetTransformation(subnetID).Return(&transformTx, nil) return state }, @@ -329,7 +332,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { }, stateF: func(ctrl *gomock.Controller) state.Chain { mockState := state.NewMockChain(ctrl) - mockState.EXPECT().GetTimestamp().Return(now).Times(2) // chain time is after latest fork activation since now.After(activeForkTime) + mockState.EXPECT().GetTimestamp().Return(now).Times(3) // chain time is after latest fork activation since now.After(activeForkTime) mockState.EXPECT().GetSubnetTransformation(subnetID).Return(&transformTx, nil) return mockState }, @@ -362,7 +365,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { }, stateF: func(ctrl *gomock.Controller) state.Chain { mockState := state.NewMockChain(ctrl) - mockState.EXPECT().GetTimestamp().Return(now).Times(2) // chain time is after latest fork activation since now.After(activeForkTime) + mockState.EXPECT().GetTimestamp().Return(now).Times(3) // chain time is after latest fork activation since now.After(activeForkTime) mockState.EXPECT().GetSubnetTransformation(subnetID).Return(&transformTx, nil) // State says validator exists mockState.EXPECT().GetCurrentValidator(subnetID, verifiedTx.NodeID()).Return(nil, nil) @@ -389,7 +392,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { }, stateF: func(ctrl *gomock.Controller) state.Chain { mockState := state.NewMockChain(ctrl) - mockState.EXPECT().GetTimestamp().Return(now).Times(3) // chain time is after latest fork activation since now.After(activeForkTime) + mockState.EXPECT().GetTimestamp().Return(now).Times(4) // chain time is after latest fork activation since now.After(activeForkTime) mockState.EXPECT().GetSubnetTransformation(subnetID).Return(&transformTx, nil) mockState.EXPECT().GetCurrentValidator(subnetID, verifiedTx.NodeID()).Return(nil, database.ErrNotFound) mockState.EXPECT().GetPendingValidator(subnetID, verifiedTx.NodeID()).Return(nil, database.ErrNotFound) @@ -436,7 +439,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { }, stateF: func(ctrl *gomock.Controller) state.Chain { mockState := state.NewMockChain(ctrl) - mockState.EXPECT().GetTimestamp().Return(now).Times(3) // chain time is after latest fork activation since now.After(activeForkTime) + mockState.EXPECT().GetTimestamp().Return(now).Times(4) // chain time is after latest fork activation since now.After(activeForkTime) mockState.EXPECT().GetSubnetTransformation(subnetID).Return(&transformTx, nil) mockState.EXPECT().GetCurrentValidator(subnetID, verifiedTx.NodeID()).Return(nil, database.ErrNotFound) mockState.EXPECT().GetPendingValidator(subnetID, verifiedTx.NodeID()).Return(nil, database.ErrNotFound) @@ -455,7 +458,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { expectedErr: ErrFlowCheckFailed, }, { - name: "success", + name: "success pre EUpgrade", backendF: func(ctrl *gomock.Controller) *Backend { bootstrapped := &utils.Atomic[bool]{} bootstrapped.Set(true) @@ -482,7 +485,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { }, stateF: func(ctrl *gomock.Controller) state.Chain { mockState := state.NewMockChain(ctrl) - mockState.EXPECT().GetTimestamp().Return(now).Times(3) // chain time is after Durango fork activation since now.After(activeForkTime) + mockState.EXPECT().GetTimestamp().Return(now).Times(4) // chain time is after Durango fork activation since now.After(activeForkTime) mockState.EXPECT().GetSubnetTransformation(subnetID).Return(&transformTx, nil) mockState.EXPECT().GetCurrentValidator(subnetID, verifiedTx.NodeID()).Return(nil, database.ErrNotFound) mockState.EXPECT().GetPendingValidator(subnetID, verifiedTx.NodeID()).Return(nil, database.ErrNotFound) @@ -513,7 +516,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { tx = tt.txF() ) - feeCalculator, err := state.PickFeeCalculator(backend.Config, chain) + feeCalculator, err := state.PickFeeCalculator(backend.Config, chain, chain.GetTimestamp()) require.NoError(t, err) err = verifyAddPermissionlessValidatorTx(backend, feeCalculator, chain, sTx, tx) diff --git a/vms/platformvm/txs/executor/standard_tx_executor_test.go b/vms/platformvm/txs/executor/standard_tx_executor_test.go index e2d3228de413..b100a8b258f0 100644 --- a/vms/platformvm/txs/executor/standard_tx_executor_test.go +++ b/vms/platformvm/txs/executor/standard_tx_executor_test.go @@ -101,7 +101,7 @@ func TestStandardTxExecutorAddValidatorTxEmptyID(t *testing.T) { stateDiff, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCalculator, err := state.PickFeeCalculator(env.config, stateDiff) + feeCalculator, err := state.PickFeeCalculator(env.config, stateDiff, stateDiff.GetTimestamp()) require.NoError(err) executor := StandardTxExecutor{ Backend: &env.backend, @@ -367,7 +367,7 @@ func TestStandardTxExecutorAddDelegator(t *testing.T) { env.config.UpgradeConfig.BanffTime = onAcceptState.GetTimestamp() - feeCalculator, err := state.PickFeeCalculator(env.config, onAcceptState) + feeCalculator, err := state.PickFeeCalculator(env.config, onAcceptState, onAcceptState.GetTimestamp()) require.NoError(err) executor := StandardTxExecutor{ Backend: &env.backend, @@ -415,7 +415,7 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { onAcceptState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCalculator, err := state.PickFeeCalculator(env.config, onAcceptState) + feeCalculator, err := state.PickFeeCalculator(env.config, onAcceptState, onAcceptState.GetTimestamp()) require.NoError(err) executor := StandardTxExecutor{ Backend: &env.backend, @@ -453,7 +453,7 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { onAcceptState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCalculator, err := state.PickFeeCalculator(env.config, onAcceptState) + feeCalculator, err := state.PickFeeCalculator(env.config, onAcceptState, onAcceptState.GetTimestamp()) require.NoError(err) executor := StandardTxExecutor{ Backend: &env.backend, @@ -513,7 +513,7 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { onAcceptState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCalculator, err := state.PickFeeCalculator(env.config, onAcceptState) + feeCalculator, err := state.PickFeeCalculator(env.config, onAcceptState, onAcceptState.GetTimestamp()) require.NoError(err) executor := StandardTxExecutor{ Backend: &env.backend, @@ -566,7 +566,7 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { onAcceptState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCalculator, err := state.PickFeeCalculator(env.config, onAcceptState) + feeCalculator, err := state.PickFeeCalculator(env.config, onAcceptState, onAcceptState.GetTimestamp()) require.NoError(err) executor := StandardTxExecutor{ Backend: &env.backend, @@ -602,7 +602,7 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { onAcceptState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCalculator, err := state.PickFeeCalculator(env.config, onAcceptState) + feeCalculator, err := state.PickFeeCalculator(env.config, onAcceptState, onAcceptState.GetTimestamp()) require.NoError(err) executor := StandardTxExecutor{ Backend: &env.backend, @@ -638,7 +638,7 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { onAcceptState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCalculator, err := state.PickFeeCalculator(env.config, onAcceptState) + feeCalculator, err := state.PickFeeCalculator(env.config, onAcceptState, onAcceptState.GetTimestamp()) require.NoError(err) executor := StandardTxExecutor{ Backend: &env.backend, @@ -677,7 +677,7 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { onAcceptState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCalculator, err := state.PickFeeCalculator(env.config, onAcceptState) + feeCalculator, err := state.PickFeeCalculator(env.config, onAcceptState, onAcceptState.GetTimestamp()) require.NoError(err) executor := StandardTxExecutor{ Backend: &env.backend, @@ -752,7 +752,7 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { onAcceptState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCalculator, err := state.PickFeeCalculator(env.config, onAcceptState) + feeCalculator, err := state.PickFeeCalculator(env.config, onAcceptState, onAcceptState.GetTimestamp()) require.NoError(err) executor := StandardTxExecutor{ Backend: &env.backend, @@ -800,7 +800,7 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { onAcceptState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCalculator, err := state.PickFeeCalculator(env.config, onAcceptState) + feeCalculator, err := state.PickFeeCalculator(env.config, onAcceptState, onAcceptState.GetTimestamp()) require.NoError(err) executor := StandardTxExecutor{ Backend: &env.backend, @@ -844,7 +844,7 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { onAcceptState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCalculator, err := state.PickFeeCalculator(env.config, onAcceptState) + feeCalculator, err := state.PickFeeCalculator(env.config, onAcceptState, onAcceptState.GetTimestamp()) require.NoError(err) executor := StandardTxExecutor{ Backend: &env.backend, @@ -886,7 +886,7 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { onAcceptState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCalculator, err := state.PickFeeCalculator(env.config, onAcceptState) + feeCalculator, err := state.PickFeeCalculator(env.config, onAcceptState, onAcceptState.GetTimestamp()) require.NoError(err) executor := StandardTxExecutor{ Backend: &env.backend, @@ -938,7 +938,7 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { onAcceptState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCalculator, err := state.PickFeeCalculator(env.config, onAcceptState) + feeCalculator, err := state.PickFeeCalculator(env.config, onAcceptState, onAcceptState.GetTimestamp()) require.NoError(err) executor := StandardTxExecutor{ Backend: &env.backend, @@ -984,7 +984,7 @@ func TestBanffStandardTxExecutorAddValidator(t *testing.T) { onAcceptState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCalculator, err := state.PickFeeCalculator(env.config, onAcceptState) + feeCalculator, err := state.PickFeeCalculator(env.config, onAcceptState, onAcceptState.GetTimestamp()) require.NoError(err) executor := StandardTxExecutor{ Backend: &env.backend, @@ -1034,7 +1034,7 @@ func TestBanffStandardTxExecutorAddValidator(t *testing.T) { onAcceptState.PutCurrentValidator(staker) onAcceptState.AddTx(tx, status.Committed) - feeCalculator, err := state.PickFeeCalculator(env.config, onAcceptState) + feeCalculator, err := state.PickFeeCalculator(env.config, onAcceptState, onAcceptState.GetTimestamp()) require.NoError(err) executor := StandardTxExecutor{ Backend: &env.backend, @@ -1081,7 +1081,7 @@ func TestBanffStandardTxExecutorAddValidator(t *testing.T) { onAcceptState.PutPendingValidator(staker) onAcceptState.AddTx(tx, status.Committed) - feeCalculator, err := state.PickFeeCalculator(env.config, onAcceptState) + feeCalculator, err := state.PickFeeCalculator(env.config, onAcceptState, onAcceptState.GetTimestamp()) require.NoError(err) executor := StandardTxExecutor{ Backend: &env.backend, @@ -1127,7 +1127,7 @@ func TestBanffStandardTxExecutorAddValidator(t *testing.T) { onAcceptState.DeleteUTXO(utxoID) } - feeCalculator, err := state.PickFeeCalculator(env.config, onAcceptState) + feeCalculator, err := state.PickFeeCalculator(env.config, onAcceptState, onAcceptState.GetTimestamp()) require.NoError(err) executor := StandardTxExecutor{ Backend: &env.backend, @@ -1236,7 +1236,7 @@ func TestDurangoDisabledTransactions(t *testing.T) { tx := tt.buildTx(env) - feeCalculator, err := state.PickFeeCalculator(env.config, onAcceptState) + feeCalculator, err := state.PickFeeCalculator(env.config, onAcceptState, onAcceptState.GetTimestamp()) require.NoError(err) err = tx.Unsigned.Visit(&StandardTxExecutor{ Backend: &env.backend, @@ -1459,7 +1459,7 @@ func TestDurangoMemoField(t *testing.T) { onAcceptState, err := state.NewDiff(env.state.GetLastAccepted(), env) require.NoError(t, err) - feeCalculator, err := state.PickFeeCalculator(env.config, onAcceptState) + feeCalculator, err := state.PickFeeCalculator(env.config, onAcceptState, onAcceptState.GetTimestamp()) require.NoError(t, err) require.NoError(t, subnetValTx.Unsigned.Visit(&StandardTxExecutor{ Backend: &env.backend, @@ -1674,7 +1674,7 @@ func TestDurangoMemoField(t *testing.T) { env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() - feeCalculator, err := state.PickFeeCalculator(env.config, env.state) + feeCalculator, err := state.PickFeeCalculator(env.config, env.state, env.state.GetTimestamp()) require.NoError(err) // Populated memo field should error @@ -1823,7 +1823,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { env.state.EXPECT().AddUTXO(gomock.Any()).Times(len(env.unsignedTx.Outs)) cfg := defaultTestConfig(t, durango, env.latestForkTime) - feeCalculator, err := state.PickFeeCalculator(cfg, env.state) + feeCalculator, err := state.PickFeeCalculator(cfg, env.state, env.state.GetTimestamp()) require.NoError(t, err) e := &StandardTxExecutor{ Backend: &Backend{ @@ -1852,7 +1852,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { env.state.EXPECT().GetTimestamp().Return(env.latestForkTime).AnyTimes() cfg := defaultTestConfig(t, durango, env.latestForkTime) - feeCalculator, err := state.PickFeeCalculator(cfg, env.state) + feeCalculator, err := state.PickFeeCalculator(cfg, env.state, env.state.GetTimestamp()) require.NoError(t, err) e := &StandardTxExecutor{ Backend: &Backend{ @@ -1881,7 +1881,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { env.state.EXPECT().GetPendingValidator(env.unsignedTx.Subnet, env.unsignedTx.NodeID).Return(nil, database.ErrNotFound) cfg := defaultTestConfig(t, durango, env.latestForkTime) - feeCalculator, err := state.PickFeeCalculator(cfg, env.state) + feeCalculator, err := state.PickFeeCalculator(cfg, env.state, env.state.GetTimestamp()) require.NoError(t, err) e := &StandardTxExecutor{ Backend: &Backend{ @@ -1913,7 +1913,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { env.state.EXPECT().GetCurrentValidator(env.unsignedTx.Subnet, env.unsignedTx.NodeID).Return(&staker, nil).Times(1) cfg := defaultTestConfig(t, durango, env.latestForkTime) - feeCalculator, err := state.PickFeeCalculator(cfg, env.state) + feeCalculator, err := state.PickFeeCalculator(cfg, env.state, env.state.GetTimestamp()) require.NoError(t, err) e := &StandardTxExecutor{ Backend: &Backend{ @@ -1943,7 +1943,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { env.state.EXPECT().GetCurrentValidator(env.unsignedTx.Subnet, env.unsignedTx.NodeID).Return(env.staker, nil) cfg := defaultTestConfig(t, durango, env.latestForkTime) - feeCalculator, err := state.PickFeeCalculator(cfg, env.state) + feeCalculator, err := state.PickFeeCalculator(cfg, env.state, env.state.GetTimestamp()) require.NoError(t, err) e := &StandardTxExecutor{ Backend: &Backend{ @@ -1972,7 +1972,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { env.state.EXPECT().GetSubnetOwner(env.unsignedTx.Subnet).Return(nil, database.ErrNotFound) cfg := defaultTestConfig(t, durango, env.latestForkTime) - feeCalculator, err := state.PickFeeCalculator(cfg, env.state) + feeCalculator, err := state.PickFeeCalculator(cfg, env.state, env.state.GetTimestamp()) require.NoError(t, err) e := &StandardTxExecutor{ Backend: &Backend{ @@ -2003,7 +2003,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { env.fx.EXPECT().VerifyPermission(gomock.Any(), env.unsignedTx.SubnetAuth, env.tx.Creds[len(env.tx.Creds)-1], subnetOwner).Return(errTest) cfg := defaultTestConfig(t, durango, env.latestForkTime) - feeCalculator, err := state.PickFeeCalculator(cfg, env.state) + feeCalculator, err := state.PickFeeCalculator(cfg, env.state, env.state.GetTimestamp()) require.NoError(t, err) e := &StandardTxExecutor{ Backend: &Backend{ @@ -2037,7 +2037,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { ).Return(errTest) cfg := defaultTestConfig(t, durango, env.latestForkTime) - feeCalculator, err := state.PickFeeCalculator(cfg, env.state) + feeCalculator, err := state.PickFeeCalculator(cfg, env.state, env.state.GetTimestamp()) require.NoError(t, err) e := &StandardTxExecutor{ Backend: &Backend{ @@ -2196,7 +2196,7 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { env.state.EXPECT().GetTimestamp().Return(env.latestForkTime).AnyTimes() cfg := defaultTestConfig(t, durango, env.latestForkTime) - feeCalculator, err := state.PickFeeCalculator(cfg, env.state) + feeCalculator, err := state.PickFeeCalculator(cfg, env.state, env.state.GetTimestamp()) require.NoError(t, err) e := &StandardTxExecutor{ Backend: &Backend{ @@ -2224,7 +2224,7 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { env.state.EXPECT().GetTimestamp().Return(env.latestForkTime).AnyTimes() cfg := defaultTestConfig(t, durango, env.latestForkTime) - feeCalculator, err := state.PickFeeCalculator(cfg, env.state) + feeCalculator, err := state.PickFeeCalculator(cfg, env.state, env.state.GetTimestamp()) require.NoError(t, err) e := &StandardTxExecutor{ Backend: &Backend{ @@ -2255,7 +2255,7 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { cfg := defaultTestConfig(t, durango, env.latestForkTime) cfg.MaxStakeDuration = math.MaxInt64 - feeCalculator, err := state.PickFeeCalculator(cfg, env.state) + feeCalculator, err := state.PickFeeCalculator(cfg, env.state, env.state.GetTimestamp()) require.NoError(t, err) e := &StandardTxExecutor{ Backend: &Backend{ @@ -2291,7 +2291,7 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { cfg := defaultTestConfig(t, durango, env.latestForkTime) cfg.MaxStakeDuration = math.MaxInt64 - feeCalculator, err := state.PickFeeCalculator(cfg, env.state) + feeCalculator, err := state.PickFeeCalculator(cfg, env.state, env.state.GetTimestamp()) require.NoError(t, err) e := &StandardTxExecutor{ Backend: &Backend{ @@ -2332,7 +2332,7 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { cfg := defaultTestConfig(t, durango, env.latestForkTime) cfg.MaxStakeDuration = math.MaxInt64 - feeCalculator, err := state.PickFeeCalculator(cfg, env.state) + feeCalculator, err := state.PickFeeCalculator(cfg, env.state, env.state.GetTimestamp()) require.NoError(t, err) e := &StandardTxExecutor{ Backend: &Backend{ diff --git a/vms/platformvm/txs/txstest/builder.go b/vms/platformvm/txs/txstest/builder.go index 7bfd7583913b..d54a316b4d78 100644 --- a/vms/platformvm/txs/txstest/builder.go +++ b/vms/platformvm/txs/txstest/builder.go @@ -4,6 +4,8 @@ package txstest import ( + "fmt" + "github.com/ava-labs/avalanchego/snow" "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" "github.com/ava-labs/avalanchego/utils/timer/mockable" @@ -52,5 +54,17 @@ func (w *WalletFactory) NewWallet(keys ...*secp256k1.PrivateKey) (builder.Builde } func (w *WalletFactory) FeeCalculator() (fee.Calculator, error) { - return state.PickFeeCalculator(w.cfg, w.state) + parentBlkTime := w.state.GetTimestamp() + nextBlkTime, _, err := state.NextBlockTime(w.state, w.clk) + if err != nil { + return nil, fmt.Errorf("failed calculating next block time: %w", err) + } + + diff, err := state.NewDiffOn(w.state) + if err != nil { + return nil, fmt.Errorf("failed building diff: %w", err) + } + diff.SetTimestamp(nextBlkTime) + + return state.PickBuildingFeeCalculator(w.cfg, diff, parentBlkTime) } diff --git a/vms/platformvm/vm.go b/vms/platformvm/vm.go index 203688d23136..2fdc52fd5343 100644 --- a/vms/platformvm/vm.go +++ b/vms/platformvm/vm.go @@ -39,6 +39,7 @@ import ( "github.com/ava-labs/avalanchego/vms/platformvm/reward" "github.com/ava-labs/avalanchego/vms/platformvm/state" "github.com/ava-labs/avalanchego/vms/platformvm/txs" + "github.com/ava-labs/avalanchego/vms/platformvm/txs/fee" "github.com/ava-labs/avalanchego/vms/platformvm/utxo" "github.com/ava-labs/avalanchego/vms/secp256k1fx" "github.com/ava-labs/avalanchego/vms/txs/mempool" @@ -111,7 +112,11 @@ func (vm *VM) Initialize( if err != nil { return err } - chainCtx.Log.Info("using VM execution config", zap.Reflect("config", execConfig)) + chainCtx.Log.Info("retrieved VM execution config", zap.Reflect("config", execConfig)) + + if err := fee.ResetDynamicConfig(chainCtx, execConfig.DynamicFeesConfig); err != nil { + return fmt.Errorf("failed resetting dynamic fees config: %w", err) + } registerer, err := metrics.MakeAndRegister(chainCtx.Metrics, "") if err != nil { diff --git a/vms/platformvm/vm_test.go b/vms/platformvm/vm_test.go index 6de34579b53f..be2c1c3aa168 100644 --- a/vms/platformvm/vm_test.go +++ b/vms/platformvm/vm_test.go @@ -84,7 +84,7 @@ const ( durango eUpgrade - latestFork = durango + latestFork fork = eUpgrade defaultWeight uint64 = 10000 ) @@ -368,7 +368,7 @@ func defaultVM(t *testing.T, f fork) (*VM, *txstest.WalletFactory, database.Data // Ensure genesis state is parsed from bytes and stored correctly func TestGenesis(t *testing.T) { require := require.New(t) - vm, _, _, _ := defaultVM(t, latestFork) + vm, _, _, _ := defaultVM(t, durango) vm.ctx.Lock.Lock() defer vm.ctx.Lock.Unlock() @@ -404,7 +404,7 @@ func TestGenesis(t *testing.T) { // we use the first key to fund a subnet creation in [defaultGenesis]. // As such we need to account for the subnet creation fee - feeCalc, err := state.PickFeeCalculator(&vm.Config, vm.state) + feeCalc, err := testReplayFeeCalculator(&vm.Config, defaultGenesisTime, vm.state) require.NoError(err) fee, err := feeCalc.CalculateFee(&txs.Tx{Unsigned: testSubnet1.Unsigned, Creds: testSubnet1.Creds}) require.NoError(err) @@ -2148,7 +2148,7 @@ func TestRemovePermissionedValidatorDuringAddPending(t *testing.T) { validatorStartTime := latestForkTime.Add(txexecutor.SyncBound).Add(1 * time.Second) validatorEndTime := validatorStartTime.Add(360 * 24 * time.Hour) - vm, factory, _, _ := defaultVM(t, latestFork) + vm, factory, _, _ := defaultVM(t, durango) vm.ctx.Lock.Lock() defer vm.ctx.Lock.Unlock() @@ -2389,7 +2389,7 @@ func TestBaseTx(t *testing.T) { vm.ctx.Lock.Lock() defer vm.ctx.Lock.Unlock() - sendAmt := uint64(100000) + sendAmt := uint64(100_000) changeAddr := ids.ShortEmpty builder, txSigner, feeCalc, err := factory.NewWallet(keys[0]) @@ -2453,7 +2453,7 @@ func TestBaseTx(t *testing.T) { } require.Equal(totalOutputAmt, key0OutputAmt+key1OutputAmt+changeAddrOutputAmt) - feeCalc, err = state.PickFeeCalculator(&vm.Config, vm.state) + feeCalc, err = state.PickFeeCalculator(&vm.Config, vm.state, vm.state.GetTimestamp()) require.NoError(err) fee, err := feeCalc.CalculateFee(baseTx) @@ -2478,7 +2478,7 @@ func TestBaseTx(t *testing.T) { func TestPruneMempool(t *testing.T) { require := require.New(t) - vm, factory, _, _ := defaultVM(t, latestFork) + vm, factory, _, _ := defaultVM(t, durango) vm.ctx.Lock.Lock() defer vm.ctx.Lock.Unlock() diff --git a/wallet/chain/p/wallet.go b/wallet/chain/p/wallet.go index a7ed2d95985e..ed0602debd3a 100644 --- a/wallet/chain/p/wallet.go +++ b/wallet/chain/p/wallet.go @@ -8,6 +8,7 @@ import ( "time" "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/version" "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/platformvm" "github.com/ava-labs/avalanchego/vms/platformvm/txs" @@ -307,7 +308,10 @@ func (w *wallet) IssueBaseTx( outputs []*avax.TransferableOutput, options ...common.Option, ) (*txs.Tx, error) { - feeCalc := w.feeCalculator(w.builder.Context(), options...) + feeCalc, err := w.feeCalculator(w.builder.Context(), options...) + if err != nil { + return nil, err + } utx, err := w.builder.NewBaseTx(outputs, feeCalc, options...) if err != nil { @@ -323,7 +327,10 @@ func (w *wallet) IssueAddValidatorTx( shares uint32, options ...common.Option, ) (*txs.Tx, error) { - feeCalc := w.feeCalculator(w.builder.Context(), options...) + feeCalc, err := w.feeCalculator(w.builder.Context(), options...) + if err != nil { + return nil, err + } utx, err := w.builder.NewAddValidatorTx(vdr, rewardsOwner, shares, feeCalc, options...) if err != nil { @@ -336,7 +343,10 @@ func (w *wallet) IssueAddSubnetValidatorTx( vdr *txs.SubnetValidator, options ...common.Option, ) (*txs.Tx, error) { - feeCalc := w.feeCalculator(w.builder.Context(), options...) + feeCalc, err := w.feeCalculator(w.builder.Context(), options...) + if err != nil { + return nil, err + } utx, err := w.builder.NewAddSubnetValidatorTx(vdr, feeCalc, options...) if err != nil { @@ -351,7 +361,10 @@ func (w *wallet) IssueRemoveSubnetValidatorTx( subnetID ids.ID, options ...common.Option, ) (*txs.Tx, error) { - feeCalc := w.feeCalculator(w.builder.Context(), options...) + feeCalc, err := w.feeCalculator(w.builder.Context(), options...) + if err != nil { + return nil, err + } utx, err := w.builder.NewRemoveSubnetValidatorTx(nodeID, subnetID, feeCalc, options...) if err != nil { @@ -366,7 +379,10 @@ func (w *wallet) IssueAddDelegatorTx( rewardsOwner *secp256k1fx.OutputOwners, options ...common.Option, ) (*txs.Tx, error) { - feeCalc := w.feeCalculator(w.builder.Context(), options...) + feeCalc, err := w.feeCalculator(w.builder.Context(), options...) + if err != nil { + return nil, err + } utx, err := w.builder.NewAddDelegatorTx(vdr, rewardsOwner, feeCalc, options...) if err != nil { @@ -383,7 +399,10 @@ func (w *wallet) IssueCreateChainTx( chainName string, options ...common.Option, ) (*txs.Tx, error) { - feeCalc := w.feeCalculator(w.builder.Context(), options...) + feeCalc, err := w.feeCalculator(w.builder.Context(), options...) + if err != nil { + return nil, err + } utx, err := w.builder.NewCreateChainTx(subnetID, genesis, vmID, fxIDs, chainName, feeCalc, options...) if err != nil { @@ -397,7 +416,10 @@ func (w *wallet) IssueCreateSubnetTx( owner *secp256k1fx.OutputOwners, options ...common.Option, ) (*txs.Tx, error) { - feeCalc := w.feeCalculator(w.builder.Context(), options...) + feeCalc, err := w.feeCalculator(w.builder.Context(), options...) + if err != nil { + return nil, err + } utx, err := w.builder.NewCreateSubnetTx(owner, feeCalc, options...) if err != nil { @@ -411,7 +433,10 @@ func (w *wallet) IssueTransferSubnetOwnershipTx( owner *secp256k1fx.OutputOwners, options ...common.Option, ) (*txs.Tx, error) { - feeCalc := w.feeCalculator(w.builder.Context(), options...) + feeCalc, err := w.feeCalculator(w.builder.Context(), options...) + if err != nil { + return nil, err + } utx, err := w.builder.NewTransferSubnetOwnershipTx(subnetID, owner, feeCalc, options...) if err != nil { @@ -425,7 +450,10 @@ func (w *wallet) IssueImportTx( to *secp256k1fx.OutputOwners, options ...common.Option, ) (*txs.Tx, error) { - feeCalc := w.feeCalculator(w.builder.Context(), options...) + feeCalc, err := w.feeCalculator(w.builder.Context(), options...) + if err != nil { + return nil, err + } utx, err := w.builder.NewImportTx(sourceChainID, to, feeCalc, options...) if err != nil { @@ -440,7 +468,10 @@ func (w *wallet) IssueExportTx( outputs []*avax.TransferableOutput, options ...common.Option, ) (*txs.Tx, error) { - feeCalc := w.feeCalculator(w.builder.Context(), options...) + feeCalc, err := w.feeCalculator(w.builder.Context(), options...) + if err != nil { + return nil, err + } utx, err := w.builder.NewExportTx(chainID, outputs, feeCalc, options...) if err != nil { @@ -467,7 +498,10 @@ func (w *wallet) IssueTransformSubnetTx( uptimeRequirement uint32, options ...common.Option, ) (*txs.Tx, error) { - feeCalc := w.feeCalculator(w.builder.Context(), options...) + feeCalc, err := w.feeCalculator(w.builder.Context(), options...) + if err != nil { + return nil, err + } utx, err := w.builder.NewTransformSubnetTx( subnetID, @@ -503,7 +537,10 @@ func (w *wallet) IssueAddPermissionlessValidatorTx( shares uint32, options ...common.Option, ) (*txs.Tx, error) { - feeCalc := w.feeCalculator(w.builder.Context(), options...) + feeCalc, err := w.feeCalculator(w.builder.Context(), options...) + if err != nil { + return nil, err + } utx, err := w.builder.NewAddPermissionlessValidatorTx( vdr, @@ -528,7 +565,10 @@ func (w *wallet) IssueAddPermissionlessDelegatorTx( rewardsOwner *secp256k1fx.OutputOwners, options ...common.Option, ) (*txs.Tx, error) { - feeCalc := w.feeCalculator(w.builder.Context(), options...) + feeCalc, err := w.feeCalculator(w.builder.Context(), options...) + if err != nil { + return nil, err + } utx, err := w.builder.NewAddPermissionlessDelegatorTx( vdr, @@ -584,52 +624,48 @@ func (w *wallet) IssueTx( return w.Backend.AcceptTx(ctx, tx) } -func (w *wallet) feeCalculator(ctx *builder.Context, options ...common.Option) fee.Calculator { - w.refreshFeesData(ctx, options...) +func (w *wallet) feeCalculator(ctx *builder.Context, options ...common.Option) (fee.Calculator, error) { + if err := w.refreshFeesData(ctx, options...); err != nil { + return nil, err + } if !w.isEUpgradeActive { - return fee.NewStaticCalculator(w.staticFeesConfig, upgrade.Config{}, time.Time{}) + return fee.NewStaticCalculator(w.staticFeesConfig, upgrade.Config{}, time.Time{}), nil } - return fee.NewBuildingDynamicCalculator(commonfee.NewCalculator(w.feeCfg.FeeDimensionWeights, w.gasPrice, w.gasCap)) + return fee.NewBuildingDynamicCalculator(commonfee.NewCalculator(w.feeCfg.FeeDimensionWeights, w.gasPrice, w.gasCap)), nil } -func (w *wallet) refreshFeesData(ctx *builder.Context, _ ...common.Option) { - // TODO: until we wire in dynamic fees verification, we should build txs as if all it's static fees - // (at least for e2e tests) - - // var ( - // ops = common.NewOptions(options) - // opsCtx = ops.Context() - // ) - - // chainTime, err := w.client.GetTimestamp(opsCtx) - // if err != nil { - // return err - // } - // eUpgradeTime := version.GetEUpgradeTime(w.builder.Context().NetworkID) - // isEUpgradeActive := !chainTime.Before(eUpgradeTime) - - // // update static and dynamic fees configs if needed - // switch { - // case !isEUpgradeActive: - // w.staticFeesConfig = staticFeesConfigFromContext(ctx) - // w.isEUpgradeActive = isEUpgradeActive - // return nil - // case !w.isEUpgradeActive && isEUpgradeActive: - // w.feeCfg, err = w.client.GetDynamicFeeConfig(opsCtx) - // if err != nil { - // return err - // } - // w.isEUpgradeActive = isEUpgradeActive - // default: - // // nothing to do - // } - // w.gasPrice, w.gasCap, err = w.client.GetNextGasData(opsCtx) - // return err - - w.staticFeesConfig = staticFeesConfigFromContext(ctx) - w.isEUpgradeActive = false +func (w *wallet) refreshFeesData(ctx *builder.Context, options ...common.Option) error { + var ( + ops = common.NewOptions(options) + opsCtx = ops.Context() + ) + + chainTime, err := w.client.GetTimestamp(opsCtx) + if err != nil { + return err + } + eUpgradeTime := version.GetEUpgradeTime(w.builder.Context().NetworkID) + isEUpgradeActive := !chainTime.Before(eUpgradeTime) + + // update static and dynamic fees configs if needed + switch { + case !isEUpgradeActive: + w.staticFeesConfig = staticFeesConfigFromContext(ctx) + w.isEUpgradeActive = isEUpgradeActive + return nil + case !w.isEUpgradeActive && isEUpgradeActive: + w.feeCfg, err = w.client.GetDynamicFeeConfig(opsCtx) + if err != nil { + return err + } + w.isEUpgradeActive = isEUpgradeActive + default: + // nothing to do + } + w.gasPrice, w.gasCap, err = w.client.GetNextGasData(opsCtx) + return err } func staticFeesConfigFromContext(ctx *builder.Context) fee.StaticConfig {