diff --git a/tests/e2e/p/workflow.go b/tests/e2e/p/workflow.go index 650b55f162ed..6ab1816fcc03 100644 --- a/tests/e2e/p/workflow.go +++ b/tests/e2e/p/workflow.go @@ -59,6 +59,11 @@ 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 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) staticFees, err := infoClient.GetTxFee(e2e.DefaultContext()) @@ -161,7 +166,7 @@ var _ = e2e.DescribePChain("[Workflow]", func() { require.NoError(err) // retrieve fees paid for the tx - feeCalc := fee.NewDynamicCalculator(commonfee.NewCalculator(nextGasPrice, nextGasCap)) + feeCalc := fee.NewDynamicCalculator(commonfee.NewCalculator(feeCfg.FeeDimensionWeights, nextGasPrice, nextGasCap)) pChainExportFee, err = feeCalc.CalculateFee(tx) require.NoError(err) }) diff --git a/vms/components/fee/calculator.go b/vms/components/fee/calculator.go index 2a43e233186c..0aa0a09ee713 100644 --- a/vms/components/fee/calculator.go +++ b/vms/components/fee/calculator.go @@ -18,25 +18,33 @@ var errGasBoundBreached = errors.New("gas bound breached") // Calculator performs fee-related operations that are share move P-chain and X-chain // Calculator is supposed to be embedded with chain specific calculators. type Calculator struct { + // feeWeights help consolidating complexity into gas + feeWeights Dimensions + // gas cap enforced with adding gas via CumulateGas gasCap Gas // Avax denominated gas price, i.e. fee per unit of complexity. gasPrice GasPrice - // blockGas helps aggregating the gas consumed in a single block + // cumulatedGas helps aggregating the gas consumed in a single block // so that we can verify it's not too big/build it properly. - blockGas Gas + cumulatedGas Gas + + // latestTxComplexity tracks complexity of latest tx being processed. + // latestTxComplexity is especially helpful while building a tx. + latestTxComplexity Dimensions // currentExcessGas stores current excess gas, cumulated over time // to be updated once a block is accepted with cumulatedGas currentExcessGas Gas } -func NewCalculator(gasPrice GasPrice, gasCap Gas) *Calculator { +func NewCalculator(feeWeights Dimensions, gasPrice GasPrice, gasCap Gas) *Calculator { return &Calculator{ - gasCap: gasCap, - gasPrice: gasPrice, + feeWeights: feeWeights, + gasCap: gasCap, + gasPrice: gasPrice, } } @@ -46,6 +54,7 @@ func NewUpdatedManager( parentBlkTime, childBlkTime time.Time, ) (*Calculator, error) { res := &Calculator{ + feeWeights: feesConfig.FeeDimensionWeights, gasCap: gasCap, currentExcessGas: currentExcessGas, } @@ -82,63 +91,78 @@ func (c *Calculator) GetGasPrice() GasPrice { return c.gasPrice } -func (c *Calculator) GetBlockGas() Gas { - return c.blockGas +func (c *Calculator) GetBlockGas() (Gas, error) { + txGas, err := ToGas(c.feeWeights, c.latestTxComplexity) + if err != nil { + return ZeroGas, err + } + return c.cumulatedGas + txGas, nil } func (c *Calculator) GetGasCap() Gas { return c.gasCap } -func (c *Calculator) GetExcessGas() Gas { - return c.currentExcessGas -} - -// CalculateFee must be a stateless method -func (c *Calculator) CalculateFee(g Gas) (uint64, error) { - return safemath.Mul64(uint64(c.gasPrice), uint64(g)) +func (c *Calculator) GetExcessGas() (Gas, error) { + g, err := safemath.Add64(uint64(c.currentExcessGas), uint64(c.cumulatedGas)) + if err != nil { + return ZeroGas, err + } + return Gas(g), nil } -// CumulateGas tries to cumulate the consumed gas [units]. Before +// CumulateComplexity tries to cumulate the consumed gas [units]. Before // actually cumulating it, it checks whether the result would breach [bounds]. // If so, it returns the first dimension to breach bounds. -func (c *Calculator) CumulateGas(gas Gas) error { +func (c *Calculator) CumulateComplexity(complexity Dimensions) error { // Ensure we can consume (don't want partial update of values) - blkGas, err := safemath.Add64(uint64(c.blockGas), uint64(gas)) + uc, err := Add(c.latestTxComplexity, complexity) if err != nil { return fmt.Errorf("%w: %w", errGasBoundBreached, err) } - if Gas(blkGas) > c.gasCap { - return errGasBoundBreached - } - - excessGas, err := safemath.Add64(uint64(c.currentExcessGas), uint64(gas)) + totalGas, err := c.GetBlockGas() if err != nil { return fmt.Errorf("%w: %w", errGasBoundBreached, err) } + if totalGas > c.gasCap { + return fmt.Errorf("%w: %w", errGasBoundBreached, err) + } - c.blockGas = Gas(blkGas) - c.currentExcessGas = Gas(excessGas) + c.latestTxComplexity = uc return nil } // Sometimes, e.g. while building a tx, we'd like freedom to speculatively add complexity // and to remove it later on. [RemoveGas] grants this freedom -func (c *Calculator) RemoveGas(gasToRm Gas) error { - rBlkdGas, err := safemath.Sub(c.blockGas, gasToRm) +func (c *Calculator) RemoveComplexity(complexity Dimensions) error { + rc, err := Remove(c.latestTxComplexity, complexity) if err != nil { - return fmt.Errorf("%w: current Gas %d, gas to revert %d", err, c.blockGas, gasToRm) + return fmt.Errorf("%w: current Gas %d, gas to revert %d", err, c.cumulatedGas, complexity) } - rExcessGas, err := safemath.Sub(c.currentExcessGas, gasToRm) + c.latestTxComplexity = rc + return nil +} + +// DoneWithLatestTx should be invoked one a tx has been fully processed, before moving to the next one +func (c *Calculator) DoneWithLatestTx() error { + txGas, err := ToGas(c.feeWeights, c.latestTxComplexity) if err != nil { - return fmt.Errorf("%w: current Excess gas %d, gas to revert %d", err, c.currentExcessGas, gasToRm) + return err } - - c.blockGas = rBlkdGas - c.currentExcessGas = rExcessGas + c.cumulatedGas += txGas + c.latestTxComplexity = Empty return nil } +// CalculateFee must be a stateless method +func (c *Calculator) GetLatestTxFee() (uint64, error) { + gas, err := ToGas(c.feeWeights, c.latestTxComplexity) + if err != nil { + return 0, err + } + return safemath.Mul64(uint64(c.gasPrice), uint64(gas)) +} + // fakeExponential approximates factor * e ** (numerator / denominator) using // Taylor expansion. func fakeExponential(f GasPrice, n, d Gas) GasPrice { diff --git a/vms/components/fee/dimensions.go b/vms/components/fee/dimensions.go index 7c5e14f785e2..286dc29813f0 100644 --- a/vms/components/fee/dimensions.go +++ b/vms/components/fee/dimensions.go @@ -42,8 +42,20 @@ func Add(lhs, rhs Dimensions) (Dimensions, error) { return res, nil } +func Remove(lhs, rhs Dimensions) (Dimensions, error) { + var res Dimensions + for i := 0; i < FeeDimensions; i++ { + v, err := safemath.Sub(lhs[i], rhs[i]) + if err != nil { + return res, err + } + res[i] = v + } + return res, nil +} + func ToGas(weights, dimensions Dimensions) (Gas, error) { - var res uint64 + res := uint64(0) for i := 0; i < FeeDimensions; i++ { v, err := safemath.Mul64(weights[i], dimensions[i]) if err != nil { @@ -54,5 +66,5 @@ func ToGas(weights, dimensions Dimensions) (Gas, error) { return ZeroGas, err } } - return Gas(res), nil + return Gas(res) / 10, nil } diff --git a/vms/components/fee/manager_test.go b/vms/components/fee/manager_test.go index 15b4896b7df3..c2d7b876cf22 100644 --- a/vms/components/fee/manager_test.go +++ b/vms/components/fee/manager_test.go @@ -155,12 +155,11 @@ func TestPChainGasPriceIncreaseDueToPeak(t *testing.T) { ) // at peak the total fee should be no more than 100 Avax. - childGas, err := ToGas(testDynamicFeeCfg.FeeDimensionWeights, childBlkData.complexity) - require.NoError(err) - - fee, err := m.CalculateFee(childGas) + require.NoError(m.CumulateComplexity(childBlkData.complexity)) + fee, err := m.GetLatestTxFee() require.NoError(err) require.Less(fee, 100*units.Avax, fmt.Sprintf("iteration: %d, total: %d", i, len(blockComplexities))) + require.NoError(m.DoneWithLatestTx()) peakGasPrice = m.GetGasPrice() } diff --git a/vms/platformvm/block/builder/builder.go b/vms/platformvm/block/builder/builder.go index 15c851f4117a..7501e2dfb6c2 100644 --- a/vms/platformvm/block/builder/builder.go +++ b/vms/platformvm/block/builder/builder.go @@ -375,10 +375,18 @@ func packBlockTxs( // pre e upgrade is active, we fill blocks till a target size // post e upgrade is active, we fill blocks till a target gas - targetSizeReached := (!isEActive && txSize > remainingSize) || - (isEActive && feeCalculator.GetBlockGas() >= gasCap) - if targetSizeReached { - break + if !isEActive { + if txSize > remainingSize { + break + } + } else { + blkGas, err := feeCalculator.GetBlockGas() + if err != nil { + return nil, err + } + if blkGas >= gasCap { + break + } } mempool.Remove(tx) diff --git a/vms/platformvm/block/executor/verifier.go b/vms/platformvm/block/executor/verifier.go index 0d8b13899e17..ff0295998442 100644 --- a/vms/platformvm/block/executor/verifier.go +++ b/vms/platformvm/block/executor/verifier.go @@ -421,7 +421,15 @@ func (v *verifier) proposalBlock( return err } - blkGas := feeCalculator.GetBlockGas() + blkGas, err := feeCalculator.GetBlockGas() + if err != nil { + return err + } + excessGas, err := feeCalculator.GetExcessGas() + if err != nil { + return err + } + if feeCalculator.IsEActive() { nextGasCap := commonfee.UpdateGasCap(currentGasCap, blkGas) onCommitState.SetCurrentGasCap(nextGasCap) @@ -451,7 +459,7 @@ func (v *verifier) proposalBlock( // always be the same as the Banff Proposal Block. timestamp: onAbortState.GetTimestamp(), blockGas: blkGas, - excessGas: feeCalculator.GetExcessGas(), + excessGas: excessGas, atomicRequests: atomicRequests, } return nil @@ -477,7 +485,15 @@ func (v *verifier) standardBlock( blkID := b.ID() - blkGas := feeCalculator.GetBlockGas() + blkGas, err := feeCalculator.GetBlockGas() + if err != nil { + return err + } + excessGas, err := feeCalculator.GetExcessGas() + if err != nil { + return err + } + if feeCalculator.IsEActive() { nextGasCap := commonfee.UpdateGasCap(currentGasCap, blkGas) onAcceptState.SetCurrentGasCap(nextGasCap) @@ -491,7 +507,7 @@ func (v *verifier) standardBlock( timestamp: onAcceptState.GetTimestamp(), blockGas: blkGas, - excessGas: feeCalculator.GetExcessGas(), + excessGas: excessGas, inputs: inputs, atomicRequests: atomicRequests, } @@ -558,7 +574,11 @@ func (v *verifier) processStandardTxs( } if v.txExecutorBackend.Config.UpgradeConfig.IsEActivated(state.GetTimestamp()) { - state.SetExcessGas(feeCalculator.GetExcessGas()) + excessGas, err := feeCalculator.GetExcessGas() + if err != nil { + return nil, nil, nil, err + } + state.SetExcessGas(excessGas) } if numFuncs := len(funcs); numFuncs == 1 { diff --git a/vms/platformvm/client.go b/vms/platformvm/client.go index 5e2fbf72f16e..49369b7c9af9 100644 --- a/vms/platformvm/client.go +++ b/vms/platformvm/client.go @@ -123,6 +123,9 @@ type Client interface { GetBlock(ctx context.Context, blockID ids.ID, options ...rpc.Option) ([]byte, error) // GetBlockByHeight returns the block at the given [height]. GetBlockByHeight(ctx context.Context, height uint64, options ...rpc.Option) ([]byte, error) + + // GetDynamicFeeConfig returns DynamicFeesConfig + GetDynamicFeeConfig(ctx context.Context, options ...rpc.Option) (commonfee.DynamicFeesConfig, error) // GetNextGasData returns the gas price that a transaction must pay to be accepted now // and the gas cap, i.e. the maximum gas a transactions can consume GetNextGasData(ctx context.Context, options ...rpc.Option) (commonfee.GasPrice, commonfee.Gas, error) @@ -549,6 +552,12 @@ func AwaitTxAccepted( } } +func (c *client) GetDynamicFeeConfig(ctx context.Context, options ...rpc.Option) (commonfee.DynamicFeesConfig, error) { + res := &DynamicFeesConfigReply{} + err := c.requester.SendRequest(ctx, "platform.getDynamicFeeConfig", struct{}{}, res, options...) + return res.DynamicFeesConfig, err +} + func (c *client) GetNextGasData(ctx context.Context, options ...rpc.Option) (commonfee.GasPrice, commonfee.Gas, error) { res := &GetGasPriceReply{} err := c.requester.SendRequest(ctx, "platform.getNextGasData", struct{}{}, res, options...) diff --git a/vms/platformvm/service.go b/vms/platformvm/service.go index deefaafad2d2..d0cd3da96f53 100644 --- a/vms/platformvm/service.go +++ b/vms/platformvm/service.go @@ -36,6 +36,7 @@ import ( "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/secp256k1fx" avajson "github.com/ava-labs/avalanchego/utils/json" @@ -1829,6 +1830,36 @@ func (s *Service) GetBlockByHeight(_ *http.Request, args *api.GetBlockByHeightAr return err } +// DynamicFeesConfigReply is the response from GetDynamicFeeConfig +type DynamicFeesConfigReply struct { + commonfee.DynamicFeesConfig `json:"nextGasPrice"` +} + +// GetNextFeeRates returns the next fee rates that a transaction must pay to be accepted now +func (s *Service) GetDynamicFeeConfig(_ *http.Request, _ *struct{}, reply *DynamicFeesConfigReply) error { + s.vm.ctx.Log.Debug("API called", + zap.String("service", "platform"), + zap.String("method", "getDynamicFeeConfig"), + ) + + s.vm.ctx.Lock.Lock() + defer s.vm.ctx.Lock.Unlock() + + chainTime := s.vm.state.GetTimestamp() + isEActive := s.vm.Config.UpgradeConfig.IsEActivated(chainTime) + cfg, err := fee.GetDynamicConfig(isEActive) + switch err { + case fee.ErrDynamicFeeConfigNotAvailable: + reply.DynamicFeesConfig = commonfee.DynamicFeesConfig{} + return nil + case nil: + reply.DynamicFeesConfig = cfg + return nil + default: + return err + } +} + // GetGasPriceReply is the response from GetFeeRates type GetGasPriceReply struct { NextGasPrice commonfee.GasPrice `json:"nextGasPrice"` diff --git a/vms/platformvm/service_test.go b/vms/platformvm/service_test.go index 15c0903072a9..634a1768af4d 100644 --- a/vms/platformvm/service_test.go +++ b/vms/platformvm/service_test.go @@ -1223,7 +1223,7 @@ func TestGetFeeRates(t *testing.T) { // let time tick. Fee rates will go down service.vm.ctx.Lock.Lock() - now = now.Add(3 * time.Second) + now = now.Add(10 * time.Second) service.vm.clock.Set(now) service.vm.ctx.Lock.Unlock() diff --git a/vms/platformvm/state/chain_time_helpers.go b/vms/platformvm/state/chain_time_helpers.go index 46cef61e4604..435331e082c5 100644 --- a/vms/platformvm/state/chain_time_helpers.go +++ b/vms/platformvm/state/chain_time_helpers.go @@ -76,6 +76,14 @@ func GetNextStakerChangeTime(state Chain) (time.Time, error) { // [PickFeeCalculator] creates either a static or a dynamic fee calculator, depending on the active upgrade // [PickFeeCalculator] does not modify [state] 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) @@ -95,7 +103,10 @@ func PickFeeCalculator(cfg *config.Config, state Chain, parentBlkTime time.Time) return nil, fmt.Errorf("failed updating fee manager: %w", err) } - return fee.NewDynamicCalculator(feesMan), nil + if !building { + return fee.NewDynamicCalculator(feesMan), nil + } + return fee.NewBuildingDynamicCalculator(feesMan), nil } func updatedFeeManager(feesCfg commonfee.DynamicFeesConfig, state Chain, parentBlkTime, childBlkTime time.Time) (*commonfee.Calculator, error) { 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/fee/calculator.go b/vms/platformvm/txs/fee/calculator.go index 1b4fd2b6de76..fe544d625e2a 100644 --- a/vms/platformvm/txs/fee/calculator.go +++ b/vms/platformvm/txs/fee/calculator.go @@ -18,8 +18,8 @@ type Calculator interface { AddFeesFor(complexity fee.Dimensions) (uint64, error) RemoveFeesFor(unitsToRm fee.Dimensions) (uint64, error) GetGasPrice() fee.GasPrice - GetBlockGas() fee.Gas - GetExcessGas() fee.Gas + GetBlockGas() (fee.Gas, error) + GetExcessGas() (fee.Gas, error) GetGasCap() fee.Gas setCredentials(creds []verify.Verifiable) IsEActive() bool diff --git a/vms/platformvm/txs/fee/calculator_test.go b/vms/platformvm/txs/fee/calculator_test.go index 154ce7f5ae0a..3fe578df7220 100644 --- a/vms/platformvm/txs/fee/calculator_test.go +++ b/vms/platformvm/txs/fee/calculator_test.go @@ -29,8 +29,8 @@ import ( ) var ( - testGasPrice = fee.GasPrice(10 * units.NanoAvax) - + testFeeWeights = fee.Dimensions{1, 1, 1, 1} + testGasPrice = fee.GasPrice(10 * units.NanoAvax) testBlockMaxGas = fee.Gas(100_000) preFundedKeys = secp256k1.TestKeys() @@ -43,29 +43,36 @@ var ( func TestAddAndRemoveFees(t *testing.T) { r := require.New(t) - fc := NewDynamicCalculator(fee.NewCalculator(testGasPrice, testBlockMaxGas)) + fc := NewDynamicCalculator(fee.NewCalculator(testFeeWeights, testGasPrice, testBlockMaxGas)) var ( units = fee.Dimensions{1, 2, 3, 4} - gas = fee.Gas(10) - doubleGas = fee.Gas(20) + gas = fee.Gas(1) + doubleGas = fee.Gas(2) ) feeDelta, err := fc.AddFeesFor(units) r.NoError(err) - r.Equal(gas, fc.GetBlockGas()) + + haveGas, err := fc.GetBlockGas() + r.NoError(err) + r.Equal(gas, haveGas) r.NotZero(feeDelta) r.Equal(feeDelta, fc.GetFee()) feeDelta2, err := fc.AddFeesFor(units) r.NoError(err) - r.Equal(doubleGas, fc.GetBlockGas()) + haveGas, err = fc.GetBlockGas() + r.NoError(err) + r.Equal(doubleGas, haveGas) r.Equal(feeDelta, feeDelta2) r.Equal(feeDelta+feeDelta2, fc.GetFee()) feeDelta3, err := fc.RemoveFeesFor(units) r.NoError(err) - r.Equal(gas, fc.GetBlockGas()) + haveGas, err = fc.GetBlockGas() + r.NoError(err) + r.Equal(gas, haveGas) r.Equal(feeDelta, feeDelta3) r.Equal(feeDelta, fc.GetFee()) @@ -141,8 +148,10 @@ func TestTxFees(t *testing.T) { expectedError: nil, unsignedAndSignedTx: addSubnetValidatorTx, checksF: func(t *testing.T, c Calculator) { - require.Equal(t, 29_110*units.NanoAvax, c.GetFee()) - require.Equal(t, fee.Gas(2_911), c.GetBlockGas()) + require.Equal(t, 2_910*units.NanoAvax, c.GetFee()) + haveGas, err := c.GetBlockGas() + require.NoError(t, err) + require.Equal(t, fee.Gas(291), haveGas) }, }, { @@ -192,8 +201,10 @@ func TestTxFees(t *testing.T) { unsignedAndSignedTx: createChainTx, expectedError: nil, checksF: func(t *testing.T, c Calculator) { - require.Equal(t, 19_540*units.NanoAvax, c.GetFee()) - require.Equal(t, fee.Gas(1_954), c.GetBlockGas()) + require.Equal(t, 1_950*units.NanoAvax, c.GetFee()) + haveGas, err := c.GetBlockGas() + require.NoError(t, err) + require.Equal(t, fee.Gas(195), haveGas) }, }, { @@ -228,8 +239,10 @@ func TestTxFees(t *testing.T) { unsignedAndSignedTx: createSubnetTx, expectedError: nil, checksF: func(t *testing.T, c Calculator) { - require.Equal(t, 18_590*units.NanoAvax, c.GetFee()) - require.Equal(t, fee.Gas(1_859), c.GetBlockGas()) + require.Equal(t, 1_850*units.NanoAvax, c.GetFee()) + haveGas, err := c.GetBlockGas() + require.NoError(t, err) + require.Equal(t, fee.Gas(185), haveGas) }, }, { @@ -256,8 +269,10 @@ func TestTxFees(t *testing.T) { unsignedAndSignedTx: removeSubnetValidatorTx, expectedError: nil, checksF: func(t *testing.T, c Calculator) { - require.Equal(t, 28_870*units.NanoAvax, c.GetFee()) - require.Equal(t, fee.Gas(2_887), c.GetBlockGas()) + require.Equal(t, 2_880*units.NanoAvax, c.GetFee()) + haveGas, err := c.GetBlockGas() + require.NoError(t, err) + require.Equal(t, fee.Gas(288), haveGas) }, }, { @@ -284,8 +299,10 @@ func TestTxFees(t *testing.T) { unsignedAndSignedTx: transformSubnetTx, expectedError: nil, checksF: func(t *testing.T, c Calculator) { - require.Equal(t, 19_720*units.NanoAvax, c.GetFee()) - require.Equal(t, fee.Gas(1_972), c.GetBlockGas()) + require.Equal(t, 1_970*units.NanoAvax, c.GetFee()) + haveGas, err := c.GetBlockGas() + require.NoError(t, err) + require.Equal(t, fee.Gas(197), haveGas) }, }, { @@ -312,8 +329,10 @@ func TestTxFees(t *testing.T) { unsignedAndSignedTx: transferSubnetOwnershipTx, expectedError: nil, checksF: func(t *testing.T, c Calculator) { - require.Equal(t, 19_030*units.NanoAvax, c.GetFee()) - require.Equal(t, fee.Gas(1_903), c.GetBlockGas()) + require.Equal(t, 1_900*units.NanoAvax, c.GetFee()) + haveGas, err := c.GetBlockGas() + require.NoError(t, err) + require.Equal(t, fee.Gas(190), haveGas) }, }, { @@ -356,8 +375,10 @@ func TestTxFees(t *testing.T) { }, expectedError: nil, checksF: func(t *testing.T, c Calculator) { - require.Equal(t, 33_170*units.NanoAvax, c.GetFee()) - require.Equal(t, fee.Gas(3_317), c.GetBlockGas()) + require.Equal(t, 3_310*units.NanoAvax, c.GetFee()) + haveGas, err := c.GetBlockGas() + require.NoError(t, err) + require.Equal(t, fee.Gas(331), haveGas) }, }, { @@ -370,8 +391,10 @@ func TestTxFees(t *testing.T) { }, expectedError: nil, checksF: func(t *testing.T, c Calculator) { - require.Equal(t, 33_170*units.NanoAvax, c.GetFee()) - require.Equal(t, fee.Gas(3_317), c.GetBlockGas()) + require.Equal(t, 3_310*units.NanoAvax, c.GetFee()) + haveGas, err := c.GetBlockGas() + require.NoError(t, err) + require.Equal(t, fee.Gas(331), haveGas) }, }, { @@ -417,8 +440,10 @@ func TestTxFees(t *testing.T) { }, expectedError: nil, checksF: func(t *testing.T, c Calculator) { - require.Equal(t, 31_250*units.NanoAvax, c.GetFee()) - require.Equal(t, fee.Gas(3_125), c.GetBlockGas()) + require.Equal(t, 3_120*units.NanoAvax, c.GetFee()) + haveGas, err := c.GetBlockGas() + require.NoError(t, err) + require.Equal(t, fee.Gas(312), haveGas) }, }, { @@ -429,8 +454,10 @@ func TestTxFees(t *testing.T) { }, expectedError: nil, checksF: func(t *testing.T, c Calculator) { - require.Equal(t, 31_250*units.NanoAvax, c.GetFee()) - require.Equal(t, fee.Gas(3_125), c.GetBlockGas()) + require.Equal(t, 3_120*units.NanoAvax, c.GetFee()) + haveGas, err := c.GetBlockGas() + require.NoError(t, err) + require.Equal(t, fee.Gas(312), haveGas) }, }, { @@ -461,8 +488,10 @@ func TestTxFees(t *testing.T) { unsignedAndSignedTx: baseTx, expectedError: nil, checksF: func(t *testing.T, c Calculator) { - require.Equal(t, 18_190*units.NanoAvax, c.GetFee()) - require.Equal(t, fee.Gas(1_819), c.GetBlockGas()) + require.Equal(t, 1_810*units.NanoAvax, c.GetFee()) + haveGas, err := c.GetBlockGas() + require.NoError(t, err) + require.Equal(t, fee.Gas(181), haveGas) }, }, { @@ -489,8 +518,10 @@ func TestTxFees(t *testing.T) { unsignedAndSignedTx: importTx, expectedError: nil, checksF: func(t *testing.T, c Calculator) { - require.Equal(t, 31_230*units.NanoAvax, c.GetFee()) - require.Equal(t, fee.Gas(3_123), c.GetBlockGas()) + require.Equal(t, 3_120*units.NanoAvax, c.GetFee()) + haveGas, err := c.GetBlockGas() + require.NoError(t, err) + require.Equal(t, fee.Gas(312), haveGas) }, }, { @@ -517,8 +548,10 @@ func TestTxFees(t *testing.T) { unsignedAndSignedTx: exportTx, expectedError: nil, checksF: func(t *testing.T, c Calculator) { - require.Equal(t, 20_410*units.NanoAvax, c.GetFee()) - require.Equal(t, fee.Gas(2_041), c.GetBlockGas()) + require.Equal(t, 2_040*units.NanoAvax, c.GetFee()) + haveGas, err := c.GetBlockGas() + require.NoError(t, err) + require.Equal(t, fee.Gas(204), haveGas) }, }, { @@ -594,7 +627,7 @@ func TestTxFees(t *testing.T) { if !upgrades.IsEActivated(tt.chainTime) { c = NewStaticCalculator(feeTestsDefaultCfg, upgrades, tt.chainTime) } else { - c = NewDynamicCalculator(fee.NewCalculator(testGasPrice, gasCap)) + c = NewDynamicCalculator(fee.NewCalculator(testFeeWeights, testGasPrice, gasCap)) } var creds []verify.Verifiable diff --git a/vms/platformvm/txs/fee/dynamic_calculator.go b/vms/platformvm/txs/fee/dynamic_calculator.go index 2fcbe530c5ee..8af234ce4a94 100644 --- a/vms/platformvm/txs/fee/dynamic_calculator.go +++ b/vms/platformvm/txs/fee/dynamic_calculator.go @@ -27,7 +27,16 @@ var ( func NewDynamicCalculator(fc *fee.Calculator) Calculator { return &dynamicCalculator{ - fc: fc, + fc: fc, + buildingTx: false, + // credentials are set when computeFee is called + } +} + +func NewBuildingDynamicCalculator(fc *fee.Calculator) Calculator { + return &dynamicCalculator{ + fc: fc, + buildingTx: true, // credentials are set when computeFee is called } } @@ -37,6 +46,8 @@ type dynamicCalculator struct { fc *fee.Calculator cred []verify.Verifiable + buildingTx bool + // outputs of visitor execution fee uint64 } @@ -45,6 +56,9 @@ func (c *dynamicCalculator) CalculateFee(tx *txs.Tx) (uint64, error) { c.setCredentials(tx.Creds) c.fee = 0 // zero fee among different calculateFee invocations (unlike gas which gets cumulated) err := tx.Unsigned.Visit(c) + if !c.buildingTx { + err = errors.Join(err, c.fc.DoneWithLatestTx()) + } return c.fee, err } @@ -52,52 +66,34 @@ func (c *dynamicCalculator) AddFeesFor(complexity fee.Dimensions) (uint64, error if complexity == fee.Empty { return 0, nil } - - feeCfg, err := GetDynamicConfig(true /*isEActive*/) - if err != nil { - return 0, fmt.Errorf("failed adding fees: %w", err) - } - txGas, err := fee.ToGas(feeCfg.FeeDimensionWeights, complexity) - if err != nil { - return 0, fmt.Errorf("failed adding fees: %w", err) - } - - if err := c.fc.CumulateGas(txGas); err != nil { + if err := c.fc.CumulateComplexity(complexity); err != nil { return 0, fmt.Errorf("failed cumulating complexity: %w", err) } - fee, err := c.fc.CalculateFee(txGas) + fee, err := c.fc.GetLatestTxFee() if err != nil { return 0, fmt.Errorf("%w: %w", errFailedFeeCalculation, err) } - c.fee += fee - return fee, nil + extraFee := fee - c.fee + c.fee = fee + return extraFee, nil } func (c *dynamicCalculator) RemoveFeesFor(unitsToRm fee.Dimensions) (uint64, error) { if unitsToRm == fee.Empty { return 0, nil } - - feeCfg, err := GetDynamicConfig(true /*isEActive*/) - if err != nil { - return 0, fmt.Errorf("failed adding fees: %w", err) - } - txGas, err := fee.ToGas(feeCfg.FeeDimensionWeights, unitsToRm) - if err != nil { - return 0, fmt.Errorf("failed adding fees: %w", err) - } - - if err := c.fc.RemoveGas(txGas); err != nil { + if err := c.fc.RemoveComplexity(unitsToRm); err != nil { return 0, fmt.Errorf("failed removing units: %w", err) } - fee, err := c.fc.CalculateFee(txGas) + fee, err := c.fc.GetLatestTxFee() if err != nil { return 0, fmt.Errorf("%w: %w", errFailedFeeCalculation, err) } - c.fee -= fee - return fee, nil + removedFee := c.fee - fee + c.fee = fee + return removedFee, nil } func (c *dynamicCalculator) GetFee() uint64 { return c.fee } @@ -108,9 +104,9 @@ func (c *dynamicCalculator) ResetFee(newFee uint64) { func (c *dynamicCalculator) GetGasPrice() fee.GasPrice { return c.fc.GetGasPrice() } -func (c *dynamicCalculator) GetBlockGas() fee.Gas { return c.fc.GetBlockGas() } +func (c *dynamicCalculator) GetBlockGas() (fee.Gas, error) { return c.fc.GetBlockGas() } -func (c *dynamicCalculator) GetExcessGas() fee.Gas { return c.fc.GetExcessGas() } +func (c *dynamicCalculator) GetExcessGas() (fee.Gas, error) { return c.fc.GetExcessGas() } func (c *dynamicCalculator) GetGasCap() fee.Gas { return c.fc.GetGasCap() } diff --git a/vms/platformvm/txs/fee/dynamic_config.go b/vms/platformvm/txs/fee/dynamic_config.go index ca028031d5db..d7d3b7b928f3 100644 --- a/vms/platformvm/txs/fee/dynamic_config.go +++ b/vms/platformvm/txs/fee/dynamic_config.go @@ -15,7 +15,7 @@ import ( ) var ( - errDynamicFeeConfigNotAvailable = errors.New("dynamic fee config not available") + ErrDynamicFeeConfigNotAvailable = errors.New("dynamic fee config not available") eUpgradeDynamicFeesConfig = commonfee.DynamicFeesConfig{ MinGasPrice: commonfee.GasPrice(10 * units.NanoAvax), @@ -37,7 +37,7 @@ func init() { func GetDynamicConfig(isEActive bool) (commonfee.DynamicFeesConfig, error) { if !isEActive { - return commonfee.DynamicFeesConfig{}, errDynamicFeeConfigNotAvailable + return commonfee.DynamicFeesConfig{}, ErrDynamicFeeConfigNotAvailable } if customDynamicFeesConfig != nil { diff --git a/vms/platformvm/txs/fee/static_calculator.go b/vms/platformvm/txs/fee/static_calculator.go index 86cce9700356..5351aa02cb7a 100644 --- a/vms/platformvm/txs/fee/static_calculator.go +++ b/vms/platformvm/txs/fee/static_calculator.go @@ -67,9 +67,9 @@ func (*staticCalculator) RemoveFeesFor(fee.Dimensions) (uint64, error) { func (*staticCalculator) GetGasPrice() fee.GasPrice { return fee.ZeroGasPrice } -func (*staticCalculator) GetBlockGas() fee.Gas { return fee.ZeroGas } +func (*staticCalculator) GetBlockGas() (fee.Gas, error) { return fee.ZeroGas, nil } -func (*staticCalculator) GetExcessGas() fee.Gas { return fee.ZeroGas } +func (*staticCalculator) GetExcessGas() (fee.Gas, error) { return fee.ZeroGas, nil } func (*staticCalculator) GetGasCap() fee.Gas { return fee.ZeroGas } diff --git a/vms/platformvm/txs/txstest/builder.go b/vms/platformvm/txs/txstest/builder.go index 75b012445174..d54a316b4d78 100644 --- a/vms/platformvm/txs/txstest/builder.go +++ b/vms/platformvm/txs/txstest/builder.go @@ -66,5 +66,5 @@ func (w *WalletFactory) FeeCalculator() (fee.Calculator, error) { } diff.SetTimestamp(nextBlkTime) - return state.PickFeeCalculator(w.cfg, diff, parentBlkTime) + return state.PickBuildingFeeCalculator(w.cfg, diff, parentBlkTime) } diff --git a/wallet/chain/p/builder_test.go b/wallet/chain/p/builder_test.go index 375c25508a61..d389ab8aac93 100644 --- a/wallet/chain/p/builder_test.go +++ b/wallet/chain/p/builder_test.go @@ -56,6 +56,7 @@ var ( } testStaticConfig = staticFeesConfigFromContext(testContext) + testFeeWeights = commonfee.Dimensions{1, 1, 1, 1} testGasPrice = commonfee.GasPrice(10 * units.MicroAvax) testBlockMaxGas = commonfee.Gas(100_000) ) @@ -95,7 +96,7 @@ func TestBaseTx(t *testing.T) { ) { // Post E-Upgrade - feeCalc := fee.NewDynamicCalculator(commonfee.NewCalculator(testGasPrice, testBlockMaxGas)) + feeCalc := fee.NewBuildingDynamicCalculator(commonfee.NewCalculator(testFeeWeights, testGasPrice, testBlockMaxGas)) utx, err := builder.NewBaseTx( outputsToMove, feeCalc, @@ -105,10 +106,10 @@ func TestBaseTx(t *testing.T) { tx, err := signer.SignUnsigned(stdcontext.Background(), s, utx) require.NoError(err) - fc := fee.NewDynamicCalculator(commonfee.NewCalculator(testGasPrice, testBlockMaxGas)) + fc := fee.NewDynamicCalculator(commonfee.NewCalculator(testFeeWeights, testGasPrice, testBlockMaxGas)) fee, err := fc.CalculateFee(tx) require.NoError(err) - require.Equal(30_620*units.MicroAvax, fee) + require.Equal(3_060*units.MicroAvax, fee) // check UTXOs selection and fee financing ins := utx.Ins @@ -199,17 +200,17 @@ func TestAddSubnetValidatorTx(t *testing.T) { ) { // Post E-Upgrade - feeCalc := fee.NewDynamicCalculator(commonfee.NewCalculator(testGasPrice, testBlockMaxGas)) + feeCalc := fee.NewBuildingDynamicCalculator(commonfee.NewCalculator(testFeeWeights, testGasPrice, testBlockMaxGas)) utx, err := builder.NewAddSubnetValidatorTx(subnetValidator, feeCalc) require.NoError(err) tx, err := signer.SignUnsigned(stdcontext.Background(), s, utx) require.NoError(err) - fc := fee.NewDynamicCalculator(commonfee.NewCalculator(testGasPrice, testBlockMaxGas)) + fc := fee.NewDynamicCalculator(commonfee.NewCalculator(testFeeWeights, testGasPrice, testBlockMaxGas)) fee, err := fc.CalculateFee(tx) require.NoError(err) - require.Equal(40_610*units.MicroAvax, fee) + require.Equal(4_060*units.MicroAvax, fee) // check UTXOs selection and fee financing ins := utx.Ins @@ -287,7 +288,7 @@ func TestRemoveSubnetValidatorTx(t *testing.T) { ) { // Post E-Upgrade - feeCalc := fee.NewDynamicCalculator(commonfee.NewCalculator(testGasPrice, testBlockMaxGas)) + feeCalc := fee.NewBuildingDynamicCalculator(commonfee.NewCalculator(testFeeWeights, testGasPrice, testBlockMaxGas)) utx, err := builder.NewRemoveSubnetValidatorTx( ids.GenerateTestNodeID(), subnetID, @@ -298,10 +299,10 @@ func TestRemoveSubnetValidatorTx(t *testing.T) { tx, err := signer.SignUnsigned(stdcontext.Background(), s, utx) require.NoError(err) - fc := fee.NewDynamicCalculator(commonfee.NewCalculator(testGasPrice, testBlockMaxGas)) + fc := fee.NewDynamicCalculator(commonfee.NewCalculator(testFeeWeights, testGasPrice, testBlockMaxGas)) fee, err := fc.CalculateFee(tx) require.NoError(err) - require.Equal(40_370*units.MicroAvax, fee) + require.Equal(4_030*units.MicroAvax, fee) // check UTXOs selection and fee financing ins := utx.Ins @@ -389,7 +390,7 @@ func TestCreateChainTx(t *testing.T) { ) { // Post E-Upgrade - feeCalc := fee.NewDynamicCalculator(commonfee.NewCalculator(testGasPrice, testBlockMaxGas)) + feeCalc := fee.NewBuildingDynamicCalculator(commonfee.NewCalculator(testFeeWeights, testGasPrice, testBlockMaxGas)) utx, err := builder.NewCreateChainTx( subnetID, genesisBytes, @@ -403,19 +404,19 @@ func TestCreateChainTx(t *testing.T) { tx, err := signer.SignUnsigned(stdcontext.Background(), s, utx) require.NoError(err) - fc := fee.NewDynamicCalculator(commonfee.NewCalculator(testGasPrice, testBlockMaxGas)) + fc := fee.NewDynamicCalculator(commonfee.NewCalculator(testFeeWeights, testGasPrice, testBlockMaxGas)) fee, err := fc.CalculateFee(tx) require.NoError(err) - require.Equal(31_040*units.MicroAvax, fee) + require.Equal(1_760*units.MicroAvax, fee) // check UTXOs selection and fee financing ins := utx.Ins outs := utx.Outs - require.Len(ins, 2) + require.Len(ins, 1) require.Len(outs, 1) expectedConsumed := fee - consumed := ins[0].In.Amount() + ins[1].In.Amount() - outs[0].Out.Amount() + consumed := ins[0].In.Amount() - outs[0].Out.Amount() require.Equal(expectedConsumed, consumed) } @@ -491,7 +492,7 @@ func TestCreateSubnetTx(t *testing.T) { ) { // Post E-Upgrade - feeCalc := fee.NewDynamicCalculator(commonfee.NewCalculator(testGasPrice, testBlockMaxGas)) + feeCalc := fee.NewBuildingDynamicCalculator(commonfee.NewCalculator(testFeeWeights, testGasPrice, testBlockMaxGas)) utx, err := builder.NewCreateSubnetTx( subnetOwner, feeCalc, @@ -501,19 +502,19 @@ func TestCreateSubnetTx(t *testing.T) { tx, err := signer.SignUnsigned(stdcontext.Background(), s, utx) require.NoError(err) - fc := fee.NewDynamicCalculator(commonfee.NewCalculator(testGasPrice, testBlockMaxGas)) + fc := fee.NewDynamicCalculator(commonfee.NewCalculator(testFeeWeights, testGasPrice, testBlockMaxGas)) fee, err := fc.CalculateFee(tx) require.NoError(err) - require.Equal(29_400*units.MicroAvax, fee) + require.Equal(1_590*units.MicroAvax, fee) // check UTXOs selection and fee financing ins := utx.Ins outs := utx.Outs - require.Len(ins, 2) + require.Len(ins, 1) require.Len(outs, 1) expectedConsumed := fee - consumed := ins[0].In.Amount() + ins[1].In.Amount() - outs[0].Out.Amount() + consumed := ins[0].In.Amount() - outs[0].Out.Amount() require.Equal(expectedConsumed, consumed) } @@ -585,7 +586,7 @@ func TestTransferSubnetOwnershipTx(t *testing.T) { ) { // Post E-Upgrade - feeCalc := fee.NewDynamicCalculator(commonfee.NewCalculator(testGasPrice, testBlockMaxGas)) + feeCalc := fee.NewBuildingDynamicCalculator(commonfee.NewCalculator(testFeeWeights, testGasPrice, testBlockMaxGas)) utx, err := builder.NewTransferSubnetOwnershipTx( subnetID, subnetOwner, @@ -596,19 +597,19 @@ func TestTransferSubnetOwnershipTx(t *testing.T) { tx, err := signer.SignUnsigned(stdcontext.Background(), s, utx) require.NoError(err) - fc := fee.NewDynamicCalculator(commonfee.NewCalculator(testGasPrice, testBlockMaxGas)) + fc := fee.NewDynamicCalculator(commonfee.NewCalculator(testFeeWeights, testGasPrice, testBlockMaxGas)) fee, err := fc.CalculateFee(tx) require.NoError(err) - require.Equal(30_570*units.MicroAvax, fee) + require.Equal(1_710*units.MicroAvax, fee) // check UTXOs selection and fee financing ins := utx.Ins outs := utx.Outs - require.Len(ins, 2) + require.Len(ins, 1) require.Len(outs, 1) expectedConsumed := fee - consumed := ins[0].In.Amount() + ins[1].In.Amount() - outs[0].Out.Amount() + consumed := ins[0].In.Amount() - outs[0].Out.Amount() require.Equal(expectedConsumed, consumed) } @@ -675,7 +676,7 @@ func TestImportTx(t *testing.T) { ) { // Post E-Upgrade - feeCalc := fee.NewDynamicCalculator(commonfee.NewCalculator(testGasPrice, testBlockMaxGas)) + feeCalc := fee.NewBuildingDynamicCalculator(commonfee.NewCalculator(testFeeWeights, testGasPrice, testBlockMaxGas)) utx, err := builder.NewImportTx( sourceChainID, importTo, @@ -686,21 +687,21 @@ func TestImportTx(t *testing.T) { tx, err := signer.SignUnsigned(stdcontext.Background(), s, utx) require.NoError(err) - fc := fee.NewDynamicCalculator(commonfee.NewCalculator(testGasPrice, testBlockMaxGas)) + fc := fee.NewDynamicCalculator(commonfee.NewCalculator(testFeeWeights, testGasPrice, testBlockMaxGas)) fee, err := fc.CalculateFee(tx) require.NoError(err) - require.Equal(42_770*units.MicroAvax, fee) + require.Equal(1_590*units.MicroAvax, fee) // check UTXOs selection and fee financing ins := utx.Ins outs := utx.Outs importedIns := utx.ImportedInputs - require.Len(ins, 2) + require.Empty(ins) require.Len(importedIns, 1) require.Len(outs, 1) expectedConsumed := fee - consumed := importedIns[0].In.Amount() + ins[0].In.Amount() + ins[1].In.Amount() - outs[0].Out.Amount() + consumed := importedIns[0].In.Amount() - outs[0].Out.Amount() require.Equal(expectedConsumed, consumed) } @@ -765,7 +766,7 @@ func TestExportTx(t *testing.T) { ) { // Post E-Upgrade - feeCalc := fee.NewDynamicCalculator(commonfee.NewCalculator(testGasPrice, testBlockMaxGas)) + feeCalc := fee.NewBuildingDynamicCalculator(commonfee.NewCalculator(testFeeWeights, testGasPrice, testBlockMaxGas)) utx, err := builder.NewExportTx( subnetID, exportedOutputs, @@ -776,10 +777,10 @@ func TestExportTx(t *testing.T) { tx, err := signer.SignUnsigned(stdcontext.Background(), s, utx) require.NoError(err) - fc := fee.NewDynamicCalculator(commonfee.NewCalculator(testGasPrice, testBlockMaxGas)) + fc := fee.NewDynamicCalculator(commonfee.NewCalculator(testFeeWeights, testGasPrice, testBlockMaxGas)) fee, err := fc.CalculateFee(tx) require.NoError(err) - require.Equal(30_980*units.MicroAvax, fee) + require.Equal(3_090*units.MicroAvax, fee) // check UTXOs selection and fee financing ins := utx.Ins @@ -867,7 +868,7 @@ func TestTransformSubnetTx(t *testing.T) { ) { // Post E-Upgrade - feeCalc := fee.NewDynamicCalculator(commonfee.NewCalculator(testGasPrice, testBlockMaxGas)) + feeCalc := fee.NewBuildingDynamicCalculator(commonfee.NewCalculator(testFeeWeights, testGasPrice, testBlockMaxGas)) utx, err := builder.NewTransformSubnetTx( subnetID, subnetAssetID, @@ -890,10 +891,10 @@ func TestTransformSubnetTx(t *testing.T) { tx, err := signer.SignUnsigned(stdcontext.Background(), s, utx) require.NoError(err) - fc := fee.NewDynamicCalculator(commonfee.NewCalculator(testGasPrice, testBlockMaxGas)) + fc := fee.NewDynamicCalculator(commonfee.NewCalculator(testFeeWeights, testGasPrice, testBlockMaxGas)) fee, err := fc.CalculateFee(tx) require.NoError(err) - require.Equal(46_250*units.MicroAvax, fee) + require.Equal(4_620*units.MicroAvax, fee) // check UTXOs selection and fee financing ins := utx.Ins @@ -989,7 +990,7 @@ func TestAddPermissionlessValidatorTx(t *testing.T) { require.NoError(err) { // Post E-Upgrade - feeCalc := fee.NewDynamicCalculator(commonfee.NewCalculator(testGasPrice, testBlockMaxGas)) + feeCalc := fee.NewBuildingDynamicCalculator(commonfee.NewCalculator(testFeeWeights, testGasPrice, testBlockMaxGas)) utx, err := builder.NewAddPermissionlessValidatorTx( &txs.SubnetValidator{ Validator: txs.Validator{ @@ -1011,10 +1012,10 @@ func TestAddPermissionlessValidatorTx(t *testing.T) { tx, err := signer.SignUnsigned(stdcontext.Background(), s, utx) require.NoError(err) - fc := fee.NewDynamicCalculator(commonfee.NewCalculator(testGasPrice, testBlockMaxGas)) + fc := fee.NewDynamicCalculator(commonfee.NewCalculator(testFeeWeights, testGasPrice, testBlockMaxGas)) fee, err := fc.CalculateFee(tx) require.NoError(err) - require.Equal(75_240*units.MicroAvax, fee) + require.Equal(7_520*units.MicroAvax, fee) // check UTXOs selection and fee financing ins := utx.Ins @@ -1108,7 +1109,7 @@ func TestAddPermissionlessDelegatorTx(t *testing.T) { ) { // Post E-Upgrade - feeCalc := fee.NewDynamicCalculator(commonfee.NewCalculator(testGasPrice, testBlockMaxGas)) + feeCalc := fee.NewBuildingDynamicCalculator(commonfee.NewCalculator(testFeeWeights, testGasPrice, testBlockMaxGas)) utx, err := builder.NewAddPermissionlessDelegatorTx( &txs.SubnetValidator{ Validator: txs.Validator{ @@ -1127,10 +1128,10 @@ func TestAddPermissionlessDelegatorTx(t *testing.T) { tx, err := signer.SignUnsigned(stdcontext.Background(), s, utx) require.NoError(err) - fc := fee.NewDynamicCalculator(commonfee.NewCalculator(testGasPrice, testBlockMaxGas)) + fc := fee.NewDynamicCalculator(commonfee.NewCalculator(testFeeWeights, testGasPrice, testBlockMaxGas)) fee, err := fc.CalculateFee(tx) require.NoError(err) - require.Equal(73_320*units.MicroAvax, fee) + require.Equal(7_330*units.MicroAvax, fee) // check UTXOs selection and fee financing ins := utx.Ins diff --git a/wallet/chain/p/wallet.go b/wallet/chain/p/wallet.go index 0b608c8db98d..22fc97a1b1d9 100644 --- a/wallet/chain/p/wallet.go +++ b/wallet/chain/p/wallet.go @@ -291,6 +291,7 @@ type wallet struct { isEForkActive bool staticFeesConfig fee.StaticConfig + feeCfg commonfee.DynamicFeesConfig gasPrice commonfee.GasPrice gasCap commonfee.Gas } @@ -632,7 +633,7 @@ func (w *wallet) feeCalculator(ctx *builder.Context, options ...common.Option) ( return fee.NewStaticCalculator(w.staticFeesConfig, upgrade.Config{}, time.Time{}), nil } - return fee.NewDynamicCalculator(commonfee.NewCalculator(w.gasPrice, w.gasCap)), nil + return fee.NewBuildingDynamicCalculator(commonfee.NewCalculator(w.feeCfg.FeeDimensionWeights, w.gasPrice, w.gasCap)), nil } func (w *wallet) refreshFeesData(ctx *builder.Context, options ...common.Option) error { @@ -646,7 +647,15 @@ func (w *wallet) refreshFeesData(ctx *builder.Context, options ...common.Option) return err } eUpgradeTime := version.GetEUpgradeTime(w.builder.Context().NetworkID) - w.isEForkActive = !chainTime.Before(eUpgradeTime) + isEForkActive := !chainTime.Before(eUpgradeTime) + + if !w.isEForkActive && isEForkActive { + w.feeCfg, err = w.client.GetDynamicFeeConfig(opsCtx) + if err != nil { + return err + } + } + w.isEForkActive = isEForkActive if !w.isEForkActive { w.staticFeesConfig = staticFeesConfigFromContext(ctx)