From 10d71e74ec6b1b590204e5d23cb5551e00702b2a Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 8 Jan 2024 10:33:16 +0100 Subject: [PATCH 001/190] fee manager draft --- vms/platformvm/fees/manager.go | 82 ++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 vms/platformvm/fees/manager.go diff --git a/vms/platformvm/fees/manager.go b/vms/platformvm/fees/manager.go new file mode 100644 index 000000000000..a7266e063f06 --- /dev/null +++ b/vms/platformvm/fees/manager.go @@ -0,0 +1,82 @@ +// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package fees + +import "github.com/ava-labs/avalanchego/utils/math" + +const ( + Bandwidth Dimension = 0 + // Compute Dimension = 1 // TODO ABENEGIA: we'll add others interatively + UTXORead Dimension = 1 + UTXOWrite Dimension = 2 // includes delete + + FeeDimensions = 3 +) + +type ( + Dimension int + Dimensions [FeeDimensions]uint64 +) + +type Manager struct { + // Avax prices per units for all fee dimensions + unitPrices Dimensions + + // cumulatedUnits helps aggregating the units consumed by a block + // so that we can verify it's not too big/build it properly + cumulatedUnits Dimensions +} + +func NewManager(initialUnitPrices Dimensions) *Manager { + return &Manager{ + unitPrices: initialUnitPrices, + } +} + +func (m *Manager) UnitPrices() Dimensions { + var d Dimensions + for i := Dimension(0); i < FeeDimensions; i++ { + d[i] = m.unitPrices[i] + } + return d +} + +func (m *Manager) CalculateFee(units Dimensions) (uint64, error) { + fee := uint64(0) + + for i := Dimension(0); i < FeeDimensions; i++ { + contribution, err := math.Mul64(m.unitPrices[i], units[i]) + if err != nil { + return 0, err + } + fee, err = math.Add64(contribution, fee) + if err != nil { + return 0, err + } + } + return fee, nil +} + +func (m *Manager) CumulateUnits(units, bounds Dimensions) (bool, Dimension) { + // Ensure we can consume (don't want partial update of values) + for i := Dimension(0); i < FeeDimensions; i++ { + consumed, err := math.Add64(m.cumulatedUnits[i], units[i]) + if err != nil { + return false, i + } + if consumed > bounds[i] { + return false, i + } + } + + // Commit to consumption + for i := Dimension(0); i < FeeDimensions; i++ { + consumed, err := math.Add64(m.cumulatedUnits[i], units[i]) + if err != nil { + return false, i + } + m.cumulatedUnits[i] = consumed + } + return true, 0 +} From f4da004abe713f07f7c11fed59f0478733e4f0de Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 8 Jan 2024 10:35:52 +0100 Subject: [PATCH 002/190] fee calculator draft --- vms/platformvm/config/config.go | 18 +++ vms/platformvm/fees/manager.go | 28 ++-- vms/platformvm/txs/executor/fee_calculator.go | 131 ++++++++++++++++++ 3 files changed, 162 insertions(+), 15 deletions(-) create mode 100644 vms/platformvm/txs/executor/fee_calculator.go diff --git a/vms/platformvm/config/config.go b/vms/platformvm/config/config.go index 50628c422afd..834b1d4b44c4 100644 --- a/vms/platformvm/config/config.go +++ b/vms/platformvm/config/config.go @@ -4,6 +4,7 @@ package config import ( + "math" "time" "github.com/ava-labs/avalanchego/chains" @@ -12,6 +13,7 @@ import ( "github.com/ava-labs/avalanchego/snow/validators" "github.com/ava-labs/avalanchego/utils/constants" "github.com/ava-labs/avalanchego/utils/set" + "github.com/ava-labs/avalanchego/vms/platformvm/fees" "github.com/ava-labs/avalanchego/vms/platformvm/reward" "github.com/ava-labs/avalanchego/vms/platformvm/txs" ) @@ -107,6 +109,9 @@ type Config struct { // Time of the Durango network upgrade DurangoTime time.Time + // Time of the E network upgrade + EForkTime time.Time + // UseCurrentHeight forces [GetMinimumHeight] to return the current height // of the P-Chain instead of the oldest block in the [recentlyAccepted] // window. @@ -137,6 +142,10 @@ func (c *Config) IsDurangoActivated(timestamp time.Time) bool { return !timestamp.Before(c.DurangoTime) } +func (c *Config) IsEForkActivated(timestamp time.Time) bool { + return !timestamp.Before(c.EForkTime) +} + func (c *Config) GetCreateBlockchainTxFee(timestamp time.Time) uint64 { if c.IsApricotPhase3Activated(timestamp) { return c.CreateBlockchainTxFee @@ -170,3 +179,12 @@ func (c *Config) CreateChain(chainID ids.ID, tx *txs.CreateChainTx) { c.Chains.QueueChainCreation(chainParams) } + +func (*Config) BlockMaxConsumedUnits() fees.Dimensions { + // TODO ABENEGIA: to be set + var res fees.Dimensions + for i := fees.Dimension(0); i < fees.FeeDimensions; i++ { + res[i] = math.MaxUint64 + } + return res +} diff --git a/vms/platformvm/fees/manager.go b/vms/platformvm/fees/manager.go index a7266e063f06..78682723a6f6 100644 --- a/vms/platformvm/fees/manager.go +++ b/vms/platformvm/fees/manager.go @@ -5,13 +5,16 @@ package fees import "github.com/ava-labs/avalanchego/utils/math" +// 1. Fees are not dynamic yet. We'll add mechanism for fee updating iterativelly +// 2. Not all fees dimensions are correctly prices. We'll add other dimensions iteratively + const ( Bandwidth Dimension = 0 - // Compute Dimension = 1 // TODO ABENEGIA: we'll add others interatively - UTXORead Dimension = 1 - UTXOWrite Dimension = 2 // includes delete + // Compute Dimension = 1 + // UTXORead Dimension = 2 + // UTXOWrite Dimension = 3 // includes delete - FeeDimensions = 3 + FeeDimensions = 4 ) type ( @@ -24,22 +27,14 @@ type Manager struct { unitPrices Dimensions // cumulatedUnits helps aggregating the units consumed by a block - // so that we can verify it's not too big/build it properly + // so that we can verify it's not too big/build it properly. cumulatedUnits Dimensions } -func NewManager(initialUnitPrices Dimensions) *Manager { +func NewManager(unitPrices Dimensions) *Manager { return &Manager{ - unitPrices: initialUnitPrices, - } -} - -func (m *Manager) UnitPrices() Dimensions { - var d Dimensions - for i := Dimension(0); i < FeeDimensions; i++ { - d[i] = m.unitPrices[i] + unitPrices: unitPrices, } - return d } func (m *Manager) CalculateFee(units Dimensions) (uint64, error) { @@ -58,6 +53,9 @@ func (m *Manager) CalculateFee(units Dimensions) (uint64, error) { return fee, nil } +// CumulateUnits tries to cumulate the consumed units [units]. Before +// actually cumulating them, it checks whether the result would breach [bounds]. +// If so, it returns the first dimension to breach bounds. func (m *Manager) CumulateUnits(units, bounds Dimensions) (bool, Dimension) { // Ensure we can consume (don't want partial update of values) for i := Dimension(0); i < FeeDimensions; i++ { diff --git a/vms/platformvm/txs/executor/fee_calculator.go b/vms/platformvm/txs/executor/fee_calculator.go new file mode 100644 index 000000000000..094469d2c7f7 --- /dev/null +++ b/vms/platformvm/txs/executor/fee_calculator.go @@ -0,0 +1,131 @@ +// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package executor + +import ( + "errors" + "fmt" + "time" + + "github.com/ava-labs/avalanchego/vms/platformvm/config" + "github.com/ava-labs/avalanchego/vms/platformvm/fees" + "github.com/ava-labs/avalanchego/vms/platformvm/txs" +) + +var ( + _ txs.Visitor = (*FeeCalculator)(nil) + + errNotYetImplemented = errors.New("not yet implemented") + errFailedFeeCalculation = errors.New("failed fee calculation") + errFailedConsumedUnitsCumulation = errors.New("failed cumulating consumed units") +) + +type FeeCalculator struct { + // inputs, to be filled before visitor methods are called + *Backend + ChainTime time.Time + Tx *txs.Tx + feeManager *fees.Manager + + // outputs of visitor execution + Fee uint64 +} + +func (fc *FeeCalculator) AddValidatorTx(*txs.AddValidatorTx) error { + if !fc.Config.IsEForkActivated(fc.ChainTime) { + fc.Fee = fc.Config.AddPrimaryNetworkValidatorFee + return nil + } + + var ( + consumedUnits fees.Dimensions + err error + ) + consumedUnits[fees.Bandwidth] = uint64(len(fc.Tx.Bytes())) + + fc.Fee, err = processFees(fc.Config, fc.feeManager, consumedUnits) + return err +} + +func (fc *FeeCalculator) AddSubnetValidatorTx(*txs.AddSubnetValidatorTx) error { + if !fc.Config.IsEForkActivated(fc.ChainTime) { + fc.Fee = fc.Config.AddSubnetValidatorFee + return nil + } + + var ( + consumedUnits fees.Dimensions + err error + ) + consumedUnits[fees.Bandwidth] = uint64(len(fc.Tx.Bytes())) + + fc.Fee, err = processFees(fc.Config, fc.feeManager, consumedUnits) + return err +} + +func (*FeeCalculator) AddDelegatorTx(*txs.AddDelegatorTx) error { + return errNotYetImplemented +} + +func (*FeeCalculator) CreateChainTx(*txs.CreateChainTx) error { + return errNotYetImplemented +} + +func (*FeeCalculator) CreateSubnetTx(*txs.CreateSubnetTx) error { + return errNotYetImplemented +} + +func (*FeeCalculator) AdvanceTimeTx(*txs.AdvanceTimeTx) error { + return errNotYetImplemented +} + +func (*FeeCalculator) RewardValidatorTx(*txs.RewardValidatorTx) error { + return errNotYetImplemented +} + +func (*FeeCalculator) RemoveSubnetValidatorTx(*txs.RemoveSubnetValidatorTx) error { + return errNotYetImplemented +} + +func (*FeeCalculator) TransformSubnetTx(*txs.TransformSubnetTx) error { + return errNotYetImplemented +} + +func (*FeeCalculator) TransferSubnetOwnershipTx(*txs.TransferSubnetOwnershipTx) error { + return errNotYetImplemented +} + +func (*FeeCalculator) AddPermissionlessValidatorTx(*txs.AddPermissionlessValidatorTx) error { + return errNotYetImplemented +} + +func (*FeeCalculator) AddPermissionlessDelegatorTx(*txs.AddPermissionlessDelegatorTx) error { + return errNotYetImplemented +} + +func (*FeeCalculator) BaseTx(*txs.BaseTx) error { + return errNotYetImplemented +} + +func (*FeeCalculator) ImportTx(*txs.ImportTx) error { + return errNotYetImplemented +} + +func (*FeeCalculator) ExportTx(*txs.ExportTx) error { + return errNotYetImplemented +} + +func processFees(cfg *config.Config, fc *fees.Manager, consumedUnits fees.Dimensions) (uint64, error) { + boundBreached, dimension := fc.CumulateUnits(consumedUnits, cfg.BlockMaxConsumedUnits()) + if boundBreached { + return 0, fmt.Errorf("%w: breached dimension %d", errFailedConsumedUnitsCumulation, dimension) + } + + fee, err := fc.CalculateFee(consumedUnits) + if err != nil { + return 0, fmt.Errorf("%w: %w", errFailedFeeCalculation, err) + } + + return fee, nil +} From c705d55440df579b682665424009add051c99481 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 8 Jan 2024 14:35:17 +0100 Subject: [PATCH 003/190] some more fee calculator drafting --- vms/platformvm/txs/executor/fee_calculator.go | 190 +++++++++++++++--- 1 file changed, 165 insertions(+), 25 deletions(-) diff --git a/vms/platformvm/txs/executor/fee_calculator.go b/vms/platformvm/txs/executor/fee_calculator.go index 094469d2c7f7..f6df239665f9 100644 --- a/vms/platformvm/txs/executor/fee_calculator.go +++ b/vms/platformvm/txs/executor/fee_calculator.go @@ -8,6 +8,7 @@ import ( "fmt" "time" + "github.com/ava-labs/avalanchego/utils/constants" "github.com/ava-labs/avalanchego/vms/platformvm/config" "github.com/ava-labs/avalanchego/vms/platformvm/fees" "github.com/ava-labs/avalanchego/vms/platformvm/txs" @@ -16,7 +17,6 @@ import ( var ( _ txs.Visitor = (*FeeCalculator)(nil) - errNotYetImplemented = errors.New("not yet implemented") errFailedFeeCalculation = errors.New("failed fee calculation") errFailedConsumedUnitsCumulation = errors.New("failed cumulating consumed units") ) @@ -64,56 +64,196 @@ func (fc *FeeCalculator) AddSubnetValidatorTx(*txs.AddSubnetValidatorTx) error { return err } -func (*FeeCalculator) AddDelegatorTx(*txs.AddDelegatorTx) error { - return errNotYetImplemented +func (fc *FeeCalculator) AddDelegatorTx(*txs.AddDelegatorTx) error { + if !fc.Config.IsEForkActivated(fc.ChainTime) { + fc.Fee = fc.Config.AddPrimaryNetworkDelegatorFee + return nil + } + + var ( + consumedUnits fees.Dimensions + err error + ) + consumedUnits[fees.Bandwidth] = uint64(len(fc.Tx.Bytes())) + + fc.Fee, err = processFees(fc.Config, fc.feeManager, consumedUnits) + return err } -func (*FeeCalculator) CreateChainTx(*txs.CreateChainTx) error { - return errNotYetImplemented +func (fc *FeeCalculator) CreateChainTx(*txs.CreateChainTx) error { + if !fc.Config.IsEForkActivated(fc.ChainTime) { + fc.Fee = fc.Config.GetCreateBlockchainTxFee(fc.ChainTime) + return nil + } + + var ( + consumedUnits fees.Dimensions + err error + ) + consumedUnits[fees.Bandwidth] = uint64(len(fc.Tx.Bytes())) + + fc.Fee, err = processFees(fc.Config, fc.feeManager, consumedUnits) + return err } -func (*FeeCalculator) CreateSubnetTx(*txs.CreateSubnetTx) error { - return errNotYetImplemented +func (fc *FeeCalculator) CreateSubnetTx(*txs.CreateSubnetTx) error { + if !fc.Config.IsEForkActivated(fc.ChainTime) { + fc.Fee = fc.Config.GetCreateSubnetTxFee(fc.ChainTime) + return nil + } + + var ( + consumedUnits fees.Dimensions + err error + ) + consumedUnits[fees.Bandwidth] = uint64(len(fc.Tx.Bytes())) + + fc.Fee, err = processFees(fc.Config, fc.feeManager, consumedUnits) + return err } func (*FeeCalculator) AdvanceTimeTx(*txs.AdvanceTimeTx) error { - return errNotYetImplemented + return nil // no fees } func (*FeeCalculator) RewardValidatorTx(*txs.RewardValidatorTx) error { - return errNotYetImplemented + return nil // no fees } -func (*FeeCalculator) RemoveSubnetValidatorTx(*txs.RemoveSubnetValidatorTx) error { - return errNotYetImplemented +func (fc *FeeCalculator) RemoveSubnetValidatorTx(*txs.RemoveSubnetValidatorTx) error { + if !fc.Config.IsEForkActivated(fc.ChainTime) { + fc.Fee = fc.Config.TxFee + return nil + } + + var ( + consumedUnits fees.Dimensions + err error + ) + consumedUnits[fees.Bandwidth] = uint64(len(fc.Tx.Bytes())) + + fc.Fee, err = processFees(fc.Config, fc.feeManager, consumedUnits) + return err } -func (*FeeCalculator) TransformSubnetTx(*txs.TransformSubnetTx) error { - return errNotYetImplemented +func (fc *FeeCalculator) TransformSubnetTx(*txs.TransformSubnetTx) error { + if !fc.Config.IsEForkActivated(fc.ChainTime) { + fc.Fee = fc.Config.TransformSubnetTxFee + return nil + } + + var ( + consumedUnits fees.Dimensions + err error + ) + consumedUnits[fees.Bandwidth] = uint64(len(fc.Tx.Bytes())) + + fc.Fee, err = processFees(fc.Config, fc.feeManager, consumedUnits) + return err } -func (*FeeCalculator) TransferSubnetOwnershipTx(*txs.TransferSubnetOwnershipTx) error { - return errNotYetImplemented +func (fc *FeeCalculator) TransferSubnetOwnershipTx(*txs.TransferSubnetOwnershipTx) error { + if !fc.Config.IsEForkActivated(fc.ChainTime) { + fc.Fee = fc.Config.TxFee + return nil + } + + var ( + consumedUnits fees.Dimensions + err error + ) + consumedUnits[fees.Bandwidth] = uint64(len(fc.Tx.Bytes())) + + fc.Fee, err = processFees(fc.Config, fc.feeManager, consumedUnits) + return err } -func (*FeeCalculator) AddPermissionlessValidatorTx(*txs.AddPermissionlessValidatorTx) error { - return errNotYetImplemented +func (fc *FeeCalculator) AddPermissionlessValidatorTx(tx *txs.AddPermissionlessValidatorTx) error { + if !fc.Config.IsEForkActivated(fc.ChainTime) { + if tx.Subnet != constants.PrimaryNetworkID { + fc.Fee = fc.Config.AddSubnetValidatorFee + } else { + fc.Fee = fc.Config.AddPrimaryNetworkValidatorFee + } + return nil + } + + var ( + consumedUnits fees.Dimensions + err error + ) + consumedUnits[fees.Bandwidth] = uint64(len(fc.Tx.Bytes())) + + fc.Fee, err = processFees(fc.Config, fc.feeManager, consumedUnits) + return err } -func (*FeeCalculator) AddPermissionlessDelegatorTx(*txs.AddPermissionlessDelegatorTx) error { - return errNotYetImplemented +func (fc *FeeCalculator) AddPermissionlessDelegatorTx(tx *txs.AddPermissionlessDelegatorTx) error { + if !fc.Config.IsEForkActivated(fc.ChainTime) { + if tx.Subnet != constants.PrimaryNetworkID { + fc.Fee = fc.Config.AddSubnetDelegatorFee + } else { + fc.Fee = fc.Config.AddPrimaryNetworkDelegatorFee + } + return nil + } + + var ( + consumedUnits fees.Dimensions + err error + ) + consumedUnits[fees.Bandwidth] = uint64(len(fc.Tx.Bytes())) + + fc.Fee, err = processFees(fc.Config, fc.feeManager, consumedUnits) + return err } -func (*FeeCalculator) BaseTx(*txs.BaseTx) error { - return errNotYetImplemented +func (fc *FeeCalculator) BaseTx(*txs.BaseTx) error { + if !fc.Config.IsEForkActivated(fc.ChainTime) { + fc.Fee = fc.Config.TxFee + return nil + } + + var ( + consumedUnits fees.Dimensions + err error + ) + consumedUnits[fees.Bandwidth] = uint64(len(fc.Tx.Bytes())) + + fc.Fee, err = processFees(fc.Config, fc.feeManager, consumedUnits) + return err } -func (*FeeCalculator) ImportTx(*txs.ImportTx) error { - return errNotYetImplemented +func (fc *FeeCalculator) ImportTx(*txs.ImportTx) error { + if !fc.Config.IsEForkActivated(fc.ChainTime) { + fc.Fee = fc.Config.TxFee + return nil + } + + var ( + consumedUnits fees.Dimensions + err error + ) + consumedUnits[fees.Bandwidth] = uint64(len(fc.Tx.Bytes())) + + fc.Fee, err = processFees(fc.Config, fc.feeManager, consumedUnits) + return err } -func (*FeeCalculator) ExportTx(*txs.ExportTx) error { - return errNotYetImplemented +func (fc *FeeCalculator) ExportTx(*txs.ExportTx) error { + if !fc.Config.IsEForkActivated(fc.ChainTime) { + fc.Fee = fc.Config.TxFee + return nil + } + + var ( + consumedUnits fees.Dimensions + err error + ) + consumedUnits[fees.Bandwidth] = uint64(len(fc.Tx.Bytes())) + + fc.Fee, err = processFees(fc.Config, fc.feeManager, consumedUnits) + return err } func processFees(cfg *config.Config, fc *fees.Manager, consumedUnits fees.Dimensions) (uint64, error) { From 75b93b7a227fd0d9f3f95f972c63f8e066397163 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 8 Jan 2024 14:52:59 +0100 Subject: [PATCH 004/190] wired in fee calculator --- vms/platformvm/block/builder/builder.go | 8 +- vms/platformvm/block/builder/helpers_test.go | 10 +- vms/platformvm/block/executor/helpers_test.go | 10 +- vms/platformvm/block/executor/verifier.go | 9 +- vms/platformvm/fees/manager.go | 3 + .../txs/executor/atomic_tx_executor.go | 8 +- .../txs/executor/create_chain_test.go | 36 +-- .../txs/executor/create_subnet_test.go | 8 +- vms/platformvm/txs/executor/helpers_test.go | 9 +- .../txs/executor/proposal_tx_executor.go | 7 +- .../txs/executor/staker_tx_verification.go | 102 +++++++-- .../executor/staker_tx_verification_test.go | 26 ++- .../txs/executor/standard_tx_executor.go | 66 +++++- .../txs/executor/standard_tx_executor_test.go | 215 +++++++++++------- .../txs/executor/tx_mempool_verifier.go | 8 +- vms/platformvm/validator_set_property_test.go | 2 + vms/platformvm/vm_regression_test.go | 1 + vms/platformvm/vm_test.go | 8 + 18 files changed, 381 insertions(+), 155 deletions(-) diff --git a/vms/platformvm/block/builder/builder.go b/vms/platformvm/block/builder/builder.go index 09e99ba9ac3e..d98935612506 100644 --- a/vms/platformvm/block/builder/builder.go +++ b/vms/platformvm/block/builder/builder.go @@ -18,6 +18,7 @@ import ( "github.com/ava-labs/avalanchego/utils/timer/mockable" "github.com/ava-labs/avalanchego/utils/units" "github.com/ava-labs/avalanchego/vms/platformvm/block" + "github.com/ava-labs/avalanchego/vms/platformvm/fees" "github.com/ava-labs/avalanchego/vms/platformvm/state" "github.com/ava-labs/avalanchego/vms/platformvm/status" "github.com/ava-labs/avalanchego/vms/platformvm/txs" @@ -378,9 +379,10 @@ func packBlockTxs( } executor := &txexecutor.StandardTxExecutor{ - Backend: backend, - State: txDiff, - Tx: tx, + Backend: backend, + BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + State: txDiff, + Tx: tx, } err = tx.Unsigned.Visit(executor) diff --git a/vms/platformvm/block/builder/helpers_test.go b/vms/platformvm/block/builder/helpers_test.go index fa7339be6fdb..a77461dc5fcd 100644 --- a/vms/platformvm/block/builder/helpers_test.go +++ b/vms/platformvm/block/builder/helpers_test.go @@ -38,6 +38,7 @@ import ( "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/fees" "github.com/ava-labs/avalanchego/vms/platformvm/fx" "github.com/ava-labs/avalanchego/vms/platformvm/metrics" "github.com/ava-labs/avalanchego/vms/platformvm/network" @@ -237,9 +238,10 @@ func addSubnet(t *testing.T, env *environment) { require.NoError(err) executor := txexecutor.StandardTxExecutor{ - Backend: &env.backend, - State: stateDiff, - Tx: testSubnet1, + Backend: &env.backend, + BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + State: stateDiff, + Tx: testSubnet1, } require.NoError(testSubnet1.Unsigned.Visit(&executor)) @@ -298,6 +300,8 @@ func defaultConfig() *config.Config { ApricotPhase3Time: defaultValidateEndTime, ApricotPhase5Time: defaultValidateEndTime, BanffTime: time.Time{}, // neglecting fork ordering this for package tests + DurangoTime: time.Time{}, + EForkTime: mockable.MaxTime, } } diff --git a/vms/platformvm/block/executor/helpers_test.go b/vms/platformvm/block/executor/helpers_test.go index 5e7b5a3fce1e..606c61bab294 100644 --- a/vms/platformvm/block/executor/helpers_test.go +++ b/vms/platformvm/block/executor/helpers_test.go @@ -38,6 +38,7 @@ import ( "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/fees" "github.com/ava-labs/avalanchego/vms/platformvm/fx" "github.com/ava-labs/avalanchego/vms/platformvm/metrics" "github.com/ava-labs/avalanchego/vms/platformvm/reward" @@ -248,9 +249,10 @@ func addSubnet(env *environment) { } executor := executor.StandardTxExecutor{ - Backend: env.backend, - State: stateDiff, - Tx: testSubnet1, + Backend: env.backend, + BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + State: stateDiff, + Tx: testSubnet1, } err = testSubnet1.Unsigned.Visit(&executor) if err != nil { @@ -316,6 +318,8 @@ func defaultConfig() *config.Config { ApricotPhase3Time: defaultValidateEndTime, ApricotPhase5Time: defaultValidateEndTime, BanffTime: mockable.MaxTime, + DurangoTime: mockable.MaxTime, + EForkTime: mockable.MaxTime, } } diff --git a/vms/platformvm/block/executor/verifier.go b/vms/platformvm/block/executor/verifier.go index 2af7cb20912a..6e7e85e4a364 100644 --- a/vms/platformvm/block/executor/verifier.go +++ b/vms/platformvm/block/executor/verifier.go @@ -11,6 +11,7 @@ import ( "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils/set" "github.com/ava-labs/avalanchego/vms/platformvm/block" + "github.com/ava-labs/avalanchego/vms/platformvm/fees" "github.com/ava-labs/avalanchego/vms/platformvm/state" "github.com/ava-labs/avalanchego/vms/platformvm/status" "github.com/ava-labs/avalanchego/vms/platformvm/txs" @@ -455,12 +456,14 @@ func (v *verifier) processStandardTxs(txs []*txs.Tx, state state.Diff, parentID inputs set.Set[ids.ID] funcs = make([]func(), 0, len(txs)) atomicRequests = make(map[ids.ID]*atomic.Requests) + feeManager = fees.NewManager(fees.DummyUnitPrices) ) for _, tx := range txs { txExecutor := executor.StandardTxExecutor{ - Backend: v.txExecutorBackend, - State: state, - Tx: tx, + Backend: v.txExecutorBackend, + BlkFeeManager: feeManager, + State: state, + Tx: tx, } if err := tx.Unsigned.Visit(&txExecutor); err != nil { txID := tx.ID() diff --git a/vms/platformvm/fees/manager.go b/vms/platformvm/fees/manager.go index 78682723a6f6..34aaa5e4c9b0 100644 --- a/vms/platformvm/fees/manager.go +++ b/vms/platformvm/fees/manager.go @@ -22,6 +22,9 @@ type ( Dimensions [FeeDimensions]uint64 ) +// TODO ABENEGIA: drop this +var DummyUnitPrices Dimensions + type Manager struct { // Avax prices per units for all fee dimensions unitPrices Dimensions diff --git a/vms/platformvm/txs/executor/atomic_tx_executor.go b/vms/platformvm/txs/executor/atomic_tx_executor.go index 2a35cb45eeab..a0d6bbd687ee 100644 --- a/vms/platformvm/txs/executor/atomic_tx_executor.go +++ b/vms/platformvm/txs/executor/atomic_tx_executor.go @@ -7,6 +7,7 @@ import ( "github.com/ava-labs/avalanchego/chains/atomic" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils/set" + "github.com/ava-labs/avalanchego/vms/platformvm/fees" "github.com/ava-labs/avalanchego/vms/platformvm/state" "github.com/ava-labs/avalanchego/vms/platformvm/txs" ) @@ -99,9 +100,10 @@ func (e *AtomicTxExecutor) atomicTx(tx txs.UnsignedTx) error { e.OnAccept = onAccept executor := StandardTxExecutor{ - Backend: e.Backend, - State: e.OnAccept, - Tx: e.Tx, + Backend: e.Backend, + BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + State: e.OnAccept, + Tx: e.Tx, } err = tx.Visit(&executor) e.Inputs = executor.Inputs diff --git a/vms/platformvm/txs/executor/create_chain_test.go b/vms/platformvm/txs/executor/create_chain_test.go index 3b0502616473..6659fd61f600 100644 --- a/vms/platformvm/txs/executor/create_chain_test.go +++ b/vms/platformvm/txs/executor/create_chain_test.go @@ -16,6 +16,7 @@ import ( "github.com/ava-labs/avalanchego/utils/hashing" "github.com/ava-labs/avalanchego/utils/units" "github.com/ava-labs/avalanchego/vms/components/avax" + "github.com/ava-labs/avalanchego/vms/platformvm/fees" "github.com/ava-labs/avalanchego/vms/platformvm/state" "github.com/ava-labs/avalanchego/vms/platformvm/txs" "github.com/ava-labs/avalanchego/vms/platformvm/utxo" @@ -49,9 +50,10 @@ func TestCreateChainTxInsufficientControlSigs(t *testing.T) { require.NoError(err) executor := StandardTxExecutor{ - Backend: &env.backend, - State: stateDiff, - Tx: tx, + Backend: &env.backend, + BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + State: stateDiff, + Tx: tx, } err = tx.Unsigned.Visit(&executor) require.ErrorIs(err, errUnauthorizedSubnetModification) @@ -90,9 +92,10 @@ func TestCreateChainTxWrongControlSig(t *testing.T) { require.NoError(err) executor := StandardTxExecutor{ - Backend: &env.backend, - State: stateDiff, - Tx: tx, + Backend: &env.backend, + BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + State: stateDiff, + Tx: tx, } err = tx.Unsigned.Visit(&executor) require.ErrorIs(err, errUnauthorizedSubnetModification) @@ -125,9 +128,10 @@ func TestCreateChainTxNoSuchSubnet(t *testing.T) { require.NoError(err) executor := StandardTxExecutor{ - Backend: &env.backend, - State: stateDiff, - Tx: tx, + Backend: &env.backend, + BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + State: stateDiff, + Tx: tx, } err = tx.Unsigned.Visit(&executor) require.ErrorIs(err, database.ErrNotFound) @@ -157,9 +161,10 @@ func TestCreateChainTxValid(t *testing.T) { require.NoError(err) executor := StandardTxExecutor{ - Backend: &env.backend, - State: stateDiff, - Tx: tx, + Backend: &env.backend, + BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + State: stateDiff, + Tx: tx, } require.NoError(tx.Unsigned.Visit(&executor)) } @@ -231,9 +236,10 @@ func TestCreateChainTxAP3FeeChange(t *testing.T) { stateDiff.SetTimestamp(test.time) executor := StandardTxExecutor{ - Backend: &env.backend, - State: stateDiff, - Tx: tx, + Backend: &env.backend, + BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + State: stateDiff, + Tx: tx, } err = tx.Unsigned.Visit(&executor) require.ErrorIs(err, test.expectedError) diff --git a/vms/platformvm/txs/executor/create_subnet_test.go b/vms/platformvm/txs/executor/create_subnet_test.go index 158eded74867..df10f6685db4 100644 --- a/vms/platformvm/txs/executor/create_subnet_test.go +++ b/vms/platformvm/txs/executor/create_subnet_test.go @@ -12,6 +12,7 @@ import ( "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils/units" "github.com/ava-labs/avalanchego/vms/components/avax" + "github.com/ava-labs/avalanchego/vms/platformvm/fees" "github.com/ava-labs/avalanchego/vms/platformvm/state" "github.com/ava-labs/avalanchego/vms/platformvm/txs" "github.com/ava-labs/avalanchego/vms/platformvm/utxo" @@ -78,9 +79,10 @@ func TestCreateSubnetTxAP3FeeChange(t *testing.T) { stateDiff.SetTimestamp(test.time) executor := StandardTxExecutor{ - Backend: &env.backend, - State: stateDiff, - Tx: tx, + Backend: &env.backend, + BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + State: stateDiff, + Tx: tx, } err = tx.Unsigned.Visit(&executor) require.ErrorIs(err, test.expectedErr) diff --git a/vms/platformvm/txs/executor/helpers_test.go b/vms/platformvm/txs/executor/helpers_test.go index 1ea645efcfb8..caaf2d8ea5f9 100644 --- a/vms/platformvm/txs/executor/helpers_test.go +++ b/vms/platformvm/txs/executor/helpers_test.go @@ -37,6 +37,7 @@ import ( "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/fees" "github.com/ava-labs/avalanchego/vms/platformvm/fx" "github.com/ava-labs/avalanchego/vms/platformvm/metrics" "github.com/ava-labs/avalanchego/vms/platformvm/reward" @@ -205,9 +206,10 @@ func addSubnet( require.NoError(err) executor := StandardTxExecutor{ - Backend: &env.backend, - State: stateDiff, - Tx: testSubnet1, + Backend: &env.backend, + BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + State: stateDiff, + Tx: testSubnet1, } require.NoError(testSubnet1.Unsigned.Visit(&executor)) @@ -284,6 +286,7 @@ func defaultConfig(postBanff, postCortina, postDurango bool) *config.Config { BanffTime: banffTime, CortinaTime: cortinaTime, DurangoTime: durangoTime, + EForkTime: mockable.MaxTime, } } diff --git a/vms/platformvm/txs/executor/proposal_tx_executor.go b/vms/platformvm/txs/executor/proposal_tx_executor.go index c3893be429d3..adb2d4da6ebb 100644 --- a/vms/platformvm/txs/executor/proposal_tx_executor.go +++ b/vms/platformvm/txs/executor/proposal_tx_executor.go @@ -14,6 +14,7 @@ import ( "github.com/ava-labs/avalanchego/utils/math" "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/components/verify" + "github.com/ava-labs/avalanchego/vms/platformvm/fees" "github.com/ava-labs/avalanchego/vms/platformvm/reward" "github.com/ava-labs/avalanchego/vms/platformvm/state" "github.com/ava-labs/avalanchego/vms/platformvm/txs" @@ -46,7 +47,8 @@ var ( type ProposalTxExecutor struct { // inputs, to be filled before visitor methods are called *Backend - Tx *txs.Tx + BlkFeeManager *fees.Manager + Tx *txs.Tx // [OnCommitState] is the state used for validation. // [OnCommitState] is modified by this struct's methods to // reflect changes made to the state if the proposal is committed. @@ -121,6 +123,7 @@ func (e *ProposalTxExecutor) AddValidatorTx(tx *txs.AddValidatorTx) error { onAbortOuts, err := verifyAddValidatorTx( e.Backend, + e.BlkFeeManager, e.OnCommitState, e.Tx, tx, @@ -170,6 +173,7 @@ func (e *ProposalTxExecutor) AddSubnetValidatorTx(tx *txs.AddSubnetValidatorTx) if err := verifyAddSubnetValidatorTx( e.Backend, + e.BlkFeeManager, e.OnCommitState, e.Tx, tx, @@ -218,6 +222,7 @@ func (e *ProposalTxExecutor) AddDelegatorTx(tx *txs.AddDelegatorTx) error { onAbortOuts, err := verifyAddDelegatorTx( e.Backend, + e.BlkFeeManager, e.OnCommitState, e.Tx, tx, diff --git a/vms/platformvm/txs/executor/staker_tx_verification.go b/vms/platformvm/txs/executor/staker_tx_verification.go index a17bbbffc14d..d54d69ab9b15 100644 --- a/vms/platformvm/txs/executor/staker_tx_verification.go +++ b/vms/platformvm/txs/executor/staker_tx_verification.go @@ -13,6 +13,7 @@ import ( "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils/constants" "github.com/ava-labs/avalanchego/vms/components/avax" + "github.com/ava-labs/avalanchego/vms/platformvm/fees" "github.com/ava-labs/avalanchego/vms/platformvm/state" "github.com/ava-labs/avalanchego/vms/platformvm/txs" @@ -88,6 +89,7 @@ func verifySubnetValidatorPrimaryNetworkRequirements( // added to the staking set. func verifyAddValidatorTx( backend *Backend, + feeManager *fees.Manager, chainState state.Chain, sTx *txs.Tx, tx *txs.AddValidatorTx, @@ -160,6 +162,16 @@ func verifyAddValidatorTx( } // Verify the flowcheck + feeCalculator := FeeCalculator{ + Backend: backend, + ChainTime: currentTimestamp, + Tx: sTx, + feeManager: feeManager, + } + if err := tx.Visit(&feeCalculator); err != nil { + return nil, err + } + if err := backend.FlowChecker.VerifySpend( tx, chainState, @@ -167,7 +179,7 @@ func verifyAddValidatorTx( outs, sTx.Creds, map[ids.ID]uint64{ - backend.Ctx.AVAXAssetID: backend.Config.AddPrimaryNetworkValidatorFee, + backend.Ctx.AVAXAssetID: feeCalculator.Fee, }, ); err != nil { return nil, fmt.Errorf("%w: %w", ErrFlowCheckFailed, err) @@ -182,6 +194,7 @@ func verifyAddValidatorTx( // AddSubnetValidatorTx. func verifyAddSubnetValidatorTx( backend *Backend, + feeManager *fees.Manager, chainState state.Chain, sTx *txs.Tx, tx *txs.AddSubnetValidatorTx, @@ -246,6 +259,16 @@ func verifyAddSubnetValidatorTx( } // Verify the flowcheck + feeCalculator := FeeCalculator{ + Backend: backend, + ChainTime: currentTimestamp, + Tx: sTx, + feeManager: feeManager, + } + if err := tx.Visit(&feeCalculator); err != nil { + return err + } + if err := backend.FlowChecker.VerifySpend( tx, chainState, @@ -253,7 +276,7 @@ func verifyAddSubnetValidatorTx( tx.Outs, baseTxCreds, map[ids.ID]uint64{ - backend.Ctx.AVAXAssetID: backend.Config.AddSubnetValidatorFee, + backend.Ctx.AVAXAssetID: feeCalculator.Fee, }, ); err != nil { return fmt.Errorf("%w: %w", ErrFlowCheckFailed, err) @@ -274,6 +297,7 @@ func verifyAddSubnetValidatorTx( // * The flow checker passes. func verifyRemoveSubnetValidatorTx( backend *Backend, + feeManager *fees.Manager, chainState state.Chain, sTx *txs.Tx, tx *txs.RemoveSubnetValidatorTx, @@ -315,6 +339,16 @@ func verifyRemoveSubnetValidatorTx( } // Verify the flowcheck + feeCalculator := FeeCalculator{ + Backend: backend, + ChainTime: chainState.GetTimestamp(), + Tx: sTx, + feeManager: feeManager, + } + if err := tx.Visit(&feeCalculator); err != nil { + return nil, false, err + } + if err := backend.FlowChecker.VerifySpend( tx, chainState, @@ -322,7 +356,7 @@ func verifyRemoveSubnetValidatorTx( tx.Outs, baseTxCreds, map[ids.ID]uint64{ - backend.Ctx.AVAXAssetID: backend.Config.TxFee, + backend.Ctx.AVAXAssetID: feeCalculator.Fee, }, ); err != nil { return nil, false, fmt.Errorf("%w: %w", ErrFlowCheckFailed, err) @@ -336,6 +370,7 @@ func verifyRemoveSubnetValidatorTx( // added to the staking set. func verifyAddDelegatorTx( backend *Backend, + feeManager *fees.Manager, chainState state.Chain, sTx *txs.Tx, tx *txs.AddDelegatorTx, @@ -427,6 +462,16 @@ func verifyAddDelegatorTx( } // Verify the flowcheck + feeCalculator := FeeCalculator{ + Backend: backend, + ChainTime: chainState.GetTimestamp(), + Tx: sTx, + feeManager: feeManager, + } + if err := tx.Visit(&feeCalculator); err != nil { + return nil, err + } + if err := backend.FlowChecker.VerifySpend( tx, chainState, @@ -434,7 +479,7 @@ func verifyAddDelegatorTx( outs, sTx.Creds, map[ids.ID]uint64{ - backend.Ctx.AVAXAssetID: backend.Config.AddPrimaryNetworkDelegatorFee, + backend.Ctx.AVAXAssetID: feeCalculator.Fee, }, ); err != nil { return nil, fmt.Errorf("%w: %w", ErrFlowCheckFailed, err) @@ -449,6 +494,7 @@ func verifyAddDelegatorTx( // AddPermissionlessValidatorTx. func verifyAddPermissionlessValidatorTx( backend *Backend, + feeManager *fees.Manager, chainState state.Chain, sTx *txs.Tx, tx *txs.AddPermissionlessValidatorTx, @@ -531,15 +577,10 @@ func verifyAddPermissionlessValidatorTx( ) } - var txFee uint64 if tx.Subnet != constants.PrimaryNetworkID { if err := verifySubnetValidatorPrimaryNetworkRequirements(isDurangoActive, chainState, tx.Validator); err != nil { return err } - - txFee = backend.Config.AddSubnetValidatorFee - } else { - txFee = backend.Config.AddPrimaryNetworkValidatorFee } outs := make([]*avax.TransferableOutput, len(tx.Outs)+len(tx.StakeOuts)) @@ -547,6 +588,16 @@ func verifyAddPermissionlessValidatorTx( copy(outs[len(tx.Outs):], tx.StakeOuts) // Verify the flowcheck + feeCalculator := FeeCalculator{ + Backend: backend, + ChainTime: currentTimestamp, + Tx: sTx, + feeManager: feeManager, + } + if err := tx.Visit(&feeCalculator); err != nil { + return err + } + if err := backend.FlowChecker.VerifySpend( tx, chainState, @@ -554,7 +605,7 @@ func verifyAddPermissionlessValidatorTx( outs, sTx.Creds, map[ids.ID]uint64{ - backend.Ctx.AVAXAssetID: txFee, + backend.Ctx.AVAXAssetID: feeCalculator.Fee, }, ); err != nil { return fmt.Errorf("%w: %w", ErrFlowCheckFailed, err) @@ -569,6 +620,7 @@ func verifyAddPermissionlessValidatorTx( // AddPermissionlessDelegatorTx. func verifyAddPermissionlessDelegatorTx( backend *Backend, + feeManager *fees.Manager, chainState state.Chain, sTx *txs.Tx, tx *txs.AddPermissionlessDelegatorTx, @@ -672,7 +724,6 @@ func verifyAddPermissionlessDelegatorTx( copy(outs, tx.Outs) copy(outs[len(tx.Outs):], tx.StakeOuts) - var txFee uint64 if tx.Subnet != constants.PrimaryNetworkID { // Invariant: Delegators must only be able to reference validator // transactions that implement [txs.ValidatorTx]. All @@ -683,13 +734,19 @@ func verifyAddPermissionlessDelegatorTx( if validator.Priority.IsPermissionedValidator() { return ErrDelegateToPermissionedValidator } - - txFee = backend.Config.AddSubnetDelegatorFee - } else { - txFee = backend.Config.AddPrimaryNetworkDelegatorFee } // Verify the flowcheck + feeCalculator := FeeCalculator{ + Backend: backend, + ChainTime: currentTimestamp, + Tx: sTx, + feeManager: feeManager, + } + if err := tx.Visit(&feeCalculator); err != nil { + return err + } + if err := backend.FlowChecker.VerifySpend( tx, chainState, @@ -697,7 +754,7 @@ func verifyAddPermissionlessDelegatorTx( outs, sTx.Creds, map[ids.ID]uint64{ - backend.Ctx.AVAXAssetID: txFee, + backend.Ctx.AVAXAssetID: feeCalculator.Fee, }, ); err != nil { return fmt.Errorf("%w: %w", ErrFlowCheckFailed, err) @@ -715,6 +772,7 @@ func verifyAddPermissionlessDelegatorTx( // * The flow checker passes. func verifyTransferSubnetOwnershipTx( backend *Backend, + feeManager *fees.Manager, chainState state.Chain, sTx *txs.Tx, tx *txs.TransferSubnetOwnershipTx, @@ -739,6 +797,16 @@ func verifyTransferSubnetOwnershipTx( } // Verify the flowcheck + feeCalculator := FeeCalculator{ + Backend: backend, + ChainTime: chainState.GetTimestamp(), + Tx: sTx, + feeManager: feeManager, + } + if err := tx.Visit(&feeCalculator); err != nil { + return err + } + if err := backend.FlowChecker.VerifySpend( tx, chainState, @@ -746,7 +814,7 @@ func verifyTransferSubnetOwnershipTx( tx.Outs, baseTxCreds, map[ids.ID]uint64{ - backend.Ctx.AVAXAssetID: backend.Config.TxFee, + backend.Ctx.AVAXAssetID: feeCalculator.Fee, }, ); err != nil { return fmt.Errorf("%w: %w", ErrFlowCheckFailed, err) diff --git a/vms/platformvm/txs/executor/staker_tx_verification_test.go b/vms/platformvm/txs/executor/staker_tx_verification_test.go index b59daf0da2b0..4a8906d82cc4 100644 --- a/vms/platformvm/txs/executor/staker_tx_verification_test.go +++ b/vms/platformvm/txs/executor/staker_tx_verification_test.go @@ -21,6 +21,7 @@ import ( "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/components/verify" "github.com/ava-labs/avalanchego/vms/platformvm/config" + "github.com/ava-labs/avalanchego/vms/platformvm/fees" "github.com/ava-labs/avalanchego/vms/platformvm/state" "github.com/ava-labs/avalanchego/vms/platformvm/txs" "github.com/ava-labs/avalanchego/vms/platformvm/utxo" @@ -113,6 +114,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { Ctx: ctx, Config: &config.Config{ DurangoTime: activeForkTime, // activate latest fork + EForkTime: mockable.MaxTime, }, } }, @@ -134,6 +136,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { Ctx: ctx, Config: &config.Config{ DurangoTime: activeForkTime, // activate latest fork + EForkTime: mockable.MaxTime, }, Bootstrapped: &utils.Atomic[bool]{}, } @@ -159,6 +162,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { Config: &config.Config{ CortinaTime: activeForkTime, DurangoTime: mockable.MaxTime, + EForkTime: mockable.MaxTime, }, Bootstrapped: bootstrapped, } @@ -185,6 +189,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { Ctx: ctx, Config: &config.Config{ DurangoTime: activeForkTime, // activate latest fork + EForkTime: mockable.MaxTime, }, Bootstrapped: bootstrapped, } @@ -214,6 +219,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { Ctx: ctx, Config: &config.Config{ DurangoTime: activeForkTime, // activate latest fork + EForkTime: mockable.MaxTime, }, Bootstrapped: bootstrapped, } @@ -243,6 +249,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { Ctx: ctx, Config: &config.Config{ DurangoTime: activeForkTime, // activate latest fork + EForkTime: mockable.MaxTime, }, Bootstrapped: bootstrapped, } @@ -273,6 +280,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { Ctx: ctx, Config: &config.Config{ DurangoTime: activeForkTime, // activate latest fork + EForkTime: mockable.MaxTime, }, Bootstrapped: bootstrapped, } @@ -306,6 +314,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { Ctx: ctx, Config: &config.Config{ DurangoTime: activeForkTime, // activate latest fork + EForkTime: mockable.MaxTime, }, Bootstrapped: bootstrapped, } @@ -339,6 +348,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { Ctx: ctx, Config: &config.Config{ DurangoTime: activeForkTime, // activate latest fork + EForkTime: mockable.MaxTime, }, Bootstrapped: bootstrapped, } @@ -374,6 +384,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { Ctx: ctx, Config: &config.Config{ DurangoTime: activeForkTime, // activate latest fork + EForkTime: mockable.MaxTime, }, Bootstrapped: bootstrapped, } @@ -403,6 +414,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { Ctx: ctx, Config: &config.Config{ DurangoTime: activeForkTime, // activate latest fork + EForkTime: mockable.MaxTime, }, Bootstrapped: bootstrapped, } @@ -449,6 +461,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { Config: &config.Config{ AddSubnetValidatorFee: 1, DurangoTime: activeForkTime, // activate latest fork, + EForkTime: mockable.MaxTime, }, Ctx: ctx, Bootstrapped: bootstrapped, @@ -495,6 +508,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { Config: &config.Config{ CortinaTime: activeForkTime, DurangoTime: mockable.MaxTime, + EForkTime: mockable.MaxTime, AddSubnetValidatorFee: 1, }, Ctx: ctx, @@ -547,6 +561,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { Config: &config.Config{ AddSubnetValidatorFee: 1, DurangoTime: activeForkTime, // activate latest fork, + EForkTime: mockable.MaxTime, }, Ctx: ctx, Bootstrapped: bootstrapped, @@ -579,13 +594,14 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { ctrl := gomock.NewController(t) var ( - backend = tt.backendF(ctrl) - state = tt.stateF(ctrl) - sTx = tt.sTxF() - tx = tt.txF() + backend = tt.backendF(ctrl) + feeManager = fees.NewManager(fees.DummyUnitPrices) + state = tt.stateF(ctrl) + sTx = tt.sTxF() + tx = tt.txF() ) - err := verifyAddPermissionlessValidatorTx(backend, state, sTx, tx) + err := verifyAddPermissionlessValidatorTx(backend, feeManager, state, sTx, tx) require.ErrorIs(t, err, tt.expectedErr) }) } diff --git a/vms/platformvm/txs/executor/standard_tx_executor.go b/vms/platformvm/txs/executor/standard_tx_executor.go index e780673e6431..bfbd7ddaed32 100644 --- a/vms/platformvm/txs/executor/standard_tx_executor.go +++ b/vms/platformvm/txs/executor/standard_tx_executor.go @@ -17,6 +17,7 @@ import ( "github.com/ava-labs/avalanchego/utils/set" "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/components/verify" + "github.com/ava-labs/avalanchego/vms/platformvm/fees" "github.com/ava-labs/avalanchego/vms/platformvm/state" "github.com/ava-labs/avalanchego/vms/platformvm/txs" ) @@ -32,8 +33,9 @@ var ( type StandardTxExecutor struct { // inputs, to be filled before visitor methods are called *Backend - State state.Diff // state is expected to be modified - Tx *txs.Tx + BlkFeeManager *fees.Manager + State state.Diff // state is expected to be modified + Tx *txs.Tx // outputs of visitor execution OnAccept func() // may be nil @@ -60,8 +62,16 @@ func (e *StandardTxExecutor) CreateChainTx(tx *txs.CreateChainTx) error { } // Verify the flowcheck - timestamp := e.State.GetTimestamp() - createBlockchainTxFee := e.Config.GetCreateBlockchainTxFee(timestamp) + feeCalculator := FeeCalculator{ + Backend: e.Backend, + ChainTime: e.State.GetTimestamp(), + Tx: e.Tx, + feeManager: e.BlkFeeManager, + } + if err := tx.Visit(&feeCalculator); err != nil { + return err + } + if err := e.FlowChecker.VerifySpend( tx, e.State, @@ -69,7 +79,7 @@ func (e *StandardTxExecutor) CreateChainTx(tx *txs.CreateChainTx) error { tx.Outs, baseTxCreds, map[ids.ID]uint64{ - e.Ctx.AVAXAssetID: createBlockchainTxFee, + e.Ctx.AVAXAssetID: feeCalculator.Fee, }, ); err != nil { return err @@ -99,8 +109,16 @@ func (e *StandardTxExecutor) CreateSubnetTx(tx *txs.CreateSubnetTx) error { } // Verify the flowcheck - timestamp := e.State.GetTimestamp() - createSubnetTxFee := e.Config.GetCreateSubnetTxFee(timestamp) + feeCalculator := FeeCalculator{ + Backend: e.Backend, + ChainTime: e.State.GetTimestamp(), + Tx: e.Tx, + feeManager: e.BlkFeeManager, + } + if err := tx.Visit(&feeCalculator); err != nil { + return err + } + if err := e.FlowChecker.VerifySpend( tx, e.State, @@ -108,7 +126,7 @@ func (e *StandardTxExecutor) CreateSubnetTx(tx *txs.CreateSubnetTx) error { tx.Outs, e.Tx.Creds, map[ids.ID]uint64{ - e.Ctx.AVAXAssetID: createSubnetTxFee, + e.Ctx.AVAXAssetID: feeCalculator.Fee, }, ); err != nil { return err @@ -172,6 +190,17 @@ func (e *StandardTxExecutor) ImportTx(tx *txs.ImportTx) error { copy(ins, tx.Ins) copy(ins[len(tx.Ins):], tx.ImportedInputs) + // Verify the flowcheck + feeCalculator := FeeCalculator{ + Backend: e.Backend, + ChainTime: e.State.GetTimestamp(), + Tx: e.Tx, + feeManager: e.BlkFeeManager, + } + if err := tx.Visit(&feeCalculator); err != nil { + return err + } + if err := e.FlowChecker.VerifySpendUTXOs( tx, utxos, @@ -179,7 +208,7 @@ func (e *StandardTxExecutor) ImportTx(tx *txs.ImportTx) error { tx.Outs, e.Tx.Creds, map[ids.ID]uint64{ - e.Ctx.AVAXAssetID: e.Config.TxFee, + e.Ctx.AVAXAssetID: feeCalculator.Fee, }, ); err != nil { return err @@ -220,6 +249,16 @@ func (e *StandardTxExecutor) ExportTx(tx *txs.ExportTx) error { } // Verify the flowcheck + feeCalculator := FeeCalculator{ + Backend: e.Backend, + ChainTime: e.State.GetTimestamp(), + Tx: e.Tx, + feeManager: e.BlkFeeManager, + } + if err := tx.Visit(&feeCalculator); err != nil { + return err + } + if err := e.FlowChecker.VerifySpend( tx, e.State, @@ -227,7 +266,7 @@ func (e *StandardTxExecutor) ExportTx(tx *txs.ExportTx) error { outs, e.Tx.Creds, map[ids.ID]uint64{ - e.Ctx.AVAXAssetID: e.Config.TxFee, + e.Ctx.AVAXAssetID: feeCalculator.Fee, }, ); err != nil { return fmt.Errorf("failed verifySpend: %w", err) @@ -284,6 +323,7 @@ func (e *StandardTxExecutor) AddValidatorTx(tx *txs.AddValidatorTx) error { if _, err := verifyAddValidatorTx( e.Backend, + e.BlkFeeManager, e.State, e.Tx, tx, @@ -313,6 +353,7 @@ func (e *StandardTxExecutor) AddValidatorTx(tx *txs.AddValidatorTx) error { func (e *StandardTxExecutor) AddSubnetValidatorTx(tx *txs.AddSubnetValidatorTx) error { if err := verifyAddSubnetValidatorTx( e.Backend, + e.BlkFeeManager, e.State, e.Tx, tx, @@ -333,6 +374,7 @@ func (e *StandardTxExecutor) AddSubnetValidatorTx(tx *txs.AddSubnetValidatorTx) func (e *StandardTxExecutor) AddDelegatorTx(tx *txs.AddDelegatorTx) error { if _, err := verifyAddDelegatorTx( e.Backend, + e.BlkFeeManager, e.State, e.Tx, tx, @@ -358,6 +400,7 @@ func (e *StandardTxExecutor) AddDelegatorTx(tx *txs.AddDelegatorTx) error { func (e *StandardTxExecutor) RemoveSubnetValidatorTx(tx *txs.RemoveSubnetValidatorTx) error { staker, isCurrentValidator, err := verifyRemoveSubnetValidatorTx( e.Backend, + e.BlkFeeManager, e.State, e.Tx, tx, @@ -430,6 +473,7 @@ func (e *StandardTxExecutor) TransformSubnetTx(tx *txs.TransformSubnetTx) error func (e *StandardTxExecutor) AddPermissionlessValidatorTx(tx *txs.AddPermissionlessValidatorTx) error { if err := verifyAddPermissionlessValidatorTx( e.Backend, + e.BlkFeeManager, e.State, e.Tx, tx, @@ -462,6 +506,7 @@ func (e *StandardTxExecutor) AddPermissionlessValidatorTx(tx *txs.AddPermissionl func (e *StandardTxExecutor) AddPermissionlessDelegatorTx(tx *txs.AddPermissionlessDelegatorTx) error { if err := verifyAddPermissionlessDelegatorTx( e.Backend, + e.BlkFeeManager, e.State, e.Tx, tx, @@ -486,6 +531,7 @@ func (e *StandardTxExecutor) AddPermissionlessDelegatorTx(tx *txs.AddPermissionl func (e *StandardTxExecutor) TransferSubnetOwnershipTx(tx *txs.TransferSubnetOwnershipTx) error { err := verifyTransferSubnetOwnershipTx( e.Backend, + e.BlkFeeManager, e.State, e.Tx, tx, diff --git a/vms/platformvm/txs/executor/standard_tx_executor_test.go b/vms/platformvm/txs/executor/standard_tx_executor_test.go index a86c579fee79..dbbe196fc084 100644 --- a/vms/platformvm/txs/executor/standard_tx_executor_test.go +++ b/vms/platformvm/txs/executor/standard_tx_executor_test.go @@ -21,9 +21,11 @@ import ( "github.com/ava-labs/avalanchego/utils/constants" "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" "github.com/ava-labs/avalanchego/utils/hashing" + "github.com/ava-labs/avalanchego/utils/timer/mockable" "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/components/verify" "github.com/ava-labs/avalanchego/vms/platformvm/config" + "github.com/ava-labs/avalanchego/vms/platformvm/fees" "github.com/ava-labs/avalanchego/vms/platformvm/fx" "github.com/ava-labs/avalanchego/vms/platformvm/reward" "github.com/ava-labs/avalanchego/vms/platformvm/state" @@ -87,9 +89,10 @@ func TestStandardTxExecutorAddValidatorTxEmptyID(t *testing.T) { require.NoError(err) executor := StandardTxExecutor{ - Backend: &env.backend, - State: stateDiff, - Tx: tx, + Backend: &env.backend, + BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + State: stateDiff, + Tx: tx, } err = tx.Unsigned.Visit(&executor) require.ErrorIs(err, test.expectedError) @@ -357,9 +360,10 @@ func TestStandardTxExecutorAddDelegator(t *testing.T) { freshTH.config.BanffTime = onAcceptState.GetTimestamp() executor := StandardTxExecutor{ - Backend: &freshTH.backend, - State: onAcceptState, - Tx: tx, + Backend: &freshTH.backend, + BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + State: onAcceptState, + Tx: tx, } err = tx.Unsigned.Visit(&executor) require.ErrorIs(err, tt.expectedExecutionErr) @@ -406,9 +410,10 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { require.NoError(err) executor := StandardTxExecutor{ - Backend: &env.backend, - State: onAcceptState, - Tx: tx, + Backend: &env.backend, + BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + State: onAcceptState, + Tx: tx, } err = tx.Unsigned.Visit(&executor) require.ErrorIs(err, ErrPeriodMismatch) @@ -434,9 +439,10 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { require.NoError(err) executor := StandardTxExecutor{ - Backend: &env.backend, - State: onAcceptState, - Tx: tx, + Backend: &env.backend, + BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + State: onAcceptState, + Tx: tx, } require.NoError(tx.Unsigned.Visit(&executor)) } @@ -476,9 +482,10 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { require.NoError(err) executor := StandardTxExecutor{ - Backend: &env.backend, - State: onAcceptState, - Tx: tx, + Backend: &env.backend, + BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + State: onAcceptState, + Tx: tx, } err = tx.Unsigned.Visit(&executor) require.ErrorIs(err, ErrNotValidator) @@ -519,9 +526,10 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { require.NoError(err) executor := StandardTxExecutor{ - Backend: &env.backend, - State: onAcceptState, - Tx: tx, + Backend: &env.backend, + BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + State: onAcceptState, + Tx: tx, } err = tx.Unsigned.Visit(&executor) require.ErrorIs(err, ErrPeriodMismatch) @@ -545,9 +553,10 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { require.NoError(err) executor := StandardTxExecutor{ - Backend: &env.backend, - State: onAcceptState, - Tx: tx, + Backend: &env.backend, + BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + State: onAcceptState, + Tx: tx, } err = tx.Unsigned.Visit(&executor) require.ErrorIs(err, ErrPeriodMismatch) @@ -570,9 +579,10 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { onAcceptState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) executor := StandardTxExecutor{ - Backend: &env.backend, - State: onAcceptState, - Tx: tx, + Backend: &env.backend, + BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + State: onAcceptState, + Tx: tx, } require.NoError(tx.Unsigned.Visit(&executor)) } @@ -598,9 +608,10 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { require.NoError(err) executor := StandardTxExecutor{ - Backend: &env.backend, - State: onAcceptState, - Tx: tx, + Backend: &env.backend, + BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + State: onAcceptState, + Tx: tx, } err = tx.Unsigned.Visit(&executor) require.ErrorIs(err, ErrTimestampNotBeforeStartTime) @@ -654,9 +665,10 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { require.NoError(err) executor := StandardTxExecutor{ - Backend: &env.backend, - State: onAcceptState, - Tx: duplicateSubnetTx, + Backend: &env.backend, + BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + State: onAcceptState, + Tx: duplicateSubnetTx, } err = duplicateSubnetTx.Unsigned.Visit(&executor) require.ErrorIs(err, ErrDuplicateValidator) @@ -691,9 +703,10 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { require.NoError(err) executor := StandardTxExecutor{ - Backend: &env.backend, - State: onAcceptState, - Tx: tx, + Backend: &env.backend, + BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + State: onAcceptState, + Tx: tx, } err = tx.Unsigned.Visit(&executor) require.ErrorIs(err, secp256k1fx.ErrInputIndicesNotSortedUnique) @@ -724,9 +737,10 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { require.NoError(err) executor := StandardTxExecutor{ - Backend: &env.backend, - State: onAcceptState, - Tx: tx, + Backend: &env.backend, + BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + State: onAcceptState, + Tx: tx, } err = tx.Unsigned.Visit(&executor) require.ErrorIs(err, errUnauthorizedSubnetModification) @@ -755,9 +769,10 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { require.NoError(err) executor := StandardTxExecutor{ - Backend: &env.backend, - State: onAcceptState, - Tx: tx, + Backend: &env.backend, + BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + State: onAcceptState, + Tx: tx, } err = tx.Unsigned.Visit(&executor) require.ErrorIs(err, errUnauthorizedSubnetModification) @@ -796,9 +811,10 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { require.NoError(err) executor := StandardTxExecutor{ - Backend: &env.backend, - State: onAcceptState, - Tx: tx, + Backend: &env.backend, + BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + State: onAcceptState, + Tx: tx, } err = tx.Unsigned.Visit(&executor) require.ErrorIs(err, ErrDuplicateValidator) @@ -833,9 +849,10 @@ func TestStandardTxExecutorBanffAddValidator(t *testing.T) { require.NoError(err) executor := StandardTxExecutor{ - Backend: &env.backend, - State: onAcceptState, - Tx: tx, + Backend: &env.backend, + BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + State: onAcceptState, + Tx: tx, } err = tx.Unsigned.Visit(&executor) require.ErrorIs(err, ErrTimestampNotBeforeStartTime) @@ -859,9 +876,10 @@ func TestStandardTxExecutorBanffAddValidator(t *testing.T) { require.NoError(err) executor := StandardTxExecutor{ - Backend: &env.backend, - State: onAcceptState, - Tx: tx, + Backend: &env.backend, + BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + State: onAcceptState, + Tx: tx, } err = tx.Unsigned.Visit(&executor) require.ErrorIs(err, ErrFutureStakeTime) @@ -898,9 +916,10 @@ func TestStandardTxExecutorBanffAddValidator(t *testing.T) { onAcceptState.AddTx(tx, status.Committed) executor := StandardTxExecutor{ - Backend: &env.backend, - State: onAcceptState, - Tx: tx, + Backend: &env.backend, + BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + State: onAcceptState, + Tx: tx, } err = tx.Unsigned.Visit(&executor) require.ErrorIs(err, ErrAlreadyValidator) @@ -934,9 +953,10 @@ func TestStandardTxExecutorBanffAddValidator(t *testing.T) { onAcceptState.AddTx(tx, status.Committed) executor := StandardTxExecutor{ - Backend: &env.backend, - State: onAcceptState, - Tx: tx, + Backend: &env.backend, + BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + State: onAcceptState, + Tx: tx, } err = tx.Unsigned.Visit(&executor) require.ErrorIs(err, ErrAlreadyValidator) @@ -969,9 +989,10 @@ func TestStandardTxExecutorBanffAddValidator(t *testing.T) { } executor := StandardTxExecutor{ - Backend: &env.backend, - State: onAcceptState, - Tx: tx, + Backend: &env.backend, + BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + State: onAcceptState, + Tx: tx, } err = tx.Unsigned.Visit(&executor) require.ErrorIs(err, ErrFlowCheckFailed) @@ -1135,6 +1156,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { // Set dependency expectations. env.state.EXPECT().GetCurrentValidator(env.unsignedTx.Subnet, env.unsignedTx.NodeID).Return(env.staker, nil).Times(1) + env.state.EXPECT().GetTimestamp().Return(time.Now()) subnetOwner := fx.NewMockOwner(ctrl) env.state.EXPECT().GetSubnetOwner(env.unsignedTx.Subnet).Return(subnetOwner, nil).Times(1) env.fx.EXPECT().VerifyPermission(env.unsignedTx, env.unsignedTx.SubnetAuth, env.tx.Creds[len(env.tx.Creds)-1], subnetOwner).Return(nil).Times(1) @@ -1150,14 +1172,16 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { BanffTime: env.latestForkTime, CortinaTime: env.latestForkTime, DurangoTime: env.latestForkTime, + EForkTime: mockable.MaxTime, }, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - Tx: env.tx, - State: env.state, + BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + Tx: env.tx, + State: env.state, } e.Bootstrapped.Set(true) return env.unsignedTx, e @@ -1177,14 +1201,16 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { BanffTime: env.latestForkTime, CortinaTime: env.latestForkTime, DurangoTime: env.latestForkTime, + EForkTime: mockable.MaxTime, }, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - Tx: env.tx, - State: env.state, + BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + Tx: env.tx, + State: env.state, } e.Bootstrapped.Set(true) return env.unsignedTx, e @@ -1204,14 +1230,16 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { BanffTime: env.latestForkTime, CortinaTime: env.latestForkTime, DurangoTime: env.latestForkTime, + EForkTime: mockable.MaxTime, }, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - Tx: env.tx, - State: env.state, + BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + Tx: env.tx, + State: env.state, } e.Bootstrapped.Set(true) return env.unsignedTx, e @@ -1234,14 +1262,16 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { BanffTime: env.latestForkTime, CortinaTime: env.latestForkTime, DurangoTime: env.latestForkTime, + EForkTime: mockable.MaxTime, }, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - Tx: env.tx, - State: env.state, + BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + Tx: env.tx, + State: env.state, } e.Bootstrapped.Set(true) return env.unsignedTx, e @@ -1262,14 +1292,16 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { BanffTime: env.latestForkTime, CortinaTime: env.latestForkTime, DurangoTime: env.latestForkTime, + EForkTime: mockable.MaxTime, }, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - Tx: env.tx, - State: env.state, + BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + Tx: env.tx, + State: env.state, } e.Bootstrapped.Set(true) return env.unsignedTx, e @@ -1289,14 +1321,16 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { BanffTime: env.latestForkTime, CortinaTime: env.latestForkTime, DurangoTime: env.latestForkTime, + EForkTime: mockable.MaxTime, }, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - Tx: env.tx, - State: env.state, + BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + Tx: env.tx, + State: env.state, } e.Bootstrapped.Set(true) return env.unsignedTx, e @@ -1318,14 +1352,16 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { BanffTime: env.latestForkTime, CortinaTime: env.latestForkTime, DurangoTime: env.latestForkTime, + EForkTime: mockable.MaxTime, }, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - Tx: env.tx, - State: env.state, + BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + Tx: env.tx, + State: env.state, } e.Bootstrapped.Set(true) return env.unsignedTx, e @@ -1337,6 +1373,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { newExecutor: func(ctrl *gomock.Controller) (*txs.RemoveSubnetValidatorTx, *StandardTxExecutor) { env := newValidRemoveSubnetValidatorTxVerifyEnv(t, ctrl) env.state = state.NewMockDiff(ctrl) + env.state.EXPECT().GetTimestamp().Return(time.Now()) env.state.EXPECT().GetCurrentValidator(env.unsignedTx.Subnet, env.unsignedTx.NodeID).Return(env.staker, nil) subnetOwner := fx.NewMockOwner(ctrl) env.state.EXPECT().GetSubnetOwner(env.unsignedTx.Subnet).Return(subnetOwner, nil) @@ -1350,14 +1387,16 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { BanffTime: env.latestForkTime, CortinaTime: env.latestForkTime, DurangoTime: env.latestForkTime, + EForkTime: mockable.MaxTime, }, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - Tx: env.tx, - State: env.state, + BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + Tx: env.tx, + State: env.state, } e.Bootstrapped.Set(true) return env.unsignedTx, e @@ -1507,14 +1546,16 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { BanffTime: env.latestForkTime, CortinaTime: env.latestForkTime, DurangoTime: env.latestForkTime, + EForkTime: mockable.MaxTime, }, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - Tx: env.tx, - State: env.state, + BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + Tx: env.tx, + State: env.state, } e.Bootstrapped.Set(true) return env.unsignedTx, e @@ -1533,14 +1574,16 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { BanffTime: env.latestForkTime, CortinaTime: env.latestForkTime, DurangoTime: env.latestForkTime, + EForkTime: mockable.MaxTime, }, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - Tx: env.tx, - State: env.state, + BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + Tx: env.tx, + State: env.state, } e.Bootstrapped.Set(true) return env.unsignedTx, e @@ -1560,6 +1603,7 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { BanffTime: env.latestForkTime, CortinaTime: env.latestForkTime, DurangoTime: env.latestForkTime, + EForkTime: mockable.MaxTime, MaxStakeDuration: math.MaxInt64, }, Bootstrapped: &utils.Atomic[bool]{}, @@ -1567,8 +1611,9 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - Tx: env.tx, - State: env.state, + BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + Tx: env.tx, + State: env.state, } e.Bootstrapped.Set(true) return env.unsignedTx, e @@ -1593,6 +1638,7 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { BanffTime: env.latestForkTime, CortinaTime: env.latestForkTime, DurangoTime: env.latestForkTime, + EForkTime: mockable.MaxTime, MaxStakeDuration: math.MaxInt64, }, Bootstrapped: &utils.Atomic[bool]{}, @@ -1600,8 +1646,9 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - Tx: env.tx, - State: env.state, + BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + Tx: env.tx, + State: env.state, } e.Bootstrapped.Set(true) return env.unsignedTx, e @@ -1631,6 +1678,7 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { BanffTime: env.latestForkTime, CortinaTime: env.latestForkTime, DurangoTime: env.latestForkTime, + EForkTime: mockable.MaxTime, MaxStakeDuration: math.MaxInt64, }, Bootstrapped: &utils.Atomic[bool]{}, @@ -1638,8 +1686,9 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - Tx: env.tx, - State: env.state, + BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + Tx: env.tx, + State: env.state, } e.Bootstrapped.Set(true) return env.unsignedTx, e diff --git a/vms/platformvm/txs/executor/tx_mempool_verifier.go b/vms/platformvm/txs/executor/tx_mempool_verifier.go index f2e7d09673e6..7ad0cbc84d81 100644 --- a/vms/platformvm/txs/executor/tx_mempool_verifier.go +++ b/vms/platformvm/txs/executor/tx_mempool_verifier.go @@ -10,6 +10,7 @@ import ( "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils/timer/mockable" + "github.com/ava-labs/avalanchego/vms/platformvm/fees" "github.com/ava-labs/avalanchego/vms/platformvm/state" "github.com/ava-labs/avalanchego/vms/platformvm/txs" ) @@ -90,9 +91,10 @@ func (v *MempoolTxVerifier) standardTx(tx txs.UnsignedTx) error { } executor := StandardTxExecutor{ - Backend: v.Backend, - State: baseState, - Tx: v.Tx, + Backend: v.Backend, + BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + State: baseState, + Tx: v.Tx, } err = tx.Visit(&executor) // We ignore [errFutureStakeTime] here because the time will be advanced diff --git a/vms/platformvm/validator_set_property_test.go b/vms/platformvm/validator_set_property_test.go index 5ca5bfd6c241..ca161f744011 100644 --- a/vms/platformvm/validator_set_property_test.go +++ b/vms/platformvm/validator_set_property_test.go @@ -730,6 +730,8 @@ func buildVM(t *testing.T) (*VM, ids.ID, error) { ApricotPhase5Time: forkTime, BanffTime: forkTime, CortinaTime: forkTime, + DurangoTime: forkTime, + EForkTime: mockable.MaxTime, }} vm.clock.Set(forkTime.Add(time.Second)) diff --git a/vms/platformvm/vm_regression_test.go b/vms/platformvm/vm_regression_test.go index 36186ec32ae0..a82cf6f76c67 100644 --- a/vms/platformvm/vm_regression_test.go +++ b/vms/platformvm/vm_regression_test.go @@ -373,6 +373,7 @@ func TestUnverifiedParentPanicRegression(t *testing.T) { BanffTime: latestForkTime, CortinaTime: mockable.MaxTime, DurangoTime: mockable.MaxTime, + EForkTime: mockable.MaxTime, }} ctx := snowtest.Context(t, snowtest.PChainID) diff --git a/vms/platformvm/vm_test.go b/vms/platformvm/vm_test.go index 23e88a646368..6c8733550d09 100644 --- a/vms/platformvm/vm_test.go +++ b/vms/platformvm/vm_test.go @@ -252,6 +252,7 @@ func defaultVM(t *testing.T, fork activeFork) (*VM, database.Database, *mutableS BanffTime: banffTime, CortinaTime: cortinaTime, DurangoTime: durangoTime, + EForkTime: mockable.MaxTime, }} db := memdb.New() @@ -1135,6 +1136,7 @@ func TestRestartFullyAccepted(t *testing.T) { BanffTime: latestForkTime, CortinaTime: latestForkTime, DurangoTime: latestForkTime, + EForkTime: mockable.MaxTime, }} firstCtx := snowtest.Context(t, snowtest.PChainID) @@ -1222,6 +1224,7 @@ func TestRestartFullyAccepted(t *testing.T) { BanffTime: latestForkTime, CortinaTime: latestForkTime, DurangoTime: latestForkTime, + EForkTime: mockable.MaxTime, }} secondCtx := snowtest.Context(t, snowtest.PChainID) @@ -1272,6 +1275,7 @@ func TestBootstrapPartiallyAccepted(t *testing.T) { BanffTime: latestForkTime, CortinaTime: latestForkTime, DurangoTime: latestForkTime, + EForkTime: mockable.MaxTime, }} initialClkTime := latestForkTime.Add(time.Second) @@ -1613,6 +1617,7 @@ func TestUnverifiedParent(t *testing.T) { BanffTime: latestForkTime, CortinaTime: latestForkTime, DurangoTime: latestForkTime, + EForkTime: mockable.MaxTime, }} initialClkTime := latestForkTime.Add(time.Second) @@ -1776,6 +1781,7 @@ func TestUptimeDisallowedWithRestart(t *testing.T) { BanffTime: latestForkTime, CortinaTime: latestForkTime, DurangoTime: latestForkTime, + EForkTime: mockable.MaxTime, }} firstCtx := snowtest.Context(t, snowtest.PChainID) @@ -1824,6 +1830,7 @@ func TestUptimeDisallowedWithRestart(t *testing.T) { BanffTime: latestForkTime, CortinaTime: latestForkTime, DurangoTime: latestForkTime, + EForkTime: mockable.MaxTime, }} secondCtx := snowtest.Context(t, snowtest.PChainID) @@ -1923,6 +1930,7 @@ func TestUptimeDisallowedAfterNeverConnecting(t *testing.T) { BanffTime: latestForkTime, CortinaTime: latestForkTime, DurangoTime: latestForkTime, + EForkTime: mockable.MaxTime, }} ctx := snowtest.Context(t, snowtest.PChainID) From b7a539cd0cfc73a66bb8829f89a14aa5470487ba Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 8 Jan 2024 15:58:54 +0100 Subject: [PATCH 005/190] fixed leftovers --- vms/platformvm/fees/manager.go | 2 ++ vms/platformvm/txs/executor/standard_tx_executor.go | 12 +++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/vms/platformvm/fees/manager.go b/vms/platformvm/fees/manager.go index 34aaa5e4c9b0..cc33eae66319 100644 --- a/vms/platformvm/fees/manager.go +++ b/vms/platformvm/fees/manager.go @@ -22,6 +22,8 @@ type ( Dimensions [FeeDimensions]uint64 ) +// DummyUnitPrices should be dropped and +// unit prices should be retrieved from state/config // TODO ABENEGIA: drop this var DummyUnitPrices Dimensions diff --git a/vms/platformvm/txs/executor/standard_tx_executor.go b/vms/platformvm/txs/executor/standard_tx_executor.go index bfbd7ddaed32..47cfc4c2bd4a 100644 --- a/vms/platformvm/txs/executor/standard_tx_executor.go +++ b/vms/platformvm/txs/executor/standard_tx_executor.go @@ -559,6 +559,16 @@ func (e *StandardTxExecutor) BaseTx(tx *txs.BaseTx) error { } // Verify the flowcheck + feeCalculator := FeeCalculator{ + Backend: e.Backend, + ChainTime: e.State.GetTimestamp(), + Tx: e.Tx, + feeManager: e.BlkFeeManager, + } + if err := tx.Visit(&feeCalculator); err != nil { + return err + } + if err := e.FlowChecker.VerifySpend( tx, e.State, @@ -566,7 +576,7 @@ func (e *StandardTxExecutor) BaseTx(tx *txs.BaseTx) error { tx.Outs, e.Tx.Creds, map[ids.ID]uint64{ - e.Ctx.AVAXAssetID: e.Config.TxFee, + e.Ctx.AVAXAssetID: feeCalculator.Fee, }, ); err != nil { return err From 195741f3b8a2f102f9719a98bd90585fb4467962 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 8 Jan 2024 16:18:55 +0100 Subject: [PATCH 006/190] nit --- vms/platformvm/txs/executor/fee_calculator.go | 2 +- .../txs/executor/staker_tx_verification.go | 14 +++++++------- .../txs/executor/standard_tx_executor.go | 10 +++++----- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/vms/platformvm/txs/executor/fee_calculator.go b/vms/platformvm/txs/executor/fee_calculator.go index f6df239665f9..5e36c0b0c7f4 100644 --- a/vms/platformvm/txs/executor/fee_calculator.go +++ b/vms/platformvm/txs/executor/fee_calculator.go @@ -23,7 +23,7 @@ var ( type FeeCalculator struct { // inputs, to be filled before visitor methods are called - *Backend + Config *config.Config ChainTime time.Time Tx *txs.Tx feeManager *fees.Manager diff --git a/vms/platformvm/txs/executor/staker_tx_verification.go b/vms/platformvm/txs/executor/staker_tx_verification.go index d54d69ab9b15..7726fb18e047 100644 --- a/vms/platformvm/txs/executor/staker_tx_verification.go +++ b/vms/platformvm/txs/executor/staker_tx_verification.go @@ -163,7 +163,7 @@ func verifyAddValidatorTx( // Verify the flowcheck feeCalculator := FeeCalculator{ - Backend: backend, + Config: backend.Config, ChainTime: currentTimestamp, Tx: sTx, feeManager: feeManager, @@ -260,7 +260,7 @@ func verifyAddSubnetValidatorTx( // Verify the flowcheck feeCalculator := FeeCalculator{ - Backend: backend, + Config: backend.Config, ChainTime: currentTimestamp, Tx: sTx, feeManager: feeManager, @@ -340,7 +340,7 @@ func verifyRemoveSubnetValidatorTx( // Verify the flowcheck feeCalculator := FeeCalculator{ - Backend: backend, + Config: backend.Config, ChainTime: chainState.GetTimestamp(), Tx: sTx, feeManager: feeManager, @@ -463,7 +463,7 @@ func verifyAddDelegatorTx( // Verify the flowcheck feeCalculator := FeeCalculator{ - Backend: backend, + Config: backend.Config, ChainTime: chainState.GetTimestamp(), Tx: sTx, feeManager: feeManager, @@ -589,7 +589,7 @@ func verifyAddPermissionlessValidatorTx( // Verify the flowcheck feeCalculator := FeeCalculator{ - Backend: backend, + Config: backend.Config, ChainTime: currentTimestamp, Tx: sTx, feeManager: feeManager, @@ -738,7 +738,7 @@ func verifyAddPermissionlessDelegatorTx( // Verify the flowcheck feeCalculator := FeeCalculator{ - Backend: backend, + Config: backend.Config, ChainTime: currentTimestamp, Tx: sTx, feeManager: feeManager, @@ -798,7 +798,7 @@ func verifyTransferSubnetOwnershipTx( // Verify the flowcheck feeCalculator := FeeCalculator{ - Backend: backend, + Config: backend.Config, ChainTime: chainState.GetTimestamp(), Tx: sTx, feeManager: feeManager, diff --git a/vms/platformvm/txs/executor/standard_tx_executor.go b/vms/platformvm/txs/executor/standard_tx_executor.go index 47cfc4c2bd4a..4bab74a0757d 100644 --- a/vms/platformvm/txs/executor/standard_tx_executor.go +++ b/vms/platformvm/txs/executor/standard_tx_executor.go @@ -63,7 +63,7 @@ func (e *StandardTxExecutor) CreateChainTx(tx *txs.CreateChainTx) error { // Verify the flowcheck feeCalculator := FeeCalculator{ - Backend: e.Backend, + Config: e.Backend.Config, ChainTime: e.State.GetTimestamp(), Tx: e.Tx, feeManager: e.BlkFeeManager, @@ -110,7 +110,7 @@ func (e *StandardTxExecutor) CreateSubnetTx(tx *txs.CreateSubnetTx) error { // Verify the flowcheck feeCalculator := FeeCalculator{ - Backend: e.Backend, + Config: e.Backend.Config, ChainTime: e.State.GetTimestamp(), Tx: e.Tx, feeManager: e.BlkFeeManager, @@ -192,7 +192,7 @@ func (e *StandardTxExecutor) ImportTx(tx *txs.ImportTx) error { // Verify the flowcheck feeCalculator := FeeCalculator{ - Backend: e.Backend, + Config: e.Backend.Config, ChainTime: e.State.GetTimestamp(), Tx: e.Tx, feeManager: e.BlkFeeManager, @@ -250,7 +250,7 @@ func (e *StandardTxExecutor) ExportTx(tx *txs.ExportTx) error { // Verify the flowcheck feeCalculator := FeeCalculator{ - Backend: e.Backend, + Config: e.Backend.Config, ChainTime: e.State.GetTimestamp(), Tx: e.Tx, feeManager: e.BlkFeeManager, @@ -560,7 +560,7 @@ func (e *StandardTxExecutor) BaseTx(tx *txs.BaseTx) error { // Verify the flowcheck feeCalculator := FeeCalculator{ - Backend: e.Backend, + Config: e.Backend.Config, ChainTime: e.State.GetTimestamp(), Tx: e.Tx, feeManager: e.BlkFeeManager, From b86f784a09a049d4ae693f77f17739a3a5b223a3 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 8 Jan 2024 16:35:00 +0100 Subject: [PATCH 007/190] fixed EFork fork time --- node/node.go | 1 + version/constants.go | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/node/node.go b/node/node.go index 45e2f6a506eb..7670922e44ea 100644 --- a/node/node.go +++ b/node/node.go @@ -1120,6 +1120,7 @@ func (n *Node) initVMs() error { BanffTime: version.GetBanffTime(n.Config.NetworkID), CortinaTime: version.GetCortinaTime(n.Config.NetworkID), DurangoTime: durangoTime, + EForkTime: version.GetEForkTime(n.Config.NetworkID), UseCurrentHeight: n.Config.UseCurrentHeight, }, }), diff --git a/version/constants.go b/version/constants.go index 053a57a4585b..4a4187bd2774 100644 --- a/version/constants.go +++ b/version/constants.go @@ -109,6 +109,12 @@ var ( constants.MainnetID: time.Date(10000, time.December, 1, 0, 0, 0, 0, time.UTC), constants.FujiID: time.Date(10000, time.December, 1, 0, 0, 0, 0, time.UTC), } + + EForkTimes = map[uint32]time.Time{ + constants.MainnetID: time.Date(10000, time.December, 1, 0, 0, 0, 0, time.UTC), + constants.FujiID: time.Date(10000, time.December, 1, 0, 0, 0, 0, time.UTC), + } + TempForkTime = time.Date(10000, time.December, 1, 0, 0, 0, 0, time.UTC) ) func init() { @@ -204,6 +210,13 @@ func GetDurangoTime(networkID uint32) time.Time { return DefaultUpgradeTime } +func GetEForkTime(networkID uint32) time.Time { + if upgradeTime, exists := EForkTimes[networkID]; exists { + return upgradeTime + } + return TempForkTime +} + func GetCompatibility(networkID uint32) Compatibility { return NewCompatibility( CurrentApp, From 033abd03cbbf6012c194145e376f7b67bb2c9622 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 8 Jan 2024 17:49:06 +0100 Subject: [PATCH 008/190] fixed DefaultUnitPrices --- node/node.go | 62 ++--- vms/platformvm/block/builder/builder.go | 2 +- vms/platformvm/block/builder/helpers_test.go | 20 +- vms/platformvm/block/executor/helpers_test.go | 20 +- vms/platformvm/block/executor/verifier.go | 2 +- vms/platformvm/config/config.go | 28 +- vms/platformvm/config/fee_config.go | 37 +++ vms/platformvm/fees/manager.go | 5 - .../txs/executor/atomic_tx_executor.go | 2 +- .../txs/executor/create_chain_test.go | 10 +- .../txs/executor/create_subnet_test.go | 2 +- vms/platformvm/txs/executor/helpers_test.go | 20 +- .../executor/staker_tx_verification_test.go | 38 +-- .../txs/executor/standard_tx_executor_test.go | 252 ++++++++++-------- .../txs/executor/tx_mempool_verifier.go | 2 +- vms/platformvm/validator_set_property_test.go | 34 +-- vms/platformvm/vm_test.go | 34 +-- 17 files changed, 312 insertions(+), 258 deletions(-) create mode 100644 vms/platformvm/config/fee_config.go diff --git a/node/node.go b/node/node.go index 7670922e44ea..7980acb113c8 100644 --- a/node/node.go +++ b/node/node.go @@ -1092,36 +1092,38 @@ func (n *Node) initVMs() error { err := utils.Err( vmRegisterer.Register(context.TODO(), constants.PlatformVMID, &platformvm.Factory{ Config: platformconfig.Config{ - Chains: n.chainManager, - Validators: vdrs, - UptimeLockedCalculator: n.uptimeCalculator, - SybilProtectionEnabled: n.Config.SybilProtectionEnabled, - PartialSyncPrimaryNetwork: n.Config.PartialSyncPrimaryNetwork, - TrackedSubnets: n.Config.TrackedSubnets, - TxFee: n.Config.TxFee, - CreateAssetTxFee: n.Config.CreateAssetTxFee, - CreateSubnetTxFee: n.Config.CreateSubnetTxFee, - TransformSubnetTxFee: n.Config.TransformSubnetTxFee, - CreateBlockchainTxFee: n.Config.CreateBlockchainTxFee, - AddPrimaryNetworkValidatorFee: n.Config.AddPrimaryNetworkValidatorFee, - AddPrimaryNetworkDelegatorFee: n.Config.AddPrimaryNetworkDelegatorFee, - AddSubnetValidatorFee: n.Config.AddSubnetValidatorFee, - AddSubnetDelegatorFee: n.Config.AddSubnetDelegatorFee, - UptimePercentage: n.Config.UptimeRequirement, - MinValidatorStake: n.Config.MinValidatorStake, - MaxValidatorStake: n.Config.MaxValidatorStake, - MinDelegatorStake: n.Config.MinDelegatorStake, - MinDelegationFee: n.Config.MinDelegationFee, - MinStakeDuration: n.Config.MinStakeDuration, - MaxStakeDuration: n.Config.MaxStakeDuration, - RewardConfig: n.Config.RewardConfig, - ApricotPhase3Time: version.GetApricotPhase3Time(n.Config.NetworkID), - ApricotPhase5Time: version.GetApricotPhase5Time(n.Config.NetworkID), - BanffTime: version.GetBanffTime(n.Config.NetworkID), - CortinaTime: version.GetCortinaTime(n.Config.NetworkID), - DurangoTime: durangoTime, - EForkTime: version.GetEForkTime(n.Config.NetworkID), - UseCurrentHeight: n.Config.UseCurrentHeight, + Chains: n.chainManager, + Validators: vdrs, + UptimeLockedCalculator: n.uptimeCalculator, + SybilProtectionEnabled: n.Config.SybilProtectionEnabled, + PartialSyncPrimaryNetwork: n.Config.PartialSyncPrimaryNetwork, + TrackedSubnets: n.Config.TrackedSubnets, + FeeConfig: platformconfig.FeeConfig{ + TxFee: n.Config.TxFee, + CreateAssetTxFee: n.Config.CreateAssetTxFee, + CreateSubnetTxFee: n.Config.CreateSubnetTxFee, + TransformSubnetTxFee: n.Config.TransformSubnetTxFee, + CreateBlockchainTxFee: n.Config.CreateBlockchainTxFee, + AddPrimaryNetworkValidatorFee: n.Config.AddPrimaryNetworkValidatorFee, + AddPrimaryNetworkDelegatorFee: n.Config.AddPrimaryNetworkDelegatorFee, + AddSubnetValidatorFee: n.Config.AddSubnetValidatorFee, + AddSubnetDelegatorFee: n.Config.AddSubnetDelegatorFee, + }, + UptimePercentage: n.Config.UptimeRequirement, + MinValidatorStake: n.Config.MinValidatorStake, + MaxValidatorStake: n.Config.MaxValidatorStake, + MinDelegatorStake: n.Config.MinDelegatorStake, + MinDelegationFee: n.Config.MinDelegationFee, + MinStakeDuration: n.Config.MinStakeDuration, + MaxStakeDuration: n.Config.MaxStakeDuration, + RewardConfig: n.Config.RewardConfig, + ApricotPhase3Time: version.GetApricotPhase3Time(n.Config.NetworkID), + ApricotPhase5Time: version.GetApricotPhase5Time(n.Config.NetworkID), + BanffTime: version.GetBanffTime(n.Config.NetworkID), + CortinaTime: version.GetCortinaTime(n.Config.NetworkID), + DurangoTime: durangoTime, + EForkTime: version.GetEForkTime(n.Config.NetworkID), + UseCurrentHeight: n.Config.UseCurrentHeight, }, }), vmRegisterer.Register(context.TODO(), constants.AVMID, &avm.Factory{ diff --git a/vms/platformvm/block/builder/builder.go b/vms/platformvm/block/builder/builder.go index d98935612506..5c582fad12da 100644 --- a/vms/platformvm/block/builder/builder.go +++ b/vms/platformvm/block/builder/builder.go @@ -380,7 +380,7 @@ func packBlockTxs( executor := &txexecutor.StandardTxExecutor{ Backend: backend, - BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + BlkFeeManager: fees.NewManager(backend.Config.DefaultUnitPrices), State: txDiff, Tx: tx, } diff --git a/vms/platformvm/block/builder/helpers_test.go b/vms/platformvm/block/builder/helpers_test.go index a77461dc5fcd..3ddd9e123889 100644 --- a/vms/platformvm/block/builder/helpers_test.go +++ b/vms/platformvm/block/builder/helpers_test.go @@ -239,7 +239,7 @@ func addSubnet(t *testing.T, env *environment) { executor := txexecutor.StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitPrices), State: stateDiff, Tx: testSubnet1, } @@ -283,14 +283,16 @@ func defaultConfig() *config.Config { Chains: chains.TestManager, UptimeLockedCalculator: uptime.NewLockedCalculator(), Validators: validators.NewManager(), - TxFee: defaultTxFee, - CreateSubnetTxFee: 100 * defaultTxFee, - CreateBlockchainTxFee: 100 * defaultTxFee, - MinValidatorStake: 5 * units.MilliAvax, - MaxValidatorStake: 500 * units.MilliAvax, - MinDelegatorStake: 1 * units.MilliAvax, - MinStakeDuration: defaultMinStakingDuration, - MaxStakeDuration: defaultMaxStakingDuration, + FeeConfig: config.FeeConfig{ + TxFee: defaultTxFee, + CreateSubnetTxFee: 100 * defaultTxFee, + CreateBlockchainTxFee: 100 * defaultTxFee, + }, + MinValidatorStake: 5 * units.MilliAvax, + MaxValidatorStake: 500 * units.MilliAvax, + MinDelegatorStake: 1 * units.MilliAvax, + MinStakeDuration: defaultMinStakingDuration, + MaxStakeDuration: defaultMaxStakingDuration, RewardConfig: reward.Config{ MaxConsumptionRate: .12 * reward.PercentDenominator, MinConsumptionRate: .10 * reward.PercentDenominator, diff --git a/vms/platformvm/block/executor/helpers_test.go b/vms/platformvm/block/executor/helpers_test.go index 606c61bab294..9c7ff2acf6fb 100644 --- a/vms/platformvm/block/executor/helpers_test.go +++ b/vms/platformvm/block/executor/helpers_test.go @@ -250,7 +250,7 @@ func addSubnet(env *environment) { executor := executor.StandardTxExecutor{ Backend: env.backend, - BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitPrices), State: stateDiff, Tx: testSubnet1, } @@ -301,14 +301,16 @@ func defaultConfig() *config.Config { Chains: chains.TestManager, UptimeLockedCalculator: uptime.NewLockedCalculator(), Validators: validators.NewManager(), - TxFee: defaultTxFee, - CreateSubnetTxFee: 100 * defaultTxFee, - CreateBlockchainTxFee: 100 * defaultTxFee, - MinValidatorStake: 5 * units.MilliAvax, - MaxValidatorStake: 500 * units.MilliAvax, - MinDelegatorStake: 1 * units.MilliAvax, - MinStakeDuration: defaultMinStakingDuration, - MaxStakeDuration: defaultMaxStakingDuration, + FeeConfig: config.FeeConfig{ + TxFee: defaultTxFee, + CreateSubnetTxFee: 100 * defaultTxFee, + CreateBlockchainTxFee: 100 * defaultTxFee, + }, + MinValidatorStake: 5 * units.MilliAvax, + MaxValidatorStake: 500 * units.MilliAvax, + MinDelegatorStake: 1 * units.MilliAvax, + MinStakeDuration: defaultMinStakingDuration, + MaxStakeDuration: defaultMaxStakingDuration, RewardConfig: reward.Config{ MaxConsumptionRate: .12 * reward.PercentDenominator, MinConsumptionRate: .10 * reward.PercentDenominator, diff --git a/vms/platformvm/block/executor/verifier.go b/vms/platformvm/block/executor/verifier.go index 6e7e85e4a364..57bb04feebf0 100644 --- a/vms/platformvm/block/executor/verifier.go +++ b/vms/platformvm/block/executor/verifier.go @@ -456,7 +456,7 @@ func (v *verifier) processStandardTxs(txs []*txs.Tx, state state.Diff, parentID inputs set.Set[ids.ID] funcs = make([]func(), 0, len(txs)) atomicRequests = make(map[ids.ID]*atomic.Requests) - feeManager = fees.NewManager(fees.DummyUnitPrices) + feeManager = fees.NewManager(v.txExecutorBackend.Config.DefaultUnitPrices) ) for _, tx := range txs { txExecutor := executor.StandardTxExecutor{ diff --git a/vms/platformvm/config/config.go b/vms/platformvm/config/config.go index 834b1d4b44c4..5fa82b3aa999 100644 --- a/vms/platformvm/config/config.go +++ b/vms/platformvm/config/config.go @@ -43,32 +43,8 @@ type Config struct { // Set of subnets that this node is validating TrackedSubnets set.Set[ids.ID] - // Fee that is burned by every non-state creating transaction - TxFee uint64 - - // Fee that must be burned by every state creating transaction before AP3 - CreateAssetTxFee uint64 - - // Fee that must be burned by every subnet creating transaction after AP3 - CreateSubnetTxFee uint64 - - // Fee that must be burned by every transform subnet transaction - TransformSubnetTxFee uint64 - - // Fee that must be burned by every blockchain creating transaction after AP3 - CreateBlockchainTxFee uint64 - - // Transaction fee for adding a primary network validator - AddPrimaryNetworkValidatorFee uint64 - - // Transaction fee for adding a primary network delegator - AddPrimaryNetworkDelegatorFee uint64 - - // Transaction fee for adding a subnet validator - AddSubnetValidatorFee uint64 - - // Transaction fee for adding a subnet delegator - AddSubnetDelegatorFee uint64 + // All related to fees (static and multivariate/dynamic) + FeeConfig // The minimum amount of tokens one must bond to be a validator MinValidatorStake uint64 diff --git a/vms/platformvm/config/fee_config.go b/vms/platformvm/config/fee_config.go new file mode 100644 index 000000000000..9c08e3e21bea --- /dev/null +++ b/vms/platformvm/config/fee_config.go @@ -0,0 +1,37 @@ +// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package config + +import "github.com/ava-labs/avalanchego/vms/platformvm/fees" + +type FeeConfig struct { + DefaultUnitPrices fees.Dimensions + + // Pre E Fork, fee that is burned by every non-state creating transaction + TxFee uint64 + + // Pre E Fork, fee that must be burned by every state creating transaction before AP3 + CreateAssetTxFee uint64 + + // Pre E Fork, fee that must be burned by every subnet creating transaction after AP3 + CreateSubnetTxFee uint64 + + // Pre E Fork, fee that must be burned by every transform subnet transaction + TransformSubnetTxFee uint64 + + // Pre E Fork, fee that must be burned by every blockchain creating transaction after AP3 + CreateBlockchainTxFee uint64 + + // Pre E Fork, transaction fee for adding a primary network validator + AddPrimaryNetworkValidatorFee uint64 + + // Pre E Fork, transaction fee for adding a primary network delegator + AddPrimaryNetworkDelegatorFee uint64 + + // Pre E Fork, transaction fee for adding a subnet validator + AddSubnetValidatorFee uint64 + + // Pre E Fork, transaction fee for adding a subnet delegator + AddSubnetDelegatorFee uint64 +} diff --git a/vms/platformvm/fees/manager.go b/vms/platformvm/fees/manager.go index cc33eae66319..78682723a6f6 100644 --- a/vms/platformvm/fees/manager.go +++ b/vms/platformvm/fees/manager.go @@ -22,11 +22,6 @@ type ( Dimensions [FeeDimensions]uint64 ) -// DummyUnitPrices should be dropped and -// unit prices should be retrieved from state/config -// TODO ABENEGIA: drop this -var DummyUnitPrices Dimensions - type Manager struct { // Avax prices per units for all fee dimensions unitPrices Dimensions diff --git a/vms/platformvm/txs/executor/atomic_tx_executor.go b/vms/platformvm/txs/executor/atomic_tx_executor.go index a0d6bbd687ee..3d8fcbd18846 100644 --- a/vms/platformvm/txs/executor/atomic_tx_executor.go +++ b/vms/platformvm/txs/executor/atomic_tx_executor.go @@ -101,7 +101,7 @@ func (e *AtomicTxExecutor) atomicTx(tx txs.UnsignedTx) error { executor := StandardTxExecutor{ Backend: e.Backend, - BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + BlkFeeManager: fees.NewManager(e.Backend.Config.DefaultUnitPrices), State: e.OnAccept, Tx: e.Tx, } diff --git a/vms/platformvm/txs/executor/create_chain_test.go b/vms/platformvm/txs/executor/create_chain_test.go index 6659fd61f600..2f83d505503b 100644 --- a/vms/platformvm/txs/executor/create_chain_test.go +++ b/vms/platformvm/txs/executor/create_chain_test.go @@ -51,7 +51,7 @@ func TestCreateChainTxInsufficientControlSigs(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitPrices), State: stateDiff, Tx: tx, } @@ -93,7 +93,7 @@ func TestCreateChainTxWrongControlSig(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitPrices), State: stateDiff, Tx: tx, } @@ -129,7 +129,7 @@ func TestCreateChainTxNoSuchSubnet(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitPrices), State: stateDiff, Tx: tx, } @@ -162,7 +162,7 @@ func TestCreateChainTxValid(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitPrices), State: stateDiff, Tx: tx, } @@ -237,7 +237,7 @@ func TestCreateChainTxAP3FeeChange(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitPrices), State: stateDiff, Tx: tx, } diff --git a/vms/platformvm/txs/executor/create_subnet_test.go b/vms/platformvm/txs/executor/create_subnet_test.go index df10f6685db4..31b8c0d04556 100644 --- a/vms/platformvm/txs/executor/create_subnet_test.go +++ b/vms/platformvm/txs/executor/create_subnet_test.go @@ -80,7 +80,7 @@ func TestCreateSubnetTxAP3FeeChange(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitPrices), State: stateDiff, Tx: tx, } diff --git a/vms/platformvm/txs/executor/helpers_test.go b/vms/platformvm/txs/executor/helpers_test.go index caaf2d8ea5f9..a48f1244f964 100644 --- a/vms/platformvm/txs/executor/helpers_test.go +++ b/vms/platformvm/txs/executor/helpers_test.go @@ -207,7 +207,7 @@ func addSubnet( executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitPrices), State: stateDiff, Tx: testSubnet1, } @@ -267,14 +267,16 @@ func defaultConfig(postBanff, postCortina, postDurango bool) *config.Config { Chains: chains.TestManager, UptimeLockedCalculator: uptime.NewLockedCalculator(), Validators: validators.NewManager(), - TxFee: defaultTxFee, - CreateSubnetTxFee: 100 * defaultTxFee, - CreateBlockchainTxFee: 100 * defaultTxFee, - MinValidatorStake: 5 * units.MilliAvax, - MaxValidatorStake: 500 * units.MilliAvax, - MinDelegatorStake: 1 * units.MilliAvax, - MinStakeDuration: defaultMinStakingDuration, - MaxStakeDuration: defaultMaxStakingDuration, + FeeConfig: config.FeeConfig{ + TxFee: defaultTxFee, + CreateSubnetTxFee: 100 * defaultTxFee, + CreateBlockchainTxFee: 100 * defaultTxFee, + }, + MinValidatorStake: 5 * units.MilliAvax, + MaxValidatorStake: 500 * units.MilliAvax, + MinDelegatorStake: 1 * units.MilliAvax, + MinStakeDuration: defaultMinStakingDuration, + MaxStakeDuration: defaultMaxStakingDuration, RewardConfig: reward.Config{ MaxConsumptionRate: .12 * reward.PercentDenominator, MinConsumptionRate: .10 * reward.PercentDenominator, diff --git a/vms/platformvm/txs/executor/staker_tx_verification_test.go b/vms/platformvm/txs/executor/staker_tx_verification_test.go index 4a8906d82cc4..77b88099301b 100644 --- a/vms/platformvm/txs/executor/staker_tx_verification_test.go +++ b/vms/platformvm/txs/executor/staker_tx_verification_test.go @@ -459,9 +459,11 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { return &Backend{ FlowChecker: flowChecker, Config: &config.Config{ - AddSubnetValidatorFee: 1, - DurangoTime: activeForkTime, // activate latest fork, - EForkTime: mockable.MaxTime, + FeeConfig: config.FeeConfig{ + AddSubnetValidatorFee: 1, + }, + DurangoTime: activeForkTime, // activate latest fork, + EForkTime: mockable.MaxTime, }, Ctx: ctx, Bootstrapped: bootstrapped, @@ -506,10 +508,12 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { return &Backend{ FlowChecker: flowChecker, Config: &config.Config{ - CortinaTime: activeForkTime, - DurangoTime: mockable.MaxTime, - EForkTime: mockable.MaxTime, - AddSubnetValidatorFee: 1, + FeeConfig: config.FeeConfig{ + AddSubnetValidatorFee: 1, + }, + CortinaTime: activeForkTime, + DurangoTime: mockable.MaxTime, + EForkTime: mockable.MaxTime, }, Ctx: ctx, Bootstrapped: bootstrapped, @@ -559,9 +563,11 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { return &Backend{ FlowChecker: flowChecker, Config: &config.Config{ - AddSubnetValidatorFee: 1, - DurangoTime: activeForkTime, // activate latest fork, - EForkTime: mockable.MaxTime, + FeeConfig: config.FeeConfig{ + AddSubnetValidatorFee: 1, + }, + DurangoTime: activeForkTime, // activate latest fork, + EForkTime: mockable.MaxTime, }, Ctx: ctx, Bootstrapped: bootstrapped, @@ -594,11 +600,13 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { ctrl := gomock.NewController(t) var ( - backend = tt.backendF(ctrl) - feeManager = fees.NewManager(fees.DummyUnitPrices) - state = tt.stateF(ctrl) - sTx = tt.sTxF() - tx = tt.txF() + backend = tt.backendF(ctrl) + + defaultUnitPrices = backend.Config.DefaultUnitPrices + feeManager = fees.NewManager(defaultUnitPrices) + state = tt.stateF(ctrl) + sTx = tt.sTxF() + tx = tt.txF() ) err := verifyAddPermissionlessValidatorTx(backend, feeManager, state, 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 dbbe196fc084..17cd27dea6c3 100644 --- a/vms/platformvm/txs/executor/standard_tx_executor_test.go +++ b/vms/platformvm/txs/executor/standard_tx_executor_test.go @@ -90,7 +90,7 @@ func TestStandardTxExecutorAddValidatorTxEmptyID(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitPrices), State: stateDiff, Tx: tx, } @@ -361,7 +361,7 @@ func TestStandardTxExecutorAddDelegator(t *testing.T) { executor := StandardTxExecutor{ Backend: &freshTH.backend, - BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + BlkFeeManager: fees.NewManager(freshTH.backend.Config.DefaultUnitPrices), State: onAcceptState, Tx: tx, } @@ -411,7 +411,7 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitPrices), State: onAcceptState, Tx: tx, } @@ -440,7 +440,7 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitPrices), State: onAcceptState, Tx: tx, } @@ -483,7 +483,7 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitPrices), State: onAcceptState, Tx: tx, } @@ -527,7 +527,7 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitPrices), State: onAcceptState, Tx: tx, } @@ -554,7 +554,7 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitPrices), State: onAcceptState, Tx: tx, } @@ -580,7 +580,7 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { require.NoError(err) executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitPrices), State: onAcceptState, Tx: tx, } @@ -609,7 +609,7 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitPrices), State: onAcceptState, Tx: tx, } @@ -666,7 +666,7 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitPrices), State: onAcceptState, Tx: duplicateSubnetTx, } @@ -704,7 +704,7 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitPrices), State: onAcceptState, Tx: tx, } @@ -738,7 +738,7 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitPrices), State: onAcceptState, Tx: tx, } @@ -770,7 +770,7 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitPrices), State: onAcceptState, Tx: tx, } @@ -812,7 +812,7 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitPrices), State: onAcceptState, Tx: tx, } @@ -850,7 +850,7 @@ func TestStandardTxExecutorBanffAddValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitPrices), State: onAcceptState, Tx: tx, } @@ -877,7 +877,7 @@ func TestStandardTxExecutorBanffAddValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitPrices), State: onAcceptState, Tx: tx, } @@ -917,7 +917,7 @@ func TestStandardTxExecutorBanffAddValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitPrices), State: onAcceptState, Tx: tx, } @@ -954,7 +954,7 @@ func TestStandardTxExecutorBanffAddValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitPrices), State: onAcceptState, Tx: tx, } @@ -990,7 +990,7 @@ func TestStandardTxExecutorBanffAddValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitPrices), State: onAcceptState, Tx: tx, } @@ -1166,20 +1166,22 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { env.state.EXPECT().DeleteCurrentValidator(env.staker) env.state.EXPECT().DeleteUTXO(gomock.Any()).Times(len(env.unsignedTx.Ins)) env.state.EXPECT().AddUTXO(gomock.Any()).Times(len(env.unsignedTx.Outs)) + + cfg := &config.Config{ + BanffTime: env.latestForkTime, + CortinaTime: env.latestForkTime, + DurangoTime: env.latestForkTime, + EForkTime: mockable.MaxTime, + } e := &StandardTxExecutor{ Backend: &Backend{ - Config: &config.Config{ - BanffTime: env.latestForkTime, - CortinaTime: env.latestForkTime, - DurangoTime: env.latestForkTime, - EForkTime: mockable.MaxTime, - }, + Config: cfg, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + BlkFeeManager: fees.NewManager(cfg.DefaultUnitPrices), Tx: env.tx, State: env.state, } @@ -1195,20 +1197,22 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { // Setting the subnet ID to the Primary Network ID makes the tx fail syntactic verification env.tx.Unsigned.(*txs.RemoveSubnetValidatorTx).Subnet = constants.PrimaryNetworkID env.state = state.NewMockDiff(ctrl) + + cfg := &config.Config{ + BanffTime: env.latestForkTime, + CortinaTime: env.latestForkTime, + DurangoTime: env.latestForkTime, + EForkTime: mockable.MaxTime, + } e := &StandardTxExecutor{ Backend: &Backend{ - Config: &config.Config{ - BanffTime: env.latestForkTime, - CortinaTime: env.latestForkTime, - DurangoTime: env.latestForkTime, - EForkTime: mockable.MaxTime, - }, + Config: cfg, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + BlkFeeManager: fees.NewManager(cfg.DefaultUnitPrices), Tx: env.tx, State: env.state, } @@ -1224,20 +1228,22 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { env.state = state.NewMockDiff(ctrl) env.state.EXPECT().GetCurrentValidator(env.unsignedTx.Subnet, env.unsignedTx.NodeID).Return(nil, database.ErrNotFound) env.state.EXPECT().GetPendingValidator(env.unsignedTx.Subnet, env.unsignedTx.NodeID).Return(nil, database.ErrNotFound) + + cfg := &config.Config{ + BanffTime: env.latestForkTime, + CortinaTime: env.latestForkTime, + DurangoTime: env.latestForkTime, + EForkTime: mockable.MaxTime, + } e := &StandardTxExecutor{ Backend: &Backend{ - Config: &config.Config{ - BanffTime: env.latestForkTime, - CortinaTime: env.latestForkTime, - DurangoTime: env.latestForkTime, - EForkTime: mockable.MaxTime, - }, + Config: cfg, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + BlkFeeManager: fees.NewManager(cfg.DefaultUnitPrices), Tx: env.tx, State: env.state, } @@ -1256,20 +1262,22 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { // Set dependency expectations. env.state.EXPECT().GetCurrentValidator(env.unsignedTx.Subnet, env.unsignedTx.NodeID).Return(&staker, nil).Times(1) + + cfg := &config.Config{ + BanffTime: env.latestForkTime, + CortinaTime: env.latestForkTime, + DurangoTime: env.latestForkTime, + EForkTime: mockable.MaxTime, + } e := &StandardTxExecutor{ Backend: &Backend{ - Config: &config.Config{ - BanffTime: env.latestForkTime, - CortinaTime: env.latestForkTime, - DurangoTime: env.latestForkTime, - EForkTime: mockable.MaxTime, - }, + Config: cfg, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + BlkFeeManager: fees.NewManager(cfg.DefaultUnitPrices), Tx: env.tx, State: env.state, } @@ -1286,20 +1294,22 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { env.tx.Creds = nil env.state = state.NewMockDiff(ctrl) env.state.EXPECT().GetCurrentValidator(env.unsignedTx.Subnet, env.unsignedTx.NodeID).Return(env.staker, nil) + + cfg := &config.Config{ + BanffTime: env.latestForkTime, + CortinaTime: env.latestForkTime, + DurangoTime: env.latestForkTime, + EForkTime: mockable.MaxTime, + } e := &StandardTxExecutor{ Backend: &Backend{ - Config: &config.Config{ - BanffTime: env.latestForkTime, - CortinaTime: env.latestForkTime, - DurangoTime: env.latestForkTime, - EForkTime: mockable.MaxTime, - }, + Config: cfg, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + BlkFeeManager: fees.NewManager(cfg.DefaultUnitPrices), Tx: env.tx, State: env.state, } @@ -1315,20 +1325,22 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { env.state = state.NewMockDiff(ctrl) env.state.EXPECT().GetCurrentValidator(env.unsignedTx.Subnet, env.unsignedTx.NodeID).Return(env.staker, nil) env.state.EXPECT().GetSubnetOwner(env.unsignedTx.Subnet).Return(nil, database.ErrNotFound) + + cfg := &config.Config{ + BanffTime: env.latestForkTime, + CortinaTime: env.latestForkTime, + DurangoTime: env.latestForkTime, + EForkTime: mockable.MaxTime, + } e := &StandardTxExecutor{ Backend: &Backend{ - Config: &config.Config{ - BanffTime: env.latestForkTime, - CortinaTime: env.latestForkTime, - DurangoTime: env.latestForkTime, - EForkTime: mockable.MaxTime, - }, + Config: cfg, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + BlkFeeManager: fees.NewManager(cfg.DefaultUnitPrices), Tx: env.tx, State: env.state, } @@ -1346,20 +1358,22 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { subnetOwner := fx.NewMockOwner(ctrl) env.state.EXPECT().GetSubnetOwner(env.unsignedTx.Subnet).Return(subnetOwner, nil) env.fx.EXPECT().VerifyPermission(gomock.Any(), env.unsignedTx.SubnetAuth, env.tx.Creds[len(env.tx.Creds)-1], subnetOwner).Return(errTest) + + cfg := &config.Config{ + BanffTime: env.latestForkTime, + CortinaTime: env.latestForkTime, + DurangoTime: env.latestForkTime, + EForkTime: mockable.MaxTime, + } e := &StandardTxExecutor{ Backend: &Backend{ - Config: &config.Config{ - BanffTime: env.latestForkTime, - CortinaTime: env.latestForkTime, - DurangoTime: env.latestForkTime, - EForkTime: mockable.MaxTime, - }, + Config: cfg, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + BlkFeeManager: fees.NewManager(cfg.DefaultUnitPrices), Tx: env.tx, State: env.state, } @@ -1381,20 +1395,22 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { env.flowChecker.EXPECT().VerifySpend( gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), ).Return(errTest) + + cfg := &config.Config{ + BanffTime: env.latestForkTime, + CortinaTime: env.latestForkTime, + DurangoTime: env.latestForkTime, + EForkTime: mockable.MaxTime, + } e := &StandardTxExecutor{ Backend: &Backend{ - Config: &config.Config{ - BanffTime: env.latestForkTime, - CortinaTime: env.latestForkTime, - DurangoTime: env.latestForkTime, - EForkTime: mockable.MaxTime, - }, + Config: cfg, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + BlkFeeManager: fees.NewManager(cfg.DefaultUnitPrices), Tx: env.tx, State: env.state, } @@ -1540,20 +1556,22 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { // Setting the tx to nil makes the tx fail syntactic verification env.tx.Unsigned = (*txs.TransformSubnetTx)(nil) env.state = state.NewMockDiff(ctrl) + + cfg := &config.Config{ + BanffTime: env.latestForkTime, + CortinaTime: env.latestForkTime, + DurangoTime: env.latestForkTime, + EForkTime: mockable.MaxTime, + } e := &StandardTxExecutor{ Backend: &Backend{ - Config: &config.Config{ - BanffTime: env.latestForkTime, - CortinaTime: env.latestForkTime, - DurangoTime: env.latestForkTime, - EForkTime: mockable.MaxTime, - }, + Config: cfg, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + BlkFeeManager: fees.NewManager(cfg.DefaultUnitPrices), Tx: env.tx, State: env.state, } @@ -1568,20 +1586,22 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { env := newValidTransformSubnetTxVerifyEnv(t, ctrl) env.unsignedTx.MaxStakeDuration = math.MaxUint32 env.state = state.NewMockDiff(ctrl) + + cfg := &config.Config{ + BanffTime: env.latestForkTime, + CortinaTime: env.latestForkTime, + DurangoTime: env.latestForkTime, + EForkTime: mockable.MaxTime, + } e := &StandardTxExecutor{ Backend: &Backend{ - Config: &config.Config{ - BanffTime: env.latestForkTime, - CortinaTime: env.latestForkTime, - DurangoTime: env.latestForkTime, - EForkTime: mockable.MaxTime, - }, + Config: cfg, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + BlkFeeManager: fees.NewManager(cfg.DefaultUnitPrices), Tx: env.tx, State: env.state, } @@ -1597,21 +1617,23 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { // Remove credentials env.tx.Creds = nil env.state = state.NewMockDiff(ctrl) + + cfg := &config.Config{ + BanffTime: env.latestForkTime, + CortinaTime: env.latestForkTime, + DurangoTime: env.latestForkTime, + EForkTime: mockable.MaxTime, + MaxStakeDuration: math.MaxInt64, + } e := &StandardTxExecutor{ Backend: &Backend{ - Config: &config.Config{ - BanffTime: env.latestForkTime, - CortinaTime: env.latestForkTime, - DurangoTime: env.latestForkTime, - EForkTime: mockable.MaxTime, - MaxStakeDuration: math.MaxInt64, - }, + Config: cfg, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + BlkFeeManager: fees.NewManager(cfg.DefaultUnitPrices), Tx: env.tx, State: env.state, } @@ -1632,21 +1654,23 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { env.flowChecker.EXPECT().VerifySpend( gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), ).Return(ErrFlowCheckFailed) + + cfg := &config.Config{ + BanffTime: env.latestForkTime, + CortinaTime: env.latestForkTime, + DurangoTime: env.latestForkTime, + EForkTime: mockable.MaxTime, + MaxStakeDuration: math.MaxInt64, + } e := &StandardTxExecutor{ Backend: &Backend{ - Config: &config.Config{ - BanffTime: env.latestForkTime, - CortinaTime: env.latestForkTime, - DurangoTime: env.latestForkTime, - EForkTime: mockable.MaxTime, - MaxStakeDuration: math.MaxInt64, - }, + Config: cfg, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + BlkFeeManager: fees.NewManager(cfg.DefaultUnitPrices), Tx: env.tx, State: env.state, } @@ -1672,21 +1696,23 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { env.state.EXPECT().SetCurrentSupply(env.unsignedTx.Subnet, env.unsignedTx.InitialSupply) env.state.EXPECT().DeleteUTXO(gomock.Any()).Times(len(env.unsignedTx.Ins)) env.state.EXPECT().AddUTXO(gomock.Any()).Times(len(env.unsignedTx.Outs)) + + cfg := &config.Config{ + BanffTime: env.latestForkTime, + CortinaTime: env.latestForkTime, + DurangoTime: env.latestForkTime, + EForkTime: mockable.MaxTime, + MaxStakeDuration: math.MaxInt64, + } e := &StandardTxExecutor{ Backend: &Backend{ - Config: &config.Config{ - BanffTime: env.latestForkTime, - CortinaTime: env.latestForkTime, - DurangoTime: env.latestForkTime, - EForkTime: mockable.MaxTime, - MaxStakeDuration: math.MaxInt64, - }, + Config: cfg, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + BlkFeeManager: fees.NewManager(cfg.DefaultUnitPrices), Tx: env.tx, State: env.state, } diff --git a/vms/platformvm/txs/executor/tx_mempool_verifier.go b/vms/platformvm/txs/executor/tx_mempool_verifier.go index 7ad0cbc84d81..8aa87ba4c970 100644 --- a/vms/platformvm/txs/executor/tx_mempool_verifier.go +++ b/vms/platformvm/txs/executor/tx_mempool_verifier.go @@ -92,7 +92,7 @@ func (v *MempoolTxVerifier) standardTx(tx txs.UnsignedTx) error { executor := StandardTxExecutor{ Backend: v.Backend, - BlkFeeManager: fees.NewManager(fees.DummyUnitPrices), + BlkFeeManager: fees.NewManager(v.Backend.Config.DefaultUnitPrices), State: baseState, Tx: v.Tx, } diff --git a/vms/platformvm/validator_set_property_test.go b/vms/platformvm/validator_set_property_test.go index ca161f744011..4c46132b9a3c 100644 --- a/vms/platformvm/validator_set_property_test.go +++ b/vms/platformvm/validator_set_property_test.go @@ -716,22 +716,24 @@ func buildVM(t *testing.T) (*VM, ids.ID, error) { UptimeLockedCalculator: uptime.NewLockedCalculator(), SybilProtectionEnabled: true, Validators: validators.NewManager(), - TxFee: defaultTxFee, - CreateSubnetTxFee: 100 * defaultTxFee, - TransformSubnetTxFee: 100 * defaultTxFee, - CreateBlockchainTxFee: 100 * defaultTxFee, - MinValidatorStake: defaultMinValidatorStake, - MaxValidatorStake: defaultMaxValidatorStake, - MinDelegatorStake: defaultMinDelegatorStake, - MinStakeDuration: defaultMinStakingDuration, - MaxStakeDuration: defaultMaxStakingDuration, - RewardConfig: defaultRewardConfig, - ApricotPhase3Time: forkTime, - ApricotPhase5Time: forkTime, - BanffTime: forkTime, - CortinaTime: forkTime, - DurangoTime: forkTime, - EForkTime: mockable.MaxTime, + FeeConfig: config.FeeConfig{ + TxFee: defaultTxFee, + CreateSubnetTxFee: 100 * defaultTxFee, + TransformSubnetTxFee: 100 * defaultTxFee, + CreateBlockchainTxFee: 100 * defaultTxFee, + }, + MinValidatorStake: defaultMinValidatorStake, + MaxValidatorStake: defaultMaxValidatorStake, + MinDelegatorStake: defaultMinDelegatorStake, + MinStakeDuration: defaultMinStakingDuration, + MaxStakeDuration: defaultMaxStakingDuration, + RewardConfig: defaultRewardConfig, + ApricotPhase3Time: forkTime, + ApricotPhase5Time: forkTime, + BanffTime: forkTime, + CortinaTime: forkTime, + DurangoTime: forkTime, + EForkTime: mockable.MaxTime, }} vm.clock.Set(forkTime.Add(time.Second)) diff --git a/vms/platformvm/vm_test.go b/vms/platformvm/vm_test.go index 6c8733550d09..e25e3cbf4088 100644 --- a/vms/platformvm/vm_test.go +++ b/vms/platformvm/vm_test.go @@ -237,22 +237,24 @@ func defaultVM(t *testing.T, fork activeFork) (*VM, database.Database, *mutableS UptimeLockedCalculator: uptime.NewLockedCalculator(), SybilProtectionEnabled: true, Validators: validators.NewManager(), - TxFee: defaultTxFee, - CreateSubnetTxFee: 100 * defaultTxFee, - TransformSubnetTxFee: 100 * defaultTxFee, - CreateBlockchainTxFee: 100 * defaultTxFee, - MinValidatorStake: defaultMinValidatorStake, - MaxValidatorStake: defaultMaxValidatorStake, - MinDelegatorStake: defaultMinDelegatorStake, - MinStakeDuration: defaultMinStakingDuration, - MaxStakeDuration: defaultMaxStakingDuration, - RewardConfig: defaultRewardConfig, - ApricotPhase3Time: apricotPhase3Time, - ApricotPhase5Time: apricotPhase5Time, - BanffTime: banffTime, - CortinaTime: cortinaTime, - DurangoTime: durangoTime, - EForkTime: mockable.MaxTime, + FeeConfig: config.FeeConfig{ + TxFee: defaultTxFee, + CreateSubnetTxFee: 100 * defaultTxFee, + TransformSubnetTxFee: 100 * defaultTxFee, + CreateBlockchainTxFee: 100 * defaultTxFee, + }, + MinValidatorStake: defaultMinValidatorStake, + MaxValidatorStake: defaultMaxValidatorStake, + MinDelegatorStake: defaultMinDelegatorStake, + MinStakeDuration: defaultMinStakingDuration, + MaxStakeDuration: defaultMaxStakingDuration, + RewardConfig: defaultRewardConfig, + ApricotPhase3Time: apricotPhase3Time, + ApricotPhase5Time: apricotPhase5Time, + BanffTime: banffTime, + CortinaTime: cortinaTime, + DurangoTime: durangoTime, + EForkTime: mockable.MaxTime, }} db := memdb.New() From 6e24cea1b5a3716dc049c2b54758fcdfb17c8c19 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 8 Jan 2024 18:09:55 +0100 Subject: [PATCH 009/190] added UTs --- vms/platformvm/config/config.go | 14 ++- vms/platformvm/config/fee_config.go | 4 + vms/platformvm/fees/manager.go | 8 +- vms/platformvm/txs/executor/fee_calculator.go | 30 ++--- .../executor/staker_tx_verification_test.go | 113 +++++++++++++++++- 5 files changed, 143 insertions(+), 26 deletions(-) diff --git a/vms/platformvm/config/config.go b/vms/platformvm/config/config.go index 5fa82b3aa999..83d421546011 100644 --- a/vms/platformvm/config/config.go +++ b/vms/platformvm/config/config.go @@ -156,11 +156,13 @@ func (c *Config) CreateChain(chainID ids.ID, tx *txs.CreateChainTx) { c.Chains.QueueChainCreation(chainParams) } -func (*Config) BlockMaxConsumedUnits() fees.Dimensions { - // TODO ABENEGIA: to be set - var res fees.Dimensions - for i := fees.Dimension(0); i < fees.FeeDimensions; i++ { - res[i] = math.MaxUint64 +func (c *Config) BlockMaxConsumedUnits(timestamp time.Time) fees.Dimensions { + if !c.IsEForkActivated(timestamp) { + var res fees.Dimensions + for i := fees.Dimension(0); i < fees.FeeDimensions; i++ { + res[i] = math.MaxUint64 + } + return res } - return res + return c.DefaultBlockMaxConsumedUnits } diff --git a/vms/platformvm/config/fee_config.go b/vms/platformvm/config/fee_config.go index 9c08e3e21bea..c99c8fd40a8b 100644 --- a/vms/platformvm/config/fee_config.go +++ b/vms/platformvm/config/fee_config.go @@ -6,8 +6,12 @@ package config import "github.com/ava-labs/avalanchego/vms/platformvm/fees" type FeeConfig struct { + // Post E Fork, the unit fee for each dimension, denominated in Avax DefaultUnitPrices fees.Dimensions + // Post E Fork, the max complexity of a block for each dimension + DefaultBlockMaxConsumedUnits fees.Dimensions + // Pre E Fork, fee that is burned by every non-state creating transaction TxFee uint64 diff --git a/vms/platformvm/fees/manager.go b/vms/platformvm/fees/manager.go index 78682723a6f6..308f66d451f9 100644 --- a/vms/platformvm/fees/manager.go +++ b/vms/platformvm/fees/manager.go @@ -61,10 +61,10 @@ func (m *Manager) CumulateUnits(units, bounds Dimensions) (bool, Dimension) { for i := Dimension(0); i < FeeDimensions; i++ { consumed, err := math.Add64(m.cumulatedUnits[i], units[i]) if err != nil { - return false, i + return true, i } if consumed > bounds[i] { - return false, i + return true, i } } @@ -72,9 +72,9 @@ func (m *Manager) CumulateUnits(units, bounds Dimensions) (bool, Dimension) { for i := Dimension(0); i < FeeDimensions; i++ { consumed, err := math.Add64(m.cumulatedUnits[i], units[i]) if err != nil { - return false, i + return true, i } m.cumulatedUnits[i] = consumed } - return true, 0 + return false, 0 } diff --git a/vms/platformvm/txs/executor/fee_calculator.go b/vms/platformvm/txs/executor/fee_calculator.go index 5e36c0b0c7f4..34d480d06c65 100644 --- a/vms/platformvm/txs/executor/fee_calculator.go +++ b/vms/platformvm/txs/executor/fee_calculator.go @@ -44,7 +44,7 @@ func (fc *FeeCalculator) AddValidatorTx(*txs.AddValidatorTx) error { ) consumedUnits[fees.Bandwidth] = uint64(len(fc.Tx.Bytes())) - fc.Fee, err = processFees(fc.Config, fc.feeManager, consumedUnits) + fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) return err } @@ -60,7 +60,7 @@ func (fc *FeeCalculator) AddSubnetValidatorTx(*txs.AddSubnetValidatorTx) error { ) consumedUnits[fees.Bandwidth] = uint64(len(fc.Tx.Bytes())) - fc.Fee, err = processFees(fc.Config, fc.feeManager, consumedUnits) + fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) return err } @@ -76,7 +76,7 @@ func (fc *FeeCalculator) AddDelegatorTx(*txs.AddDelegatorTx) error { ) consumedUnits[fees.Bandwidth] = uint64(len(fc.Tx.Bytes())) - fc.Fee, err = processFees(fc.Config, fc.feeManager, consumedUnits) + fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) return err } @@ -92,7 +92,7 @@ func (fc *FeeCalculator) CreateChainTx(*txs.CreateChainTx) error { ) consumedUnits[fees.Bandwidth] = uint64(len(fc.Tx.Bytes())) - fc.Fee, err = processFees(fc.Config, fc.feeManager, consumedUnits) + fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) return err } @@ -108,7 +108,7 @@ func (fc *FeeCalculator) CreateSubnetTx(*txs.CreateSubnetTx) error { ) consumedUnits[fees.Bandwidth] = uint64(len(fc.Tx.Bytes())) - fc.Fee, err = processFees(fc.Config, fc.feeManager, consumedUnits) + fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) return err } @@ -132,7 +132,7 @@ func (fc *FeeCalculator) RemoveSubnetValidatorTx(*txs.RemoveSubnetValidatorTx) e ) consumedUnits[fees.Bandwidth] = uint64(len(fc.Tx.Bytes())) - fc.Fee, err = processFees(fc.Config, fc.feeManager, consumedUnits) + fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) return err } @@ -148,7 +148,7 @@ func (fc *FeeCalculator) TransformSubnetTx(*txs.TransformSubnetTx) error { ) consumedUnits[fees.Bandwidth] = uint64(len(fc.Tx.Bytes())) - fc.Fee, err = processFees(fc.Config, fc.feeManager, consumedUnits) + fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) return err } @@ -164,7 +164,7 @@ func (fc *FeeCalculator) TransferSubnetOwnershipTx(*txs.TransferSubnetOwnershipT ) consumedUnits[fees.Bandwidth] = uint64(len(fc.Tx.Bytes())) - fc.Fee, err = processFees(fc.Config, fc.feeManager, consumedUnits) + fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) return err } @@ -184,7 +184,7 @@ func (fc *FeeCalculator) AddPermissionlessValidatorTx(tx *txs.AddPermissionlessV ) consumedUnits[fees.Bandwidth] = uint64(len(fc.Tx.Bytes())) - fc.Fee, err = processFees(fc.Config, fc.feeManager, consumedUnits) + fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) return err } @@ -204,7 +204,7 @@ func (fc *FeeCalculator) AddPermissionlessDelegatorTx(tx *txs.AddPermissionlessD ) consumedUnits[fees.Bandwidth] = uint64(len(fc.Tx.Bytes())) - fc.Fee, err = processFees(fc.Config, fc.feeManager, consumedUnits) + fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) return err } @@ -220,7 +220,7 @@ func (fc *FeeCalculator) BaseTx(*txs.BaseTx) error { ) consumedUnits[fees.Bandwidth] = uint64(len(fc.Tx.Bytes())) - fc.Fee, err = processFees(fc.Config, fc.feeManager, consumedUnits) + fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) return err } @@ -236,7 +236,7 @@ func (fc *FeeCalculator) ImportTx(*txs.ImportTx) error { ) consumedUnits[fees.Bandwidth] = uint64(len(fc.Tx.Bytes())) - fc.Fee, err = processFees(fc.Config, fc.feeManager, consumedUnits) + fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) return err } @@ -252,12 +252,12 @@ func (fc *FeeCalculator) ExportTx(*txs.ExportTx) error { ) consumedUnits[fees.Bandwidth] = uint64(len(fc.Tx.Bytes())) - fc.Fee, err = processFees(fc.Config, fc.feeManager, consumedUnits) + fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) return err } -func processFees(cfg *config.Config, fc *fees.Manager, consumedUnits fees.Dimensions) (uint64, error) { - boundBreached, dimension := fc.CumulateUnits(consumedUnits, cfg.BlockMaxConsumedUnits()) +func processFees(cfg *config.Config, chainTime time.Time, fc *fees.Manager, consumedUnits fees.Dimensions) (uint64, error) { + boundBreached, dimension := fc.CumulateUnits(consumedUnits, cfg.BlockMaxConsumedUnits(chainTime)) if boundBreached { return 0, fmt.Errorf("%w: breached dimension %d", errFailedConsumedUnitsCumulation, dimension) } diff --git a/vms/platformvm/txs/executor/staker_tx_verification_test.go b/vms/platformvm/txs/executor/staker_tx_verification_test.go index 77b88099301b..609ba5a1f976 100644 --- a/vms/platformvm/txs/executor/staker_tx_verification_test.go +++ b/vms/platformvm/txs/executor/staker_tx_verification_test.go @@ -18,6 +18,7 @@ import ( "github.com/ava-labs/avalanchego/utils" "github.com/ava-labs/avalanchego/utils/constants" "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/config" @@ -545,7 +546,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { expectedErr: ErrFutureStakeTime, }, { - name: "success", + name: "success pre EFork", backendF: func(ctrl *gomock.Controller) *Backend { bootstrapped := &utils.Atomic[bool]{} bootstrapped.Set(true) @@ -593,6 +594,116 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { }, expectedErr: nil, }, + { + name: "unit bound breached post EFork", + backendF: func(ctrl *gomock.Controller) *Backend { + bootstrapped := &utils.Atomic[bool]{} + bootstrapped.Set(true) + + flowChecker := utxo.NewMockVerifier(ctrl) + + return &Backend{ + FlowChecker: flowChecker, + Config: &config.Config{ + FeeConfig: config.FeeConfig{ + DefaultUnitPrices: fees.Dimensions{ + 10, + 11, + 12, + 13, + }, + DefaultBlockMaxConsumedUnits: fees.Dimensions{ + 0, + 10 * units.KiB, + 10 * units.KiB, + 10 * units.KiB, + }, + }, + EForkTime: activeForkTime, // activate latest fork, + }, + Ctx: ctx, + Bootstrapped: bootstrapped, + } + }, + stateF: func(ctrl *gomock.Controller) state.Chain { + mockState := state.NewMockChain(ctrl) + mockState.EXPECT().GetTimestamp().Return(now).Times(2) // chain time is after EFork 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) + primaryNetworkVdr := &state.Staker{ + EndTime: mockable.MaxTime, + } + mockState.EXPECT().GetCurrentValidator(constants.PrimaryNetworkID, verifiedTx.NodeID()).Return(primaryNetworkVdr, nil) + return mockState + }, + sTxF: func() *txs.Tx { + return &verifiedSignedTx + }, + txF: func() *txs.AddPermissionlessValidatorTx { + return &verifiedTx + }, + expectedErr: errFailedConsumedUnitsCumulation, + }, + { + name: "success post EFork", + backendF: func(ctrl *gomock.Controller) *Backend { + bootstrapped := &utils.Atomic[bool]{} + bootstrapped.Set(true) + + flowChecker := utxo.NewMockVerifier(ctrl) + flowChecker.EXPECT().VerifySpend( + gomock.Any(), + gomock.Any(), + gomock.Any(), + gomock.Any(), + gomock.Any(), + gomock.Any(), + ).Return(nil) + + return &Backend{ + FlowChecker: flowChecker, + Config: &config.Config{ + FeeConfig: config.FeeConfig{ + DefaultUnitPrices: fees.Dimensions{ + 10, + 11, + 12, + 13, + }, + DefaultBlockMaxConsumedUnits: fees.Dimensions{ + 10 * units.KiB, + 10 * units.KiB, + 10 * units.KiB, + 10 * units.KiB, + }, + }, + EForkTime: activeForkTime, // activate latest fork, + }, + Ctx: ctx, + Bootstrapped: bootstrapped, + } + }, + stateF: func(ctrl *gomock.Controller) state.Chain { + mockState := state.NewMockChain(ctrl) + mockState.EXPECT().GetTimestamp().Return(now).Times(2) // chain time is after EFork 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) + primaryNetworkVdr := &state.Staker{ + EndTime: mockable.MaxTime, + } + mockState.EXPECT().GetCurrentValidator(constants.PrimaryNetworkID, verifiedTx.NodeID()).Return(primaryNetworkVdr, nil) + return mockState + }, + sTxF: func() *txs.Tx { + return &verifiedSignedTx + }, + txF: func() *txs.AddPermissionlessValidatorTx { + return &verifiedTx + }, + expectedErr: nil, + }, } for _, tt := range tests { From b79b2956b024cb834d162b59e5711367a6929ab7 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 8 Jan 2024 18:16:59 +0100 Subject: [PATCH 010/190] nit --- vms/platformvm/fees/manager.go | 2 +- .../executor/staker_tx_verification_test.go | 22 +++++-------------- 2 files changed, 7 insertions(+), 17 deletions(-) diff --git a/vms/platformvm/fees/manager.go b/vms/platformvm/fees/manager.go index 308f66d451f9..8740e474723b 100644 --- a/vms/platformvm/fees/manager.go +++ b/vms/platformvm/fees/manager.go @@ -14,7 +14,7 @@ const ( // UTXORead Dimension = 2 // UTXOWrite Dimension = 3 // includes delete - FeeDimensions = 4 + FeeDimensions = 1 ) type ( diff --git a/vms/platformvm/txs/executor/staker_tx_verification_test.go b/vms/platformvm/txs/executor/staker_tx_verification_test.go index 609ba5a1f976..52a7aea397bd 100644 --- a/vms/platformvm/txs/executor/staker_tx_verification_test.go +++ b/vms/platformvm/txs/executor/staker_tx_verification_test.go @@ -18,7 +18,6 @@ import ( "github.com/ava-labs/avalanchego/utils" "github.com/ava-labs/avalanchego/utils/constants" "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/config" @@ -105,7 +104,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{ { @@ -608,15 +610,9 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { FeeConfig: config.FeeConfig{ DefaultUnitPrices: fees.Dimensions{ 10, - 11, - 12, - 13, }, DefaultBlockMaxConsumedUnits: fees.Dimensions{ - 0, - 10 * units.KiB, - 10 * units.KiB, - 10 * units.KiB, + uint64(len(signedBytes)) - 1, }, }, EForkTime: activeForkTime, // activate latest fork, @@ -667,15 +663,9 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { FeeConfig: config.FeeConfig{ DefaultUnitPrices: fees.Dimensions{ 10, - 11, - 12, - 13, }, DefaultBlockMaxConsumedUnits: fees.Dimensions{ - 10 * units.KiB, - 10 * units.KiB, - 10 * units.KiB, - 10 * units.KiB, + uint64(len(signedBytes)), }, }, EForkTime: activeForkTime, // activate latest fork, From 5a56f0e2283f998b17493e4c3ae9b9de3b82d8d2 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 8 Jan 2024 18:40:17 +0100 Subject: [PATCH 011/190] added UTXORead fee dimension --- vms/platformvm/fees/manager.go | 8 +- vms/platformvm/txs/executor/fee_calculator.go | 100 ++++++------------ 2 files changed, 39 insertions(+), 69 deletions(-) diff --git a/vms/platformvm/fees/manager.go b/vms/platformvm/fees/manager.go index 8740e474723b..e51ad9313b2e 100644 --- a/vms/platformvm/fees/manager.go +++ b/vms/platformvm/fees/manager.go @@ -10,11 +10,11 @@ import "github.com/ava-labs/avalanchego/utils/math" const ( Bandwidth Dimension = 0 - // Compute Dimension = 1 - // UTXORead Dimension = 2 - // UTXOWrite Dimension = 3 // includes delete + UTXORead Dimension = 1 + // UTXOWrite Dimension = 2 // includes delete + // Compute Dimension = 3 - FeeDimensions = 1 + FeeDimensions = 2 ) type ( diff --git a/vms/platformvm/txs/executor/fee_calculator.go b/vms/platformvm/txs/executor/fee_calculator.go index 34d480d06c65..ea4d742ab7b4 100644 --- a/vms/platformvm/txs/executor/fee_calculator.go +++ b/vms/platformvm/txs/executor/fee_calculator.go @@ -38,12 +38,9 @@ func (fc *FeeCalculator) AddValidatorTx(*txs.AddValidatorTx) error { return nil } - var ( - consumedUnits fees.Dimensions - err error - ) - consumedUnits[fees.Bandwidth] = uint64(len(fc.Tx.Bytes())) + consumedUnits := commonConsumedUnits(fc.Tx) + var err error fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) return err } @@ -54,12 +51,9 @@ func (fc *FeeCalculator) AddSubnetValidatorTx(*txs.AddSubnetValidatorTx) error { return nil } - var ( - consumedUnits fees.Dimensions - err error - ) - consumedUnits[fees.Bandwidth] = uint64(len(fc.Tx.Bytes())) + consumedUnits := commonConsumedUnits(fc.Tx) + var err error fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) return err } @@ -70,12 +64,9 @@ func (fc *FeeCalculator) AddDelegatorTx(*txs.AddDelegatorTx) error { return nil } - var ( - consumedUnits fees.Dimensions - err error - ) - consumedUnits[fees.Bandwidth] = uint64(len(fc.Tx.Bytes())) + consumedUnits := commonConsumedUnits(fc.Tx) + var err error fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) return err } @@ -86,12 +77,9 @@ func (fc *FeeCalculator) CreateChainTx(*txs.CreateChainTx) error { return nil } - var ( - consumedUnits fees.Dimensions - err error - ) - consumedUnits[fees.Bandwidth] = uint64(len(fc.Tx.Bytes())) + consumedUnits := commonConsumedUnits(fc.Tx) + var err error fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) return err } @@ -102,12 +90,9 @@ func (fc *FeeCalculator) CreateSubnetTx(*txs.CreateSubnetTx) error { return nil } - var ( - consumedUnits fees.Dimensions - err error - ) - consumedUnits[fees.Bandwidth] = uint64(len(fc.Tx.Bytes())) + consumedUnits := commonConsumedUnits(fc.Tx) + var err error fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) return err } @@ -126,12 +111,9 @@ func (fc *FeeCalculator) RemoveSubnetValidatorTx(*txs.RemoveSubnetValidatorTx) e return nil } - var ( - consumedUnits fees.Dimensions - err error - ) - consumedUnits[fees.Bandwidth] = uint64(len(fc.Tx.Bytes())) + consumedUnits := commonConsumedUnits(fc.Tx) + var err error fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) return err } @@ -142,12 +124,9 @@ func (fc *FeeCalculator) TransformSubnetTx(*txs.TransformSubnetTx) error { return nil } - var ( - consumedUnits fees.Dimensions - err error - ) - consumedUnits[fees.Bandwidth] = uint64(len(fc.Tx.Bytes())) + consumedUnits := commonConsumedUnits(fc.Tx) + var err error fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) return err } @@ -158,12 +137,9 @@ func (fc *FeeCalculator) TransferSubnetOwnershipTx(*txs.TransferSubnetOwnershipT return nil } - var ( - consumedUnits fees.Dimensions - err error - ) - consumedUnits[fees.Bandwidth] = uint64(len(fc.Tx.Bytes())) + consumedUnits := commonConsumedUnits(fc.Tx) + var err error fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) return err } @@ -178,12 +154,9 @@ func (fc *FeeCalculator) AddPermissionlessValidatorTx(tx *txs.AddPermissionlessV return nil } - var ( - consumedUnits fees.Dimensions - err error - ) - consumedUnits[fees.Bandwidth] = uint64(len(fc.Tx.Bytes())) + consumedUnits := commonConsumedUnits(fc.Tx) + var err error fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) return err } @@ -198,12 +171,9 @@ func (fc *FeeCalculator) AddPermissionlessDelegatorTx(tx *txs.AddPermissionlessD return nil } - var ( - consumedUnits fees.Dimensions - err error - ) - consumedUnits[fees.Bandwidth] = uint64(len(fc.Tx.Bytes())) + consumedUnits := commonConsumedUnits(fc.Tx) + var err error fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) return err } @@ -214,12 +184,9 @@ func (fc *FeeCalculator) BaseTx(*txs.BaseTx) error { return nil } - var ( - consumedUnits fees.Dimensions - err error - ) - consumedUnits[fees.Bandwidth] = uint64(len(fc.Tx.Bytes())) + consumedUnits := commonConsumedUnits(fc.Tx) + var err error fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) return err } @@ -230,12 +197,9 @@ func (fc *FeeCalculator) ImportTx(*txs.ImportTx) error { return nil } - var ( - consumedUnits fees.Dimensions - err error - ) - consumedUnits[fees.Bandwidth] = uint64(len(fc.Tx.Bytes())) + consumedUnits := commonConsumedUnits(fc.Tx) + var err error fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) return err } @@ -246,16 +210,22 @@ func (fc *FeeCalculator) ExportTx(*txs.ExportTx) error { return nil } - var ( - consumedUnits fees.Dimensions - err error - ) - consumedUnits[fees.Bandwidth] = uint64(len(fc.Tx.Bytes())) + consumedUnits := commonConsumedUnits(fc.Tx) + var err error fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) return err } +func commonConsumedUnits(tx *txs.Tx) fees.Dimensions { + var consumedUnits fees.Dimensions + consumedUnits[fees.Bandwidth] = uint64(len(tx.Bytes())) + + // TODO ABENEGIA: consider accounting for input complexity + consumedUnits[fees.UTXORead] = uint64(tx.Unsigned.InputIDs().Len()) + return consumedUnits +} + func processFees(cfg *config.Config, chainTime time.Time, fc *fees.Manager, consumedUnits fees.Dimensions) (uint64, error) { boundBreached, dimension := fc.CumulateUnits(consumedUnits, cfg.BlockMaxConsumedUnits(chainTime)) if boundBreached { From 23749c0509e835ac80f8a2c07a34288345c55abe Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 8 Jan 2024 18:47:30 +0100 Subject: [PATCH 012/190] added UTXOWrite fee dimension --- vms/platformvm/fees/manager.go | 4 ++-- vms/platformvm/txs/executor/fee_calculator.go | 6 +++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/vms/platformvm/fees/manager.go b/vms/platformvm/fees/manager.go index e51ad9313b2e..77014791781e 100644 --- a/vms/platformvm/fees/manager.go +++ b/vms/platformvm/fees/manager.go @@ -11,10 +11,10 @@ import "github.com/ava-labs/avalanchego/utils/math" const ( Bandwidth Dimension = 0 UTXORead Dimension = 1 - // UTXOWrite Dimension = 2 // includes delete + UTXOWrite Dimension = 2 // includes delete // Compute Dimension = 3 - FeeDimensions = 2 + FeeDimensions = 3 ) type ( diff --git a/vms/platformvm/txs/executor/fee_calculator.go b/vms/platformvm/txs/executor/fee_calculator.go index ea4d742ab7b4..0fc65f4e3013 100644 --- a/vms/platformvm/txs/executor/fee_calculator.go +++ b/vms/platformvm/txs/executor/fee_calculator.go @@ -222,7 +222,11 @@ func commonConsumedUnits(tx *txs.Tx) fees.Dimensions { consumedUnits[fees.Bandwidth] = uint64(len(tx.Bytes())) // TODO ABENEGIA: consider accounting for input complexity - consumedUnits[fees.UTXORead] = uint64(tx.Unsigned.InputIDs().Len()) + // TODO ABENEGIA: consider handling imports/exports differently + insCount := tx.Unsigned.InputIDs().Len() + outsCount := len(tx.Unsigned.Outputs()) + consumedUnits[fees.UTXORead] = uint64(insCount) // inputs are read + consumedUnits[fees.UTXOWrite] = uint64(insCount + outsCount) // inputs are deleted, outputs are created return consumedUnits } From 421032cbeb36630bf3b09a004240e7eb8f65f0b2 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 8 Jan 2024 19:16:59 +0100 Subject: [PATCH 013/190] minor renaming --- vms/platformvm/block/builder/builder.go | 2 +- vms/platformvm/block/builder/helpers_test.go | 2 +- vms/platformvm/block/executor/helpers_test.go | 2 +- vms/platformvm/block/executor/verifier.go | 2 +- vms/platformvm/config/fee_config.go | 4 +- vms/platformvm/fees/manager.go | 17 +++-- .../txs/executor/atomic_tx_executor.go | 2 +- .../txs/executor/create_chain_test.go | 10 +-- .../txs/executor/create_subnet_test.go | 2 +- vms/platformvm/txs/executor/helpers_test.go | 2 +- .../executor/staker_tx_verification_test.go | 13 ++-- .../txs/executor/standard_tx_executor_test.go | 64 +++++++++---------- .../txs/executor/tx_mempool_verifier.go | 2 +- 13 files changed, 62 insertions(+), 62 deletions(-) diff --git a/vms/platformvm/block/builder/builder.go b/vms/platformvm/block/builder/builder.go index 5c582fad12da..d1e65e7e8a21 100644 --- a/vms/platformvm/block/builder/builder.go +++ b/vms/platformvm/block/builder/builder.go @@ -380,7 +380,7 @@ func packBlockTxs( executor := &txexecutor.StandardTxExecutor{ Backend: backend, - BlkFeeManager: fees.NewManager(backend.Config.DefaultUnitPrices), + BlkFeeManager: fees.NewManager(backend.Config.DefaultUnitFees), State: txDiff, Tx: tx, } diff --git a/vms/platformvm/block/builder/helpers_test.go b/vms/platformvm/block/builder/helpers_test.go index 3ddd9e123889..3f563a0c55bd 100644 --- a/vms/platformvm/block/builder/helpers_test.go +++ b/vms/platformvm/block/builder/helpers_test.go @@ -239,7 +239,7 @@ func addSubnet(t *testing.T, env *environment) { executor := txexecutor.StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitPrices), + BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitFees), State: stateDiff, Tx: testSubnet1, } diff --git a/vms/platformvm/block/executor/helpers_test.go b/vms/platformvm/block/executor/helpers_test.go index 9c7ff2acf6fb..5e9278417923 100644 --- a/vms/platformvm/block/executor/helpers_test.go +++ b/vms/platformvm/block/executor/helpers_test.go @@ -250,7 +250,7 @@ func addSubnet(env *environment) { executor := executor.StandardTxExecutor{ Backend: env.backend, - BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitPrices), + BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitFees), State: stateDiff, Tx: testSubnet1, } diff --git a/vms/platformvm/block/executor/verifier.go b/vms/platformvm/block/executor/verifier.go index 57bb04feebf0..28502a51fef5 100644 --- a/vms/platformvm/block/executor/verifier.go +++ b/vms/platformvm/block/executor/verifier.go @@ -456,7 +456,7 @@ func (v *verifier) processStandardTxs(txs []*txs.Tx, state state.Diff, parentID inputs set.Set[ids.ID] funcs = make([]func(), 0, len(txs)) atomicRequests = make(map[ids.ID]*atomic.Requests) - feeManager = fees.NewManager(v.txExecutorBackend.Config.DefaultUnitPrices) + feeManager = fees.NewManager(v.txExecutorBackend.Config.DefaultUnitFees) ) for _, tx := range txs { txExecutor := executor.StandardTxExecutor{ diff --git a/vms/platformvm/config/fee_config.go b/vms/platformvm/config/fee_config.go index c99c8fd40a8b..866ca53bfe2d 100644 --- a/vms/platformvm/config/fee_config.go +++ b/vms/platformvm/config/fee_config.go @@ -7,7 +7,9 @@ import "github.com/ava-labs/avalanchego/vms/platformvm/fees" type FeeConfig struct { // Post E Fork, the unit fee for each dimension, denominated in Avax - DefaultUnitPrices fees.Dimensions + // As long as fees are multidimensional but not dynamic, [DefaultUnitFees] + // will be the unit fees + DefaultUnitFees fees.Dimensions // Post E Fork, the max complexity of a block for each dimension DefaultBlockMaxConsumedUnits fees.Dimensions diff --git a/vms/platformvm/fees/manager.go b/vms/platformvm/fees/manager.go index 77014791781e..d68c4068cd73 100644 --- a/vms/platformvm/fees/manager.go +++ b/vms/platformvm/fees/manager.go @@ -5,16 +5,15 @@ package fees import "github.com/ava-labs/avalanchego/utils/math" -// 1. Fees are not dynamic yet. We'll add mechanism for fee updating iterativelly -// 2. Not all fees dimensions are correctly prices. We'll add other dimensions iteratively +// Fees are not dynamic yet. We'll add mechanism for fee updating iterativelly const ( Bandwidth Dimension = 0 UTXORead Dimension = 1 UTXOWrite Dimension = 2 // includes delete - // Compute Dimension = 3 + Compute Dimension = 3 // any other cost, tx-specific - FeeDimensions = 3 + FeeDimensions = 4 ) type ( @@ -23,17 +22,17 @@ type ( ) type Manager struct { - // Avax prices per units for all fee dimensions - unitPrices Dimensions + // Avax denominated unit fees for all fee dimensions + unitFees Dimensions // cumulatedUnits helps aggregating the units consumed by a block // so that we can verify it's not too big/build it properly. cumulatedUnits Dimensions } -func NewManager(unitPrices Dimensions) *Manager { +func NewManager(unitFees Dimensions) *Manager { return &Manager{ - unitPrices: unitPrices, + unitFees: unitFees, } } @@ -41,7 +40,7 @@ func (m *Manager) CalculateFee(units Dimensions) (uint64, error) { fee := uint64(0) for i := Dimension(0); i < FeeDimensions; i++ { - contribution, err := math.Mul64(m.unitPrices[i], units[i]) + contribution, err := math.Mul64(m.unitFees[i], units[i]) if err != nil { return 0, err } diff --git a/vms/platformvm/txs/executor/atomic_tx_executor.go b/vms/platformvm/txs/executor/atomic_tx_executor.go index 3d8fcbd18846..e89d6ca40e8c 100644 --- a/vms/platformvm/txs/executor/atomic_tx_executor.go +++ b/vms/platformvm/txs/executor/atomic_tx_executor.go @@ -101,7 +101,7 @@ func (e *AtomicTxExecutor) atomicTx(tx txs.UnsignedTx) error { executor := StandardTxExecutor{ Backend: e.Backend, - BlkFeeManager: fees.NewManager(e.Backend.Config.DefaultUnitPrices), + BlkFeeManager: fees.NewManager(e.Backend.Config.DefaultUnitFees), State: e.OnAccept, Tx: e.Tx, } diff --git a/vms/platformvm/txs/executor/create_chain_test.go b/vms/platformvm/txs/executor/create_chain_test.go index 2f83d505503b..ecaf05a4ca20 100644 --- a/vms/platformvm/txs/executor/create_chain_test.go +++ b/vms/platformvm/txs/executor/create_chain_test.go @@ -51,7 +51,7 @@ func TestCreateChainTxInsufficientControlSigs(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitPrices), + BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitFees), State: stateDiff, Tx: tx, } @@ -93,7 +93,7 @@ func TestCreateChainTxWrongControlSig(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitPrices), + BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitFees), State: stateDiff, Tx: tx, } @@ -129,7 +129,7 @@ func TestCreateChainTxNoSuchSubnet(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitPrices), + BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitFees), State: stateDiff, Tx: tx, } @@ -162,7 +162,7 @@ func TestCreateChainTxValid(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitPrices), + BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitFees), State: stateDiff, Tx: tx, } @@ -237,7 +237,7 @@ func TestCreateChainTxAP3FeeChange(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitPrices), + BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitFees), State: stateDiff, Tx: tx, } diff --git a/vms/platformvm/txs/executor/create_subnet_test.go b/vms/platformvm/txs/executor/create_subnet_test.go index 31b8c0d04556..237f2986b2f6 100644 --- a/vms/platformvm/txs/executor/create_subnet_test.go +++ b/vms/platformvm/txs/executor/create_subnet_test.go @@ -80,7 +80,7 @@ func TestCreateSubnetTxAP3FeeChange(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitPrices), + BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitFees), State: stateDiff, Tx: tx, } diff --git a/vms/platformvm/txs/executor/helpers_test.go b/vms/platformvm/txs/executor/helpers_test.go index a48f1244f964..9043299e0e90 100644 --- a/vms/platformvm/txs/executor/helpers_test.go +++ b/vms/platformvm/txs/executor/helpers_test.go @@ -207,7 +207,7 @@ func addSubnet( executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitPrices), + BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitFees), State: stateDiff, Tx: testSubnet1, } diff --git a/vms/platformvm/txs/executor/staker_tx_verification_test.go b/vms/platformvm/txs/executor/staker_tx_verification_test.go index 52a7aea397bd..555984fcc79d 100644 --- a/vms/platformvm/txs/executor/staker_tx_verification_test.go +++ b/vms/platformvm/txs/executor/staker_tx_verification_test.go @@ -608,7 +608,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { FlowChecker: flowChecker, Config: &config.Config{ FeeConfig: config.FeeConfig{ - DefaultUnitPrices: fees.Dimensions{ + DefaultUnitFees: fees.Dimensions{ 10, }, DefaultBlockMaxConsumedUnits: fees.Dimensions{ @@ -661,7 +661,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { FlowChecker: flowChecker, Config: &config.Config{ FeeConfig: config.FeeConfig{ - DefaultUnitPrices: fees.Dimensions{ + DefaultUnitFees: fees.Dimensions{ 10, }, DefaultBlockMaxConsumedUnits: fees.Dimensions{ @@ -703,11 +703,10 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { var ( backend = tt.backendF(ctrl) - defaultUnitPrices = backend.Config.DefaultUnitPrices - feeManager = fees.NewManager(defaultUnitPrices) - state = tt.stateF(ctrl) - sTx = tt.sTxF() - tx = tt.txF() + feeManager = fees.NewManager(backend.Config.DefaultUnitFees) + state = tt.stateF(ctrl) + sTx = tt.sTxF() + tx = tt.txF() ) err := verifyAddPermissionlessValidatorTx(backend, feeManager, state, 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 17cd27dea6c3..424e548c3f43 100644 --- a/vms/platformvm/txs/executor/standard_tx_executor_test.go +++ b/vms/platformvm/txs/executor/standard_tx_executor_test.go @@ -90,7 +90,7 @@ func TestStandardTxExecutorAddValidatorTxEmptyID(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitPrices), + BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitFees), State: stateDiff, Tx: tx, } @@ -361,7 +361,7 @@ func TestStandardTxExecutorAddDelegator(t *testing.T) { executor := StandardTxExecutor{ Backend: &freshTH.backend, - BlkFeeManager: fees.NewManager(freshTH.backend.Config.DefaultUnitPrices), + BlkFeeManager: fees.NewManager(freshTH.backend.Config.DefaultUnitFees), State: onAcceptState, Tx: tx, } @@ -411,7 +411,7 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitPrices), + BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitFees), State: onAcceptState, Tx: tx, } @@ -440,7 +440,7 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitPrices), + BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitFees), State: onAcceptState, Tx: tx, } @@ -483,7 +483,7 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitPrices), + BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitFees), State: onAcceptState, Tx: tx, } @@ -527,7 +527,7 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitPrices), + BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitFees), State: onAcceptState, Tx: tx, } @@ -554,7 +554,7 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitPrices), + BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitFees), State: onAcceptState, Tx: tx, } @@ -580,7 +580,7 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { require.NoError(err) executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitPrices), + BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitFees), State: onAcceptState, Tx: tx, } @@ -609,7 +609,7 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitPrices), + BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitFees), State: onAcceptState, Tx: tx, } @@ -666,7 +666,7 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitPrices), + BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitFees), State: onAcceptState, Tx: duplicateSubnetTx, } @@ -704,7 +704,7 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitPrices), + BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitFees), State: onAcceptState, Tx: tx, } @@ -738,7 +738,7 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitPrices), + BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitFees), State: onAcceptState, Tx: tx, } @@ -770,7 +770,7 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitPrices), + BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitFees), State: onAcceptState, Tx: tx, } @@ -812,7 +812,7 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitPrices), + BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitFees), State: onAcceptState, Tx: tx, } @@ -850,7 +850,7 @@ func TestStandardTxExecutorBanffAddValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitPrices), + BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitFees), State: onAcceptState, Tx: tx, } @@ -877,7 +877,7 @@ func TestStandardTxExecutorBanffAddValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitPrices), + BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitFees), State: onAcceptState, Tx: tx, } @@ -917,7 +917,7 @@ func TestStandardTxExecutorBanffAddValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitPrices), + BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitFees), State: onAcceptState, Tx: tx, } @@ -954,7 +954,7 @@ func TestStandardTxExecutorBanffAddValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitPrices), + BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitFees), State: onAcceptState, Tx: tx, } @@ -990,7 +990,7 @@ func TestStandardTxExecutorBanffAddValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitPrices), + BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitFees), State: onAcceptState, Tx: tx, } @@ -1181,7 +1181,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(cfg.DefaultUnitPrices), + BlkFeeManager: fees.NewManager(cfg.DefaultUnitFees), Tx: env.tx, State: env.state, } @@ -1212,7 +1212,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(cfg.DefaultUnitPrices), + BlkFeeManager: fees.NewManager(cfg.DefaultUnitFees), Tx: env.tx, State: env.state, } @@ -1243,7 +1243,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(cfg.DefaultUnitPrices), + BlkFeeManager: fees.NewManager(cfg.DefaultUnitFees), Tx: env.tx, State: env.state, } @@ -1277,7 +1277,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(cfg.DefaultUnitPrices), + BlkFeeManager: fees.NewManager(cfg.DefaultUnitFees), Tx: env.tx, State: env.state, } @@ -1309,7 +1309,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(cfg.DefaultUnitPrices), + BlkFeeManager: fees.NewManager(cfg.DefaultUnitFees), Tx: env.tx, State: env.state, } @@ -1340,7 +1340,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(cfg.DefaultUnitPrices), + BlkFeeManager: fees.NewManager(cfg.DefaultUnitFees), Tx: env.tx, State: env.state, } @@ -1373,7 +1373,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(cfg.DefaultUnitPrices), + BlkFeeManager: fees.NewManager(cfg.DefaultUnitFees), Tx: env.tx, State: env.state, } @@ -1410,7 +1410,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(cfg.DefaultUnitPrices), + BlkFeeManager: fees.NewManager(cfg.DefaultUnitFees), Tx: env.tx, State: env.state, } @@ -1571,7 +1571,7 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(cfg.DefaultUnitPrices), + BlkFeeManager: fees.NewManager(cfg.DefaultUnitFees), Tx: env.tx, State: env.state, } @@ -1601,7 +1601,7 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(cfg.DefaultUnitPrices), + BlkFeeManager: fees.NewManager(cfg.DefaultUnitFees), Tx: env.tx, State: env.state, } @@ -1633,7 +1633,7 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(cfg.DefaultUnitPrices), + BlkFeeManager: fees.NewManager(cfg.DefaultUnitFees), Tx: env.tx, State: env.state, } @@ -1670,7 +1670,7 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(cfg.DefaultUnitPrices), + BlkFeeManager: fees.NewManager(cfg.DefaultUnitFees), Tx: env.tx, State: env.state, } @@ -1712,7 +1712,7 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(cfg.DefaultUnitPrices), + BlkFeeManager: fees.NewManager(cfg.DefaultUnitFees), Tx: env.tx, State: env.state, } diff --git a/vms/platformvm/txs/executor/tx_mempool_verifier.go b/vms/platformvm/txs/executor/tx_mempool_verifier.go index 8aa87ba4c970..7a356aabfb38 100644 --- a/vms/platformvm/txs/executor/tx_mempool_verifier.go +++ b/vms/platformvm/txs/executor/tx_mempool_verifier.go @@ -92,7 +92,7 @@ func (v *MempoolTxVerifier) standardTx(tx txs.UnsignedTx) error { executor := StandardTxExecutor{ Backend: v.Backend, - BlkFeeManager: fees.NewManager(v.Backend.Config.DefaultUnitPrices), + BlkFeeManager: fees.NewManager(v.Backend.Config.DefaultUnitFees), State: baseState, Tx: v.Tx, } From 82fb7889dc336c8a02d1be2e9f3f49fba7c90a27 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Tue, 9 Jan 2024 09:57:05 +0100 Subject: [PATCH 014/190] nit --- vms/platformvm/txs/executor/fee_calculator.go | 8 +++++--- .../txs/executor/staker_tx_verification.go | 14 +++++++------- .../txs/executor/standard_tx_executor.go | 10 +++++----- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/vms/platformvm/txs/executor/fee_calculator.go b/vms/platformvm/txs/executor/fee_calculator.go index 0fc65f4e3013..60ea687badd6 100644 --- a/vms/platformvm/txs/executor/fee_calculator.go +++ b/vms/platformvm/txs/executor/fee_calculator.go @@ -22,11 +22,13 @@ var ( ) type FeeCalculator struct { - // inputs, to be filled before visitor methods are called + // setup, to be filled before visitor methods are called + feeManager *fees.Manager Config *config.Config ChainTime time.Time - Tx *txs.Tx - feeManager *fees.Manager + + // inputs, to be filled before visitor methods are called + Tx *txs.Tx // outputs of visitor execution Fee uint64 diff --git a/vms/platformvm/txs/executor/staker_tx_verification.go b/vms/platformvm/txs/executor/staker_tx_verification.go index 7726fb18e047..b90d057780d0 100644 --- a/vms/platformvm/txs/executor/staker_tx_verification.go +++ b/vms/platformvm/txs/executor/staker_tx_verification.go @@ -163,10 +163,10 @@ func verifyAddValidatorTx( // Verify the flowcheck feeCalculator := FeeCalculator{ + feeManager: feeManager, Config: backend.Config, ChainTime: currentTimestamp, Tx: sTx, - feeManager: feeManager, } if err := tx.Visit(&feeCalculator); err != nil { return nil, err @@ -260,10 +260,10 @@ func verifyAddSubnetValidatorTx( // Verify the flowcheck feeCalculator := FeeCalculator{ + feeManager: feeManager, Config: backend.Config, ChainTime: currentTimestamp, Tx: sTx, - feeManager: feeManager, } if err := tx.Visit(&feeCalculator); err != nil { return err @@ -340,10 +340,10 @@ func verifyRemoveSubnetValidatorTx( // Verify the flowcheck feeCalculator := FeeCalculator{ + feeManager: feeManager, Config: backend.Config, ChainTime: chainState.GetTimestamp(), Tx: sTx, - feeManager: feeManager, } if err := tx.Visit(&feeCalculator); err != nil { return nil, false, err @@ -463,10 +463,10 @@ func verifyAddDelegatorTx( // Verify the flowcheck feeCalculator := FeeCalculator{ + feeManager: feeManager, Config: backend.Config, ChainTime: chainState.GetTimestamp(), Tx: sTx, - feeManager: feeManager, } if err := tx.Visit(&feeCalculator); err != nil { return nil, err @@ -589,10 +589,10 @@ func verifyAddPermissionlessValidatorTx( // Verify the flowcheck feeCalculator := FeeCalculator{ + feeManager: feeManager, Config: backend.Config, ChainTime: currentTimestamp, Tx: sTx, - feeManager: feeManager, } if err := tx.Visit(&feeCalculator); err != nil { return err @@ -738,10 +738,10 @@ func verifyAddPermissionlessDelegatorTx( // Verify the flowcheck feeCalculator := FeeCalculator{ + feeManager: feeManager, Config: backend.Config, ChainTime: currentTimestamp, Tx: sTx, - feeManager: feeManager, } if err := tx.Visit(&feeCalculator); err != nil { return err @@ -798,10 +798,10 @@ func verifyTransferSubnetOwnershipTx( // Verify the flowcheck feeCalculator := FeeCalculator{ + feeManager: feeManager, Config: backend.Config, ChainTime: chainState.GetTimestamp(), Tx: sTx, - feeManager: feeManager, } if err := tx.Visit(&feeCalculator); err != nil { return err diff --git a/vms/platformvm/txs/executor/standard_tx_executor.go b/vms/platformvm/txs/executor/standard_tx_executor.go index 4bab74a0757d..7fef238361cd 100644 --- a/vms/platformvm/txs/executor/standard_tx_executor.go +++ b/vms/platformvm/txs/executor/standard_tx_executor.go @@ -63,10 +63,10 @@ func (e *StandardTxExecutor) CreateChainTx(tx *txs.CreateChainTx) error { // Verify the flowcheck feeCalculator := FeeCalculator{ + feeManager: e.BlkFeeManager, Config: e.Backend.Config, ChainTime: e.State.GetTimestamp(), Tx: e.Tx, - feeManager: e.BlkFeeManager, } if err := tx.Visit(&feeCalculator); err != nil { return err @@ -110,10 +110,10 @@ func (e *StandardTxExecutor) CreateSubnetTx(tx *txs.CreateSubnetTx) error { // Verify the flowcheck feeCalculator := FeeCalculator{ + feeManager: e.BlkFeeManager, Config: e.Backend.Config, ChainTime: e.State.GetTimestamp(), Tx: e.Tx, - feeManager: e.BlkFeeManager, } if err := tx.Visit(&feeCalculator); err != nil { return err @@ -192,10 +192,10 @@ func (e *StandardTxExecutor) ImportTx(tx *txs.ImportTx) error { // Verify the flowcheck feeCalculator := FeeCalculator{ + feeManager: e.BlkFeeManager, Config: e.Backend.Config, ChainTime: e.State.GetTimestamp(), Tx: e.Tx, - feeManager: e.BlkFeeManager, } if err := tx.Visit(&feeCalculator); err != nil { return err @@ -250,10 +250,10 @@ func (e *StandardTxExecutor) ExportTx(tx *txs.ExportTx) error { // Verify the flowcheck feeCalculator := FeeCalculator{ + feeManager: e.BlkFeeManager, Config: e.Backend.Config, ChainTime: e.State.GetTimestamp(), Tx: e.Tx, - feeManager: e.BlkFeeManager, } if err := tx.Visit(&feeCalculator); err != nil { return err @@ -560,10 +560,10 @@ func (e *StandardTxExecutor) BaseTx(tx *txs.BaseTx) error { // Verify the flowcheck feeCalculator := FeeCalculator{ + feeManager: e.BlkFeeManager, Config: e.Backend.Config, ChainTime: e.State.GetTimestamp(), Tx: e.Tx, - feeManager: e.BlkFeeManager, } if err := tx.Visit(&feeCalculator); err != nil { return err From 7f2c7990728e8dd9c950ab4d6f841379ff4819cf Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Tue, 9 Jan 2024 11:47:38 +0100 Subject: [PATCH 015/190] wip: improved utxos complexity metering --- vms/platformvm/txs/executor/fee_calculator.go | 166 +++++++++++++----- 1 file changed, 121 insertions(+), 45 deletions(-) diff --git a/vms/platformvm/txs/executor/fee_calculator.go b/vms/platformvm/txs/executor/fee_calculator.go index 60ea687badd6..b464d8afc082 100644 --- a/vms/platformvm/txs/executor/fee_calculator.go +++ b/vms/platformvm/txs/executor/fee_calculator.go @@ -9,6 +9,7 @@ import ( "time" "github.com/ava-labs/avalanchego/utils/constants" + "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/platformvm/config" "github.com/ava-labs/avalanchego/vms/platformvm/fees" "github.com/ava-labs/avalanchego/vms/platformvm/txs" @@ -34,67 +35,85 @@ type FeeCalculator struct { Fee uint64 } -func (fc *FeeCalculator) AddValidatorTx(*txs.AddValidatorTx) error { +func (fc *FeeCalculator) AddValidatorTx(tx *txs.AddValidatorTx) error { if !fc.Config.IsEForkActivated(fc.ChainTime) { fc.Fee = fc.Config.AddPrimaryNetworkValidatorFee return nil } - consumedUnits := commonConsumedUnits(fc.Tx) + outs := make([]*avax.TransferableOutput, len(tx.Outs)+len(tx.StakeOuts)) + copy(outs, tx.Outs) + copy(outs[len(tx.Outs):], tx.StakeOuts) + + consumedUnits, err := commonConsumedUnits(fc.Tx, outs, tx.Ins) + if err != nil { + return err + } - var err error fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) return err } -func (fc *FeeCalculator) AddSubnetValidatorTx(*txs.AddSubnetValidatorTx) error { +func (fc *FeeCalculator) AddSubnetValidatorTx(tx *txs.AddSubnetValidatorTx) error { if !fc.Config.IsEForkActivated(fc.ChainTime) { fc.Fee = fc.Config.AddSubnetValidatorFee return nil } - consumedUnits := commonConsumedUnits(fc.Tx) + consumedUnits, err := commonConsumedUnits(fc.Tx, tx.Outs, tx.Ins) + if err != nil { + return err + } - var err error fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) return err } -func (fc *FeeCalculator) AddDelegatorTx(*txs.AddDelegatorTx) error { +func (fc *FeeCalculator) AddDelegatorTx(tx *txs.AddDelegatorTx) error { if !fc.Config.IsEForkActivated(fc.ChainTime) { fc.Fee = fc.Config.AddPrimaryNetworkDelegatorFee return nil } - consumedUnits := commonConsumedUnits(fc.Tx) + outs := make([]*avax.TransferableOutput, len(tx.Outs)+len(tx.StakeOuts)) + copy(outs, tx.Outs) + copy(outs[len(tx.Outs):], tx.StakeOuts) + + consumedUnits, err := commonConsumedUnits(fc.Tx, outs, tx.Ins) + if err != nil { + return err + } - var err error fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) return err } -func (fc *FeeCalculator) CreateChainTx(*txs.CreateChainTx) error { +func (fc *FeeCalculator) CreateChainTx(tx *txs.CreateChainTx) error { if !fc.Config.IsEForkActivated(fc.ChainTime) { fc.Fee = fc.Config.GetCreateBlockchainTxFee(fc.ChainTime) return nil } - consumedUnits := commonConsumedUnits(fc.Tx) + consumedUnits, err := commonConsumedUnits(fc.Tx, tx.Outs, tx.Ins) + if err != nil { + return err + } - var err error fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) return err } -func (fc *FeeCalculator) CreateSubnetTx(*txs.CreateSubnetTx) error { +func (fc *FeeCalculator) CreateSubnetTx(tx *txs.CreateSubnetTx) error { if !fc.Config.IsEForkActivated(fc.ChainTime) { fc.Fee = fc.Config.GetCreateSubnetTxFee(fc.ChainTime) return nil } - consumedUnits := commonConsumedUnits(fc.Tx) + consumedUnits, err := commonConsumedUnits(fc.Tx, tx.Outs, tx.Ins) + if err != nil { + return err + } - var err error fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) return err } @@ -107,41 +126,47 @@ func (*FeeCalculator) RewardValidatorTx(*txs.RewardValidatorTx) error { return nil // no fees } -func (fc *FeeCalculator) RemoveSubnetValidatorTx(*txs.RemoveSubnetValidatorTx) error { +func (fc *FeeCalculator) RemoveSubnetValidatorTx(tx *txs.RemoveSubnetValidatorTx) error { if !fc.Config.IsEForkActivated(fc.ChainTime) { fc.Fee = fc.Config.TxFee return nil } - consumedUnits := commonConsumedUnits(fc.Tx) + consumedUnits, err := commonConsumedUnits(fc.Tx, tx.Outs, tx.Ins) + if err != nil { + return err + } - var err error fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) return err } -func (fc *FeeCalculator) TransformSubnetTx(*txs.TransformSubnetTx) error { +func (fc *FeeCalculator) TransformSubnetTx(tx *txs.TransformSubnetTx) error { if !fc.Config.IsEForkActivated(fc.ChainTime) { fc.Fee = fc.Config.TransformSubnetTxFee return nil } - consumedUnits := commonConsumedUnits(fc.Tx) + consumedUnits, err := commonConsumedUnits(fc.Tx, tx.Outs, tx.Ins) + if err != nil { + return err + } - var err error fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) return err } -func (fc *FeeCalculator) TransferSubnetOwnershipTx(*txs.TransferSubnetOwnershipTx) error { +func (fc *FeeCalculator) TransferSubnetOwnershipTx(tx *txs.TransferSubnetOwnershipTx) error { if !fc.Config.IsEForkActivated(fc.ChainTime) { fc.Fee = fc.Config.TxFee return nil } - consumedUnits := commonConsumedUnits(fc.Tx) + consumedUnits, err := commonConsumedUnits(fc.Tx, tx.Outs, tx.Ins) + if err != nil { + return err + } - var err error fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) return err } @@ -156,9 +181,15 @@ func (fc *FeeCalculator) AddPermissionlessValidatorTx(tx *txs.AddPermissionlessV return nil } - consumedUnits := commonConsumedUnits(fc.Tx) + outs := make([]*avax.TransferableOutput, len(tx.Outs)+len(tx.StakeOuts)) + copy(outs, tx.Outs) + copy(outs[len(tx.Outs):], tx.StakeOuts) + + consumedUnits, err := commonConsumedUnits(fc.Tx, outs, tx.Ins) + if err != nil { + return err + } - var err error fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) return err } @@ -173,63 +204,108 @@ func (fc *FeeCalculator) AddPermissionlessDelegatorTx(tx *txs.AddPermissionlessD return nil } - consumedUnits := commonConsumedUnits(fc.Tx) + outs := make([]*avax.TransferableOutput, len(tx.Outs)+len(tx.StakeOuts)) + copy(outs, tx.Outs) + copy(outs[len(tx.Outs):], tx.StakeOuts) + + consumedUnits, err := commonConsumedUnits(fc.Tx, outs, tx.Ins) + if err != nil { + return err + } - var err error fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) return err } -func (fc *FeeCalculator) BaseTx(*txs.BaseTx) error { +func (fc *FeeCalculator) BaseTx(tx *txs.BaseTx) error { if !fc.Config.IsEForkActivated(fc.ChainTime) { fc.Fee = fc.Config.TxFee return nil } - consumedUnits := commonConsumedUnits(fc.Tx) + consumedUnits, err := commonConsumedUnits(fc.Tx, tx.Outs, tx.Ins) + if err != nil { + return err + } - var err error fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) return err } -func (fc *FeeCalculator) ImportTx(*txs.ImportTx) error { +func (fc *FeeCalculator) ImportTx(tx *txs.ImportTx) error { if !fc.Config.IsEForkActivated(fc.ChainTime) { fc.Fee = fc.Config.TxFee return nil } - consumedUnits := commonConsumedUnits(fc.Tx) + ins := make([]*avax.TransferableInput, len(tx.Ins)+len(tx.ImportedInputs)) + copy(ins, tx.Ins) + copy(ins[len(tx.Ins):], tx.ImportedInputs) + + consumedUnits, err := commonConsumedUnits(fc.Tx, tx.Outs, ins) + if err != nil { + return err + } - var err error fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) return err } -func (fc *FeeCalculator) ExportTx(*txs.ExportTx) error { +func (fc *FeeCalculator) ExportTx(tx *txs.ExportTx) error { if !fc.Config.IsEForkActivated(fc.ChainTime) { fc.Fee = fc.Config.TxFee return nil } - consumedUnits := commonConsumedUnits(fc.Tx) + outs := make([]*avax.TransferableOutput, len(tx.Outs)+len(tx.ExportedOutputs)) + copy(outs, tx.Outs) + copy(outs[len(tx.Outs):], tx.ExportedOutputs) + + consumedUnits, err := commonConsumedUnits(fc.Tx, outs, tx.Ins) + if err != nil { + return err + } - var err error fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) return err } -func commonConsumedUnits(tx *txs.Tx) fees.Dimensions { +func commonConsumedUnits(sTx *txs.Tx, allOuts []*avax.TransferableOutput, allIns []*avax.TransferableInput) (fees.Dimensions, error) { var consumedUnits fees.Dimensions - consumedUnits[fees.Bandwidth] = uint64(len(tx.Bytes())) + consumedUnits[fees.Bandwidth] = uint64(len(sTx.Bytes())) - // TODO ABENEGIA: consider accounting for input complexity // TODO ABENEGIA: consider handling imports/exports differently - insCount := tx.Unsigned.InputIDs().Len() - outsCount := len(tx.Unsigned.Outputs()) - consumedUnits[fees.UTXORead] = uint64(insCount) // inputs are read - consumedUnits[fees.UTXOWrite] = uint64(insCount + outsCount) // inputs are deleted, outputs are created - return consumedUnits + var ( + insCost uint64 + insSize uint64 + outsSize uint64 + ) + + for _, in := range allIns { + cost, err := in.In.Cost() + if err != nil { + return consumedUnits, fmt.Errorf("failed retrieving cost of input %s: %w", in.ID, err) + } + insCost += cost + + inSize, err := txs.Codec.Size(txs.CodecVersion, in) + if err != nil { + return consumedUnits, fmt.Errorf("failed retrieving size of input %s: %w", in.ID, err) + } + insSize += uint64(inSize) + } + + for _, out := range allOuts { + outSize, err := txs.Codec.Size(txs.CodecVersion, out) + if err != nil { + return consumedUnits, fmt.Errorf("failed retrieving size of output %s: %w", out.ID, err) + } + outsSize += uint64(outSize) + } + + consumedUnits[fees.UTXORead] = insCost + insSize // inputs are read + consumedUnits[fees.UTXOWrite] = insSize + outsSize // inputs are deleted, outputs are created + return consumedUnits, nil } func processFees(cfg *config.Config, chainTime time.Time, fc *fees.Manager, consumedUnits fees.Dimensions) (uint64, error) { From 3cf241acfd97ac8c1d4f8cc617e43f1a3dcaea32 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Tue, 9 Jan 2024 14:04:26 +0100 Subject: [PATCH 016/190] wip: adding UTs --- vms/platformvm/fees/manager.go | 4 + .../txs/executor/fee_calculator_test.go | 198 ++++++++++++++++++ .../executor/staker_tx_verification_test.go | 98 --------- 3 files changed, 202 insertions(+), 98 deletions(-) create mode 100644 vms/platformvm/txs/executor/fee_calculator_test.go diff --git a/vms/platformvm/fees/manager.go b/vms/platformvm/fees/manager.go index d68c4068cd73..4a93bed3c4b0 100644 --- a/vms/platformvm/fees/manager.go +++ b/vms/platformvm/fees/manager.go @@ -77,3 +77,7 @@ func (m *Manager) CumulateUnits(units, bounds Dimensions) (bool, Dimension) { } return false, 0 } + +func (m *Manager) GetCumulatedUnits() Dimensions { + return m.cumulatedUnits +} diff --git a/vms/platformvm/txs/executor/fee_calculator_test.go b/vms/platformvm/txs/executor/fee_calculator_test.go new file mode 100644 index 000000000000..5839f3f2b3a0 --- /dev/null +++ b/vms/platformvm/txs/executor/fee_calculator_test.go @@ -0,0 +1,198 @@ +// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package executor + +import ( + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/snow/snowtest" + "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" + "github.com/ava-labs/avalanchego/utils/units" + "github.com/ava-labs/avalanchego/vms/components/avax" + "github.com/ava-labs/avalanchego/vms/platformvm/config" + "github.com/ava-labs/avalanchego/vms/platformvm/fees" + "github.com/ava-labs/avalanchego/vms/platformvm/reward" + "github.com/ava-labs/avalanchego/vms/platformvm/stakeable" + "github.com/ava-labs/avalanchego/vms/platformvm/txs" + "github.com/ava-labs/avalanchego/vms/secp256k1fx" +) + +func TestAddValidatorTxFees(t *testing.T) { + // For simplicity, we define a single AddValidatorTx + // and we change config parameters in the different test cases + r := require.New(t) + + defaultCtx := snowtest.Context(t, snowtest.PChainID) + defaultFeeCfg := config.FeeConfig{ + DefaultUnitFees: fees.Dimensions{ + 1 * units.MicroAvax, + 2 * units.MicroAvax, + 3 * units.MicroAvax, + 4 * units.MicroAvax, + }, + DefaultBlockMaxConsumedUnits: fees.Dimensions{ + 1000, + 1500, + 1000, + 1000, + }, + AddPrimaryNetworkValidatorFee: 0, + } + + // create a well formed AddValidatorTx + signers := [][]*secp256k1.PrivateKey{preFundedKeys} + validatorWeight := uint64(2024) + inputs := []*avax.TransferableInput{{ + UTXOID: avax.UTXOID{ + TxID: ids.ID{'t', 'x', 'I', 'D'}, + OutputIndex: 2, + }, + Asset: avax.Asset{ID: defaultCtx.AVAXAssetID}, + In: &secp256k1fx.TransferInput{ + Amt: uint64(5678), + Input: secp256k1fx.Input{SigIndices: []uint32{0}}, + }, + }} + outputs := []*avax.TransferableOutput{{ + Asset: avax.Asset{ID: defaultCtx.AVAXAssetID}, + Out: &secp256k1fx.TransferOutput{ + Amt: uint64(1234), + OutputOwners: secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{preFundedKeys[0].PublicKey().Address()}, + }, + }, + }} + stakes := []*avax.TransferableOutput{{ + Asset: avax.Asset{ID: defaultCtx.AVAXAssetID}, + Out: &stakeable.LockOut{ + Locktime: uint64(time.Now().Add(time.Second).Unix()), + TransferableOut: &secp256k1fx.TransferOutput{ + Amt: validatorWeight, + OutputOwners: secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{preFundedKeys[0].PublicKey().Address()}, + }, + }, + }, + }} + uTx := &txs.AddValidatorTx{ + BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ + NetworkID: defaultCtx.NetworkID, + BlockchainID: defaultCtx.ChainID, + Ins: inputs, + Outs: outputs, + }}, + Validator: txs.Validator{ + NodeID: defaultCtx.NodeID, + Start: uint64(time.Now().Truncate(time.Second).Unix()), + End: uint64(time.Now().Truncate(time.Second).Add(time.Hour).Unix()), + Wght: validatorWeight, + }, + StakeOuts: stakes, + RewardsOwner: &secp256k1fx.OutputOwners{ + Locktime: 0, + Threshold: 1, + Addrs: []ids.ShortID{ids.GenerateTestShortID()}, + }, + DelegationShares: reward.PercentDenominator, + } + stx, err := txs.NewSigned(uTx, txs.Codec, signers) + r.NoError(err) + + type test struct { + description string + cfgAndChainTimeF func() (*config.Config, time.Time) + expectedError error + checksF func(*testing.T, *FeeCalculator) + } + + tests := []test{ + { + description: "pre E fork", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(-1 * time.Second) + + cfg := &config.Config{ + FeeConfig: defaultFeeCfg, + DurangoTime: time.Time{}, // durango already active + EForkTime: eForkTime, + } + + return cfg, chainTime + }, + expectedError: nil, + checksF: func(t *testing.T, fc *FeeCalculator) { + require.Equal(t, fc.Config.AddPrimaryNetworkValidatorFee, fc.Fee) + }, + }, + { + description: "post E fork, success", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(time.Second) + + cfg := &config.Config{ + FeeConfig: defaultFeeCfg, + DurangoTime: time.Time{}, // durango already active + EForkTime: eForkTime, + } + + return cfg, chainTime + }, + expectedError: nil, + checksF: func(t *testing.T, fc *FeeCalculator) { + require.Equal(t, 3721*units.MicroAvax, fc.Fee) + require.Equal(t, + fees.Dimensions{ + uint64(len(stx.Bytes())), // this is a simple rule, can assert easily + 1090, // this is more complex rule, gotta check against hard-coded value + 266, // this is more complex rule, gotta check against hard-coded value + 0, + }, + fc.feeManager.GetCumulatedUnits(), + ) + }, + }, + { + description: "post E fork, bandwidth cap breached", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(time.Second) + + cfg := &config.Config{ + FeeConfig: defaultFeeCfg, + DurangoTime: time.Time{}, // durango already active + EForkTime: eForkTime, + } + cfg.DefaultBlockMaxConsumedUnits[0] = uint64(len(stx.Bytes())) - 1 + + return cfg, chainTime + }, + expectedError: errFailedConsumedUnitsCumulation, + checksF: func(t *testing.T, fc *FeeCalculator) {}, + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + cfg, chainTime := tt.cfgAndChainTimeF() + + fc := &FeeCalculator{ + feeManager: fees.NewManager(cfg.DefaultUnitFees), + Config: cfg, + ChainTime: chainTime, + Tx: stx, + } + err := uTx.Visit(fc) + r.ErrorIs(err, tt.expectedError) + tt.checksF(t, fc) + }) + } +} diff --git a/vms/platformvm/txs/executor/staker_tx_verification_test.go b/vms/platformvm/txs/executor/staker_tx_verification_test.go index 555984fcc79d..844f5d8b33d7 100644 --- a/vms/platformvm/txs/executor/staker_tx_verification_test.go +++ b/vms/platformvm/txs/executor/staker_tx_verification_test.go @@ -596,104 +596,6 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { }, expectedErr: nil, }, - { - name: "unit bound breached post EFork", - backendF: func(ctrl *gomock.Controller) *Backend { - bootstrapped := &utils.Atomic[bool]{} - bootstrapped.Set(true) - - flowChecker := utxo.NewMockVerifier(ctrl) - - return &Backend{ - FlowChecker: flowChecker, - Config: &config.Config{ - FeeConfig: config.FeeConfig{ - DefaultUnitFees: fees.Dimensions{ - 10, - }, - DefaultBlockMaxConsumedUnits: fees.Dimensions{ - uint64(len(signedBytes)) - 1, - }, - }, - EForkTime: activeForkTime, // activate latest fork, - }, - Ctx: ctx, - Bootstrapped: bootstrapped, - } - }, - stateF: func(ctrl *gomock.Controller) state.Chain { - mockState := state.NewMockChain(ctrl) - mockState.EXPECT().GetTimestamp().Return(now).Times(2) // chain time is after EFork 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) - primaryNetworkVdr := &state.Staker{ - EndTime: mockable.MaxTime, - } - mockState.EXPECT().GetCurrentValidator(constants.PrimaryNetworkID, verifiedTx.NodeID()).Return(primaryNetworkVdr, nil) - return mockState - }, - sTxF: func() *txs.Tx { - return &verifiedSignedTx - }, - txF: func() *txs.AddPermissionlessValidatorTx { - return &verifiedTx - }, - expectedErr: errFailedConsumedUnitsCumulation, - }, - { - name: "success post EFork", - backendF: func(ctrl *gomock.Controller) *Backend { - bootstrapped := &utils.Atomic[bool]{} - bootstrapped.Set(true) - - flowChecker := utxo.NewMockVerifier(ctrl) - flowChecker.EXPECT().VerifySpend( - gomock.Any(), - gomock.Any(), - gomock.Any(), - gomock.Any(), - gomock.Any(), - gomock.Any(), - ).Return(nil) - - return &Backend{ - FlowChecker: flowChecker, - Config: &config.Config{ - FeeConfig: config.FeeConfig{ - DefaultUnitFees: fees.Dimensions{ - 10, - }, - DefaultBlockMaxConsumedUnits: fees.Dimensions{ - uint64(len(signedBytes)), - }, - }, - EForkTime: activeForkTime, // activate latest fork, - }, - Ctx: ctx, - Bootstrapped: bootstrapped, - } - }, - stateF: func(ctrl *gomock.Controller) state.Chain { - mockState := state.NewMockChain(ctrl) - mockState.EXPECT().GetTimestamp().Return(now).Times(2) // chain time is after EFork 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) - primaryNetworkVdr := &state.Staker{ - EndTime: mockable.MaxTime, - } - mockState.EXPECT().GetCurrentValidator(constants.PrimaryNetworkID, verifiedTx.NodeID()).Return(primaryNetworkVdr, nil) - return mockState - }, - sTxF: func() *txs.Tx { - return &verifiedSignedTx - }, - txF: func() *txs.AddPermissionlessValidatorTx { - return &verifiedTx - }, - expectedErr: nil, - }, } for _, tt := range tests { From 2ffcd08e4ecb5be722928ea3ecea1871b5a7ed76 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Tue, 9 Jan 2024 14:18:23 +0100 Subject: [PATCH 017/190] some more UTs --- .../txs/executor/fee_calculator_test.go | 1733 ++++++++++++++++- 1 file changed, 1699 insertions(+), 34 deletions(-) diff --git a/vms/platformvm/txs/executor/fee_calculator_test.go b/vms/platformvm/txs/executor/fee_calculator_test.go index 5839f3f2b3a0..fa4fc5977be6 100644 --- a/vms/platformvm/txs/executor/fee_calculator_test.go +++ b/vms/platformvm/txs/executor/fee_calculator_test.go @@ -10,13 +10,16 @@ import ( "github.com/stretchr/testify/require" "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/snow" "github.com/ava-labs/avalanchego/snow/snowtest" + "github.com/ava-labs/avalanchego/utils/crypto/bls" "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" "github.com/ava-labs/avalanchego/utils/units" "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/platformvm/config" "github.com/ava-labs/avalanchego/vms/platformvm/fees" "github.com/ava-labs/avalanchego/vms/platformvm/reward" + "github.com/ava-labs/avalanchego/vms/platformvm/signer" "github.com/ava-labs/avalanchego/vms/platformvm/stakeable" "github.com/ava-labs/avalanchego/vms/platformvm/txs" "github.com/ava-labs/avalanchego/vms/secp256k1fx" @@ -47,40 +50,7 @@ func TestAddValidatorTxFees(t *testing.T) { // create a well formed AddValidatorTx signers := [][]*secp256k1.PrivateKey{preFundedKeys} validatorWeight := uint64(2024) - inputs := []*avax.TransferableInput{{ - UTXOID: avax.UTXOID{ - TxID: ids.ID{'t', 'x', 'I', 'D'}, - OutputIndex: 2, - }, - Asset: avax.Asset{ID: defaultCtx.AVAXAssetID}, - In: &secp256k1fx.TransferInput{ - Amt: uint64(5678), - Input: secp256k1fx.Input{SigIndices: []uint32{0}}, - }, - }} - outputs := []*avax.TransferableOutput{{ - Asset: avax.Asset{ID: defaultCtx.AVAXAssetID}, - Out: &secp256k1fx.TransferOutput{ - Amt: uint64(1234), - OutputOwners: secp256k1fx.OutputOwners{ - Threshold: 1, - Addrs: []ids.ShortID{preFundedKeys[0].PublicKey().Address()}, - }, - }, - }} - stakes := []*avax.TransferableOutput{{ - Asset: avax.Asset{ID: defaultCtx.AVAXAssetID}, - Out: &stakeable.LockOut{ - Locktime: uint64(time.Now().Add(time.Second).Unix()), - TransferableOut: &secp256k1fx.TransferOutput{ - Amt: validatorWeight, - OutputOwners: secp256k1fx.OutputOwners{ - Threshold: 1, - Addrs: []ids.ShortID{preFundedKeys[0].PublicKey().Address()}, - }, - }, - }, - }} + inputs, outputs, stakes, _ := txsCreationHelpers(defaultCtx, validatorWeight) uTx := &txs.AddValidatorTx{ BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ NetworkID: defaultCtx.NetworkID, @@ -196,3 +166,1698 @@ func TestAddValidatorTxFees(t *testing.T) { }) } } + +func TestAddSubnetValidatorTxFees(t *testing.T) { + // For simplicity, we define a single AddSubnetValidatorTx + // and we change config parameters in the different test cases + r := require.New(t) + + defaultCtx := snowtest.Context(t, snowtest.PChainID) + defaultFeeCfg := config.FeeConfig{ + DefaultUnitFees: fees.Dimensions{ + 1 * units.MicroAvax, + 2 * units.MicroAvax, + 3 * units.MicroAvax, + 4 * units.MicroAvax, + }, + DefaultBlockMaxConsumedUnits: fees.Dimensions{ + 1000, + 1500, + 1000, + 1000, + }, + AddPrimaryNetworkValidatorFee: 0, + } + + // create a well formed AddValidatorTx + signers := [][]*secp256k1.PrivateKey{preFundedKeys} + validatorWeight := uint64(2024) + subnetID := ids.GenerateTestID() + inputs, outputs, _, subnetAuth := txsCreationHelpers(defaultCtx, validatorWeight) + uTx := &txs.AddSubnetValidatorTx{ + BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ + NetworkID: defaultCtx.NetworkID, + BlockchainID: defaultCtx.ChainID, + Ins: inputs, + Outs: outputs, + Memo: []byte{1, 2, 3, 4, 5, 6, 7, 8}, + }}, + SubnetValidator: txs.SubnetValidator{ + Validator: txs.Validator{ + NodeID: defaultCtx.NodeID, + Start: uint64(time.Now().Truncate(time.Second).Unix()), + End: uint64(time.Now().Truncate(time.Second).Add(time.Hour).Unix()), + Wght: validatorWeight, + }, + Subnet: subnetID, + }, + SubnetAuth: subnetAuth, + } + stx, err := txs.NewSigned(uTx, txs.Codec, signers) + r.NoError(err) + + type test struct { + description string + cfgAndChainTimeF func() (*config.Config, time.Time) + expectedError error + checksF func(*testing.T, *FeeCalculator) + } + + tests := []test{ + { + description: "pre E fork", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(-1 * time.Second) + + cfg := &config.Config{ + FeeConfig: defaultFeeCfg, + DurangoTime: time.Time{}, // durango already active + EForkTime: eForkTime, + } + + return cfg, chainTime + }, + expectedError: nil, + checksF: func(t *testing.T, fc *FeeCalculator) { + require.Equal(t, fc.Config.AddPrimaryNetworkValidatorFee, fc.Fee) + }, + }, + { + description: "post E fork, success", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(time.Second) + + cfg := &config.Config{ + FeeConfig: defaultFeeCfg, + DurangoTime: time.Time{}, // durango already active + EForkTime: eForkTime, + } + + return cfg, chainTime + }, + expectedError: nil, + checksF: func(t *testing.T, fc *FeeCalculator) { + require.Equal(t, 3355*units.MicroAvax, fc.Fee) + require.Equal(t, + fees.Dimensions{ + uint64(len(stx.Bytes())), // this is a simple rule, can assert easily + 1090, // this is more complex rule, gotta check against hard-coded value + 172, // this is more complex rule, gotta check against hard-coded value + 0, + }, + fc.feeManager.GetCumulatedUnits(), + ) + }, + }, + { + description: "post E fork, utxos read cap breached", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(time.Second) + + cfg := &config.Config{ + FeeConfig: defaultFeeCfg, + DurangoTime: time.Time{}, // durango already active + EForkTime: eForkTime, + } + cfg.DefaultBlockMaxConsumedUnits[1] = 1090 - 1 + + return cfg, chainTime + }, + expectedError: errFailedConsumedUnitsCumulation, + checksF: func(t *testing.T, fc *FeeCalculator) {}, + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + cfg, chainTime := tt.cfgAndChainTimeF() + + fc := &FeeCalculator{ + feeManager: fees.NewManager(cfg.DefaultUnitFees), + Config: cfg, + ChainTime: chainTime, + Tx: stx, + } + err := uTx.Visit(fc) + r.ErrorIs(err, tt.expectedError) + tt.checksF(t, fc) + }) + } +} + +func TestAddDelegatorTxFees(t *testing.T) { + // For simplicity, we define a single AddDelegatorTx + // and we change config parameters in the different test cases + r := require.New(t) + + defaultCtx := snowtest.Context(t, snowtest.PChainID) + defaultFeeCfg := config.FeeConfig{ + DefaultUnitFees: fees.Dimensions{ + 1 * units.MicroAvax, + 2 * units.MicroAvax, + 3 * units.MicroAvax, + 4 * units.MicroAvax, + }, + DefaultBlockMaxConsumedUnits: fees.Dimensions{ + 1000, + 1500, + 1000, + 1000, + }, + AddPrimaryNetworkValidatorFee: 0, + } + + // create a well formed AddValidatorTx + signers := [][]*secp256k1.PrivateKey{preFundedKeys} + validatorWeight := uint64(2024) + inputs, outputs, stakes, _ := txsCreationHelpers(defaultCtx, validatorWeight) + uTx := &txs.AddDelegatorTx{ + BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ + NetworkID: defaultCtx.NetworkID, + BlockchainID: defaultCtx.ChainID, + Outs: outputs, + Ins: inputs, + Memo: []byte{1, 2, 3, 4, 5, 6, 7, 8}, + }}, + Validator: txs.Validator{ + NodeID: defaultCtx.NodeID, + Start: uint64(time.Now().Truncate(time.Second).Unix()), + End: uint64(time.Now().Truncate(time.Second).Add(time.Hour).Unix()), + Wght: validatorWeight, + }, + StakeOuts: stakes, + DelegationRewardsOwner: &secp256k1fx.OutputOwners{ + Locktime: 0, + Threshold: 1, + Addrs: []ids.ShortID{preFundedKeys[0].PublicKey().Address()}, + }, + } + stx, err := txs.NewSigned(uTx, txs.Codec, signers) + r.NoError(err) + + type test struct { + description string + cfgAndChainTimeF func() (*config.Config, time.Time) + expectedError error + checksF func(*testing.T, *FeeCalculator) + } + + tests := []test{ + { + description: "pre E fork", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(-1 * time.Second) + + cfg := &config.Config{ + FeeConfig: defaultFeeCfg, + DurangoTime: time.Time{}, // durango already active + EForkTime: eForkTime, + } + + return cfg, chainTime + }, + expectedError: nil, + checksF: func(t *testing.T, fc *FeeCalculator) { + require.Equal(t, fc.Config.AddPrimaryNetworkValidatorFee, fc.Fee) + }, + }, + { + description: "post E fork, success", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(time.Second) + + cfg := &config.Config{ + FeeConfig: defaultFeeCfg, + DurangoTime: time.Time{}, // durango already active + EForkTime: eForkTime, + } + + return cfg, chainTime + }, + expectedError: nil, + checksF: func(t *testing.T, fc *FeeCalculator) { + require.Equal(t, 3725*units.MicroAvax, fc.Fee) + require.Equal(t, + fees.Dimensions{ + uint64(len(stx.Bytes())), // this is a simple rule, can assert easily + 1090, // this is more complex rule, gotta check against hard-coded value + 266, // this is more complex rule, gotta check against hard-coded value + 0, + }, + fc.feeManager.GetCumulatedUnits(), + ) + }, + }, + { + description: "post E fork, utxos read cap breached", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(time.Second) + + cfg := &config.Config{ + FeeConfig: defaultFeeCfg, + DurangoTime: time.Time{}, // durango already active + EForkTime: eForkTime, + } + cfg.DefaultBlockMaxConsumedUnits[1] = 1090 - 1 + + return cfg, chainTime + }, + expectedError: errFailedConsumedUnitsCumulation, + checksF: func(t *testing.T, fc *FeeCalculator) {}, + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + cfg, chainTime := tt.cfgAndChainTimeF() + + fc := &FeeCalculator{ + feeManager: fees.NewManager(cfg.DefaultUnitFees), + Config: cfg, + ChainTime: chainTime, + Tx: stx, + } + err := uTx.Visit(fc) + r.ErrorIs(err, tt.expectedError) + tt.checksF(t, fc) + }) + } +} + +func TestCreateChainTxFees(t *testing.T) { + // For simplicity, we define a single CreateChainTx + // and we change config parameters in the different test cases + r := require.New(t) + + defaultCtx := snowtest.Context(t, snowtest.PChainID) + defaultFeeCfg := config.FeeConfig{ + DefaultUnitFees: fees.Dimensions{ + 1 * units.MicroAvax, + 2 * units.MicroAvax, + 3 * units.MicroAvax, + 4 * units.MicroAvax, + }, + DefaultBlockMaxConsumedUnits: fees.Dimensions{ + 1000, + 1500, + 1000, + 1000, + }, + AddPrimaryNetworkValidatorFee: 0, + } + + // create a well formed AddValidatorTx + signers := [][]*secp256k1.PrivateKey{preFundedKeys} + inputs, outputs, _, subnetAuth := txsCreationHelpers(defaultCtx, 0) + uTx := &txs.CreateChainTx{ + BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ + NetworkID: defaultCtx.NetworkID, + BlockchainID: defaultCtx.ChainID, + Ins: inputs, + Outs: outputs, + }}, + SubnetID: ids.GenerateTestID(), + ChainName: "testingStuff", + VMID: ids.GenerateTestID(), + FxIDs: []ids.ID{ids.GenerateTestID()}, + GenesisData: []byte{0xff}, + SubnetAuth: subnetAuth, + } + stx, err := txs.NewSigned(uTx, txs.Codec, signers) + r.NoError(err) + + type test struct { + description string + cfgAndChainTimeF func() (*config.Config, time.Time) + expectedError error + checksF func(*testing.T, *FeeCalculator) + } + + tests := []test{ + { + description: "pre E fork", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(-1 * time.Second) + + cfg := &config.Config{ + FeeConfig: defaultFeeCfg, + DurangoTime: time.Time{}, // durango already active + EForkTime: eForkTime, + } + + return cfg, chainTime + }, + expectedError: nil, + checksF: func(t *testing.T, fc *FeeCalculator) { + require.Equal(t, fc.Config.AddPrimaryNetworkValidatorFee, fc.Fee) + }, + }, + { + description: "post E fork, success", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(time.Second) + + cfg := &config.Config{ + FeeConfig: defaultFeeCfg, + DurangoTime: time.Time{}, // durango already active + EForkTime: eForkTime, + } + + return cfg, chainTime + }, + expectedError: nil, + checksF: func(t *testing.T, fc *FeeCalculator) { + require.Equal(t, 3390*units.MicroAvax, fc.Fee) + require.Equal(t, + fees.Dimensions{ + uint64(len(stx.Bytes())), // this is a simple rule, can assert easily + 1090, // this is more complex rule, gotta check against hard-coded value + 172, // this is more complex rule, gotta check against hard-coded value + 0, + }, + fc.feeManager.GetCumulatedUnits(), + ) + }, + }, + { + description: "post E fork, utxos read cap breached", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(time.Second) + + cfg := &config.Config{ + FeeConfig: defaultFeeCfg, + DurangoTime: time.Time{}, // durango already active + EForkTime: eForkTime, + } + cfg.DefaultBlockMaxConsumedUnits[1] = 1090 - 1 + + return cfg, chainTime + }, + expectedError: errFailedConsumedUnitsCumulation, + checksF: func(t *testing.T, fc *FeeCalculator) {}, + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + cfg, chainTime := tt.cfgAndChainTimeF() + + fc := &FeeCalculator{ + feeManager: fees.NewManager(cfg.DefaultUnitFees), + Config: cfg, + ChainTime: chainTime, + Tx: stx, + } + err := uTx.Visit(fc) + r.ErrorIs(err, tt.expectedError) + tt.checksF(t, fc) + }) + } +} + +func TestCreateSubnetTxFees(t *testing.T) { + // For simplicity, we define a single CreateSubnetTx + // and we change config parameters in the different test cases + r := require.New(t) + + defaultCtx := snowtest.Context(t, snowtest.PChainID) + defaultFeeCfg := config.FeeConfig{ + DefaultUnitFees: fees.Dimensions{ + 1 * units.MicroAvax, + 2 * units.MicroAvax, + 3 * units.MicroAvax, + 4 * units.MicroAvax, + }, + DefaultBlockMaxConsumedUnits: fees.Dimensions{ + 1000, + 1500, + 1000, + 1000, + }, + AddPrimaryNetworkValidatorFee: 0, + } + + // create a well formed AddValidatorTx + signers := [][]*secp256k1.PrivateKey{preFundedKeys} + inputs, outputs, _, _ := txsCreationHelpers(defaultCtx, 0) + uTx := &txs.CreateSubnetTx{ + BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ + NetworkID: defaultCtx.NetworkID, + BlockchainID: defaultCtx.ChainID, + Ins: inputs, + Outs: outputs, + }}, + Owner: &secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{preFundedKeys[0].PublicKey().Address()}, + }, + } + stx, err := txs.NewSigned(uTx, txs.Codec, signers) + r.NoError(err) + + type test struct { + description string + cfgAndChainTimeF func() (*config.Config, time.Time) + expectedError error + checksF func(*testing.T, *FeeCalculator) + } + + tests := []test{ + { + description: "pre E fork", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(-1 * time.Second) + + cfg := &config.Config{ + FeeConfig: defaultFeeCfg, + DurangoTime: time.Time{}, // durango already active + EForkTime: eForkTime, + } + + return cfg, chainTime + }, + expectedError: nil, + checksF: func(t *testing.T, fc *FeeCalculator) { + require.Equal(t, fc.Config.AddPrimaryNetworkValidatorFee, fc.Fee) + }, + }, + { + description: "post E fork, success", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(time.Second) + + cfg := &config.Config{ + FeeConfig: defaultFeeCfg, + DurangoTime: time.Time{}, // durango already active + EForkTime: eForkTime, + } + + return cfg, chainTime + }, + expectedError: nil, + checksF: func(t *testing.T, fc *FeeCalculator) { + require.Equal(t, 3295*units.MicroAvax, fc.Fee) + require.Equal(t, + fees.Dimensions{ + uint64(len(stx.Bytes())), // this is a simple rule, can assert easily + 1090, // this is more complex rule, gotta check against hard-coded value + 172, // this is more complex rule, gotta check against hard-coded value + 0, + }, + fc.feeManager.GetCumulatedUnits(), + ) + }, + }, + { + description: "post E fork, utxos read cap breached", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(time.Second) + + cfg := &config.Config{ + FeeConfig: defaultFeeCfg, + DurangoTime: time.Time{}, // durango already active + EForkTime: eForkTime, + } + cfg.DefaultBlockMaxConsumedUnits[1] = 1090 - 1 + + return cfg, chainTime + }, + expectedError: errFailedConsumedUnitsCumulation, + checksF: func(t *testing.T, fc *FeeCalculator) {}, + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + cfg, chainTime := tt.cfgAndChainTimeF() + + fc := &FeeCalculator{ + feeManager: fees.NewManager(cfg.DefaultUnitFees), + Config: cfg, + ChainTime: chainTime, + Tx: stx, + } + err := uTx.Visit(fc) + r.ErrorIs(err, tt.expectedError) + tt.checksF(t, fc) + }) + } +} + +func TestRemoveSubnetValidatorTxFees(t *testing.T) { + // For simplicity, we define a single RemoveSubnetValidatorTx + // and we change config parameters in the different test cases + r := require.New(t) + + defaultCtx := snowtest.Context(t, snowtest.PChainID) + defaultFeeCfg := config.FeeConfig{ + DefaultUnitFees: fees.Dimensions{ + 1 * units.MicroAvax, + 2 * units.MicroAvax, + 3 * units.MicroAvax, + 4 * units.MicroAvax, + }, + DefaultBlockMaxConsumedUnits: fees.Dimensions{ + 1000, + 1500, + 1000, + 1000, + }, + AddPrimaryNetworkValidatorFee: 0, + } + + // create a well formed AddValidatorTx + signers := [][]*secp256k1.PrivateKey{preFundedKeys} + inputs, outputs, _, auth := txsCreationHelpers(defaultCtx, 0) + uTx := &txs.RemoveSubnetValidatorTx{ + BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ + NetworkID: defaultCtx.NetworkID, + BlockchainID: defaultCtx.ChainID, + Ins: inputs, + Outs: outputs, + }}, + NodeID: ids.GenerateTestNodeID(), + Subnet: ids.GenerateTestID(), + SubnetAuth: auth, + } + stx, err := txs.NewSigned(uTx, txs.Codec, signers) + r.NoError(err) + + type test struct { + description string + cfgAndChainTimeF func() (*config.Config, time.Time) + expectedError error + checksF func(*testing.T, *FeeCalculator) + } + + tests := []test{ + { + description: "pre E fork", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(-1 * time.Second) + + cfg := &config.Config{ + FeeConfig: defaultFeeCfg, + DurangoTime: time.Time{}, // durango already active + EForkTime: eForkTime, + } + + return cfg, chainTime + }, + expectedError: nil, + checksF: func(t *testing.T, fc *FeeCalculator) { + require.Equal(t, fc.Config.AddPrimaryNetworkValidatorFee, fc.Fee) + }, + }, + { + description: "post E fork, success", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(time.Second) + + cfg := &config.Config{ + FeeConfig: defaultFeeCfg, + DurangoTime: time.Time{}, // durango already active + EForkTime: eForkTime, + } + + return cfg, chainTime + }, + expectedError: nil, + checksF: func(t *testing.T, fc *FeeCalculator) { + require.Equal(t, 3323*units.MicroAvax, fc.Fee) + require.Equal(t, + fees.Dimensions{ + uint64(len(stx.Bytes())), // this is a simple rule, can assert easily + 1090, // this is more complex rule, gotta check against hard-coded value + 172, // this is more complex rule, gotta check against hard-coded value + 0, + }, + fc.feeManager.GetCumulatedUnits(), + ) + }, + }, + { + description: "post E fork, utxos read cap breached", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(time.Second) + + cfg := &config.Config{ + FeeConfig: defaultFeeCfg, + DurangoTime: time.Time{}, // durango already active + EForkTime: eForkTime, + } + cfg.DefaultBlockMaxConsumedUnits[1] = 1090 - 1 + + return cfg, chainTime + }, + expectedError: errFailedConsumedUnitsCumulation, + checksF: func(t *testing.T, fc *FeeCalculator) {}, + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + cfg, chainTime := tt.cfgAndChainTimeF() + + fc := &FeeCalculator{ + feeManager: fees.NewManager(cfg.DefaultUnitFees), + Config: cfg, + ChainTime: chainTime, + Tx: stx, + } + err := uTx.Visit(fc) + r.ErrorIs(err, tt.expectedError) + tt.checksF(t, fc) + }) + } +} + +func TestTransformSubnetTxFees(t *testing.T) { + // For simplicity, we define a single TransformSubnetTx + // and we change config parameters in the different test cases + r := require.New(t) + + defaultCtx := snowtest.Context(t, snowtest.PChainID) + defaultFeeCfg := config.FeeConfig{ + DefaultUnitFees: fees.Dimensions{ + 1 * units.MicroAvax, + 2 * units.MicroAvax, + 3 * units.MicroAvax, + 4 * units.MicroAvax, + }, + DefaultBlockMaxConsumedUnits: fees.Dimensions{ + 1000, + 1500, + 1000, + 1000, + }, + AddPrimaryNetworkValidatorFee: 0, + } + + // create a well formed AddValidatorTx + signers := [][]*secp256k1.PrivateKey{preFundedKeys} + inputs, outputs, _, auth := txsCreationHelpers(defaultCtx, 0) + uTx := &txs.TransformSubnetTx{ + BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ + NetworkID: defaultCtx.NetworkID, + BlockchainID: defaultCtx.ChainID, + Ins: inputs, + Outs: outputs, + }}, + Subnet: ids.GenerateTestID(), + AssetID: ids.GenerateTestID(), + InitialSupply: 0x1000000000000000, + MaximumSupply: 0x1000000000000000, + MinConsumptionRate: 0, + MaxConsumptionRate: 0, + MinValidatorStake: 1, + MaxValidatorStake: 0x1000000000000000, + MinStakeDuration: 1, + MaxStakeDuration: 1, + MinDelegationFee: 0, + MinDelegatorStake: 0xffffffffffffffff, + MaxValidatorWeightFactor: 255, + UptimeRequirement: 0, + SubnetAuth: auth, + } + stx, err := txs.NewSigned(uTx, txs.Codec, signers) + r.NoError(err) + + type test struct { + description string + cfgAndChainTimeF func() (*config.Config, time.Time) + expectedError error + checksF func(*testing.T, *FeeCalculator) + } + + tests := []test{ + { + description: "pre E fork", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(-1 * time.Second) + + cfg := &config.Config{ + FeeConfig: defaultFeeCfg, + DurangoTime: time.Time{}, // durango already active + EForkTime: eForkTime, + } + + return cfg, chainTime + }, + expectedError: nil, + checksF: func(t *testing.T, fc *FeeCalculator) { + require.Equal(t, fc.Config.AddPrimaryNetworkValidatorFee, fc.Fee) + }, + }, + { + description: "post E fork, success", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(time.Second) + + cfg := &config.Config{ + FeeConfig: defaultFeeCfg, + DurangoTime: time.Time{}, // durango already active + EForkTime: eForkTime, + } + + return cfg, chainTime + }, + expectedError: nil, + checksF: func(t *testing.T, fc *FeeCalculator) { + require.Equal(t, 3408*units.MicroAvax, fc.Fee) + require.Equal(t, + fees.Dimensions{ + uint64(len(stx.Bytes())), // this is a simple rule, can assert easily + 1090, // this is more complex rule, gotta check against hard-coded value + 172, // this is more complex rule, gotta check against hard-coded value + 0, + }, + fc.feeManager.GetCumulatedUnits(), + ) + }, + }, + { + description: "post E fork, utxos read cap breached", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(time.Second) + + cfg := &config.Config{ + FeeConfig: defaultFeeCfg, + DurangoTime: time.Time{}, // durango already active + EForkTime: eForkTime, + } + cfg.DefaultBlockMaxConsumedUnits[1] = 1090 - 1 + + return cfg, chainTime + }, + expectedError: errFailedConsumedUnitsCumulation, + checksF: func(t *testing.T, fc *FeeCalculator) {}, + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + cfg, chainTime := tt.cfgAndChainTimeF() + + fc := &FeeCalculator{ + feeManager: fees.NewManager(cfg.DefaultUnitFees), + Config: cfg, + ChainTime: chainTime, + Tx: stx, + } + err := uTx.Visit(fc) + r.ErrorIs(err, tt.expectedError) + tt.checksF(t, fc) + }) + } +} + +func TestTransferSubnetOwnershipTxFees(t *testing.T) { + // For simplicity, we define a single TransferSubnetOwnershipTx + // and we change config parameters in the different test cases + r := require.New(t) + + defaultCtx := snowtest.Context(t, snowtest.PChainID) + defaultFeeCfg := config.FeeConfig{ + DefaultUnitFees: fees.Dimensions{ + 1 * units.MicroAvax, + 2 * units.MicroAvax, + 3 * units.MicroAvax, + 4 * units.MicroAvax, + }, + DefaultBlockMaxConsumedUnits: fees.Dimensions{ + 1000, + 1500, + 1000, + 1000, + }, + AddPrimaryNetworkValidatorFee: 0, + } + + // create a well formed AddValidatorTx + signers := [][]*secp256k1.PrivateKey{preFundedKeys} + inputs, outputs, _, _ := txsCreationHelpers(defaultCtx, 0) + uTx := &txs.TransferSubnetOwnershipTx{ + BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ + NetworkID: defaultCtx.NetworkID, + BlockchainID: defaultCtx.ChainID, + Ins: inputs, + Outs: outputs, + }}, + Subnet: ids.GenerateTestID(), + SubnetAuth: &secp256k1fx.Input{ + SigIndices: []uint32{3}, + }, + Owner: &secp256k1fx.OutputOwners{ + Locktime: 0, + Threshold: 1, + Addrs: []ids.ShortID{ + ids.GenerateTestShortID(), + }, + }, + } + stx, err := txs.NewSigned(uTx, txs.Codec, signers) + r.NoError(err) + + type test struct { + description string + cfgAndChainTimeF func() (*config.Config, time.Time) + expectedError error + checksF func(*testing.T, *FeeCalculator) + } + + tests := []test{ + { + description: "pre E fork", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(-1 * time.Second) + + cfg := &config.Config{ + FeeConfig: defaultFeeCfg, + DurangoTime: time.Time{}, // durango already active + EForkTime: eForkTime, + } + + return cfg, chainTime + }, + expectedError: nil, + checksF: func(t *testing.T, fc *FeeCalculator) { + require.Equal(t, fc.Config.AddPrimaryNetworkValidatorFee, fc.Fee) + }, + }, + { + description: "post E fork, success", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(time.Second) + + cfg := &config.Config{ + FeeConfig: defaultFeeCfg, + DurangoTime: time.Time{}, // durango already active + EForkTime: eForkTime, + } + + return cfg, chainTime + }, + expectedError: nil, + checksF: func(t *testing.T, fc *FeeCalculator) { + require.Equal(t, 3339*units.MicroAvax, fc.Fee) + require.Equal(t, + fees.Dimensions{ + uint64(len(stx.Bytes())), // this is a simple rule, can assert easily + 1090, // this is more complex rule, gotta check against hard-coded value + 172, // this is more complex rule, gotta check against hard-coded value + 0, + }, + fc.feeManager.GetCumulatedUnits(), + ) + }, + }, + { + description: "post E fork, utxos read cap breached", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(time.Second) + + cfg := &config.Config{ + FeeConfig: defaultFeeCfg, + DurangoTime: time.Time{}, // durango already active + EForkTime: eForkTime, + } + cfg.DefaultBlockMaxConsumedUnits[1] = 1090 - 1 + + return cfg, chainTime + }, + expectedError: errFailedConsumedUnitsCumulation, + checksF: func(t *testing.T, fc *FeeCalculator) {}, + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + cfg, chainTime := tt.cfgAndChainTimeF() + + fc := &FeeCalculator{ + feeManager: fees.NewManager(cfg.DefaultUnitFees), + Config: cfg, + ChainTime: chainTime, + Tx: stx, + } + err := uTx.Visit(fc) + r.ErrorIs(err, tt.expectedError) + tt.checksF(t, fc) + }) + } +} + +func TestAddPermissionlessValidatorTxFees(t *testing.T) { + // For simplicity, we define a single AddPermissionlessValidatorTx + // and we change config parameters in the different test cases + r := require.New(t) + + defaultCtx := snowtest.Context(t, snowtest.PChainID) + defaultFeeCfg := config.FeeConfig{ + DefaultUnitFees: fees.Dimensions{ + 1 * units.MicroAvax, + 2 * units.MicroAvax, + 3 * units.MicroAvax, + 4 * units.MicroAvax, + }, + DefaultBlockMaxConsumedUnits: fees.Dimensions{ + 1000, + 1500, + 1000, + 1000, + }, + AddPrimaryNetworkValidatorFee: 0, + } + + // create a well formed AddValidatorTx + signers := [][]*secp256k1.PrivateKey{preFundedKeys} + inputs, outputs, stakes, _ := txsCreationHelpers(defaultCtx, 0) + sk, err := bls.NewSecretKey() + r.NoError(err) + uTx := &txs.AddPermissionlessValidatorTx{ + BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ + NetworkID: defaultCtx.NetworkID, + BlockchainID: defaultCtx.ChainID, + Ins: inputs, + Outs: outputs, + }}, + Subnet: ids.GenerateTestID(), + Signer: signer.NewProofOfPossession(sk), + StakeOuts: stakes, + ValidatorRewardsOwner: &secp256k1fx.OutputOwners{ + Locktime: 0, + Threshold: 1, + Addrs: []ids.ShortID{ + ids.GenerateTestShortID(), + }, + }, + DelegatorRewardsOwner: &secp256k1fx.OutputOwners{ + Locktime: 0, + Threshold: 1, + Addrs: []ids.ShortID{ + ids.GenerateTestShortID(), + }, + }, + DelegationShares: reward.PercentDenominator, + } + stx, err := txs.NewSigned(uTx, txs.Codec, signers) + r.NoError(err) + + type test struct { + description string + cfgAndChainTimeF func() (*config.Config, time.Time) + expectedError error + checksF func(*testing.T, *FeeCalculator) + } + + tests := []test{ + { + description: "pre E fork", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(-1 * time.Second) + + cfg := &config.Config{ + FeeConfig: defaultFeeCfg, + DurangoTime: time.Time{}, // durango already active + EForkTime: eForkTime, + } + + return cfg, chainTime + }, + expectedError: nil, + checksF: func(t *testing.T, fc *FeeCalculator) { + require.Equal(t, fc.Config.AddPrimaryNetworkValidatorFee, fc.Fee) + }, + }, + { + description: "post E fork, success", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(time.Second) + + cfg := &config.Config{ + FeeConfig: defaultFeeCfg, + DurangoTime: time.Time{}, // durango already active + EForkTime: eForkTime, + } + + return cfg, chainTime + }, + expectedError: nil, + checksF: func(t *testing.T, fc *FeeCalculator) { + require.Equal(t, 3941*units.MicroAvax, fc.Fee) + require.Equal(t, + fees.Dimensions{ + uint64(len(stx.Bytes())), // this is a simple rule, can assert easily + 1090, // this is more complex rule, gotta check against hard-coded value + 266, // this is more complex rule, gotta check against hard-coded value + 0, + }, + fc.feeManager.GetCumulatedUnits(), + ) + }, + }, + { + description: "post E fork, utxos read cap breached", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(time.Second) + + cfg := &config.Config{ + FeeConfig: defaultFeeCfg, + DurangoTime: time.Time{}, // durango already active + EForkTime: eForkTime, + } + cfg.DefaultBlockMaxConsumedUnits[1] = 1090 - 1 + + return cfg, chainTime + }, + expectedError: errFailedConsumedUnitsCumulation, + checksF: func(t *testing.T, fc *FeeCalculator) {}, + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + cfg, chainTime := tt.cfgAndChainTimeF() + + fc := &FeeCalculator{ + feeManager: fees.NewManager(cfg.DefaultUnitFees), + Config: cfg, + ChainTime: chainTime, + Tx: stx, + } + err := uTx.Visit(fc) + r.ErrorIs(err, tt.expectedError) + tt.checksF(t, fc) + }) + } +} + +func TestAddPermissionlessDelegatorTxFees(t *testing.T) { + // For simplicity, we define a single AddPermissionlessDelegatorTx + // and we change config parameters in the different test cases + r := require.New(t) + + defaultCtx := snowtest.Context(t, snowtest.PChainID) + defaultFeeCfg := config.FeeConfig{ + DefaultUnitFees: fees.Dimensions{ + 1 * units.MicroAvax, + 2 * units.MicroAvax, + 3 * units.MicroAvax, + 4 * units.MicroAvax, + }, + DefaultBlockMaxConsumedUnits: fees.Dimensions{ + 1000, + 1500, + 1000, + 1000, + }, + AddPrimaryNetworkValidatorFee: 0, + } + + // create a well formed AddValidatorTx + signers := [][]*secp256k1.PrivateKey{preFundedKeys} + inputs, outputs, stakes, _ := txsCreationHelpers(defaultCtx, 2*units.KiloAvax) + uTx := &txs.AddPermissionlessDelegatorTx{ + BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ + NetworkID: defaultCtx.NetworkID, + BlockchainID: defaultCtx.ChainID, + Ins: inputs, + Outs: outputs, + }}, + Validator: txs.Validator{ + NodeID: ids.GenerateTestNodeID(), + Start: 12345, + End: 12345 + 200*24*60*60, + Wght: 2 * units.KiloAvax, + }, + Subnet: ids.GenerateTestID(), + StakeOuts: stakes, + DelegationRewardsOwner: &secp256k1fx.OutputOwners{ + Locktime: 0, + Threshold: 1, + Addrs: []ids.ShortID{ + ids.GenerateTestShortID(), + }, + }, + } + stx, err := txs.NewSigned(uTx, txs.Codec, signers) + r.NoError(err) + + type test struct { + description string + cfgAndChainTimeF func() (*config.Config, time.Time) + expectedError error + checksF func(*testing.T, *FeeCalculator) + } + + tests := []test{ + { + description: "pre E fork", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(-1 * time.Second) + + cfg := &config.Config{ + FeeConfig: defaultFeeCfg, + DurangoTime: time.Time{}, // durango already active + EForkTime: eForkTime, + } + + return cfg, chainTime + }, + expectedError: nil, + checksF: func(t *testing.T, fc *FeeCalculator) { + require.Equal(t, fc.Config.AddPrimaryNetworkValidatorFee, fc.Fee) + }, + }, + { + description: "post E fork, success", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(time.Second) + + cfg := &config.Config{ + FeeConfig: defaultFeeCfg, + DurangoTime: time.Time{}, // durango already active + EForkTime: eForkTime, + } + + return cfg, chainTime + }, + expectedError: nil, + checksF: func(t *testing.T, fc *FeeCalculator) { + require.Equal(t, 3749*units.MicroAvax, fc.Fee) + require.Equal(t, + fees.Dimensions{ + uint64(len(stx.Bytes())), // this is a simple rule, can assert easily + 1090, // this is more complex rule, gotta check against hard-coded value + 266, // this is more complex rule, gotta check against hard-coded value + 0, + }, + fc.feeManager.GetCumulatedUnits(), + ) + }, + }, + { + description: "post E fork, utxos read cap breached", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(time.Second) + + cfg := &config.Config{ + FeeConfig: defaultFeeCfg, + DurangoTime: time.Time{}, // durango already active + EForkTime: eForkTime, + } + cfg.DefaultBlockMaxConsumedUnits[1] = 1090 - 1 + + return cfg, chainTime + }, + expectedError: errFailedConsumedUnitsCumulation, + checksF: func(t *testing.T, fc *FeeCalculator) {}, + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + cfg, chainTime := tt.cfgAndChainTimeF() + + fc := &FeeCalculator{ + feeManager: fees.NewManager(cfg.DefaultUnitFees), + Config: cfg, + ChainTime: chainTime, + Tx: stx, + } + err := uTx.Visit(fc) + r.ErrorIs(err, tt.expectedError) + tt.checksF(t, fc) + }) + } +} + +func TestBaseTxFees(t *testing.T) { + // For simplicity, we define a single BaseTx + // and we change config parameters in the different test cases + r := require.New(t) + + defaultCtx := snowtest.Context(t, snowtest.PChainID) + defaultFeeCfg := config.FeeConfig{ + DefaultUnitFees: fees.Dimensions{ + 1 * units.MicroAvax, + 2 * units.MicroAvax, + 3 * units.MicroAvax, + 4 * units.MicroAvax, + }, + DefaultBlockMaxConsumedUnits: fees.Dimensions{ + 1000, + 1500, + 1000, + 1000, + }, + AddPrimaryNetworkValidatorFee: 0, + } + + // create a well formed AddValidatorTx + signers := [][]*secp256k1.PrivateKey{preFundedKeys} + inputs, outputs, _, _ := txsCreationHelpers(defaultCtx, 2*units.KiloAvax) + uTx := &txs.BaseTx{BaseTx: avax.BaseTx{ + NetworkID: defaultCtx.NetworkID, + BlockchainID: defaultCtx.ChainID, + Ins: inputs, + Outs: outputs, + }} + stx, err := txs.NewSigned(uTx, txs.Codec, signers) + r.NoError(err) + + type test struct { + description string + cfgAndChainTimeF func() (*config.Config, time.Time) + expectedError error + checksF func(*testing.T, *FeeCalculator) + } + + tests := []test{ + { + description: "pre E fork", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(-1 * time.Second) + + cfg := &config.Config{ + FeeConfig: defaultFeeCfg, + DurangoTime: time.Time{}, // durango already active + EForkTime: eForkTime, + } + + return cfg, chainTime + }, + expectedError: nil, + checksF: func(t *testing.T, fc *FeeCalculator) { + require.Equal(t, fc.Config.AddPrimaryNetworkValidatorFee, fc.Fee) + }, + }, + { + description: "post E fork, success", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(time.Second) + + cfg := &config.Config{ + FeeConfig: defaultFeeCfg, + DurangoTime: time.Time{}, // durango already active + EForkTime: eForkTime, + } + + return cfg, chainTime + }, + expectedError: nil, + checksF: func(t *testing.T, fc *FeeCalculator) { + require.Equal(t, 3255*units.MicroAvax, fc.Fee) + require.Equal(t, + fees.Dimensions{ + uint64(len(stx.Bytes())), // this is a simple rule, can assert easily + 1090, // this is more complex rule, gotta check against hard-coded value + 172, // this is more complex rule, gotta check against hard-coded value + 0, + }, + fc.feeManager.GetCumulatedUnits(), + ) + }, + }, + { + description: "post E fork, utxos read cap breached", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(time.Second) + + cfg := &config.Config{ + FeeConfig: defaultFeeCfg, + DurangoTime: time.Time{}, // durango already active + EForkTime: eForkTime, + } + cfg.DefaultBlockMaxConsumedUnits[1] = 1090 - 1 + + return cfg, chainTime + }, + expectedError: errFailedConsumedUnitsCumulation, + checksF: func(t *testing.T, fc *FeeCalculator) {}, + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + cfg, chainTime := tt.cfgAndChainTimeF() + + fc := &FeeCalculator{ + feeManager: fees.NewManager(cfg.DefaultUnitFees), + Config: cfg, + ChainTime: chainTime, + Tx: stx, + } + err := uTx.Visit(fc) + r.ErrorIs(err, tt.expectedError) + tt.checksF(t, fc) + }) + } +} + +func TestImportTxFees(t *testing.T) { + // For simplicity, we define a single ImportTx + // and we change config parameters in the different test cases + r := require.New(t) + + defaultCtx := snowtest.Context(t, snowtest.PChainID) + defaultFeeCfg := config.FeeConfig{ + DefaultUnitFees: fees.Dimensions{ + 1 * units.MicroAvax, + 2 * units.MicroAvax, + 3 * units.MicroAvax, + 4 * units.MicroAvax, + }, + DefaultBlockMaxConsumedUnits: fees.Dimensions{ + 3000, + 2500, + 1000, + 1000, + }, + AddPrimaryNetworkValidatorFee: 0, + } + + // create a well formed AddValidatorTx + signers := [][]*secp256k1.PrivateKey{preFundedKeys} + inputs, outputs, _, _ := txsCreationHelpers(defaultCtx, 2*units.KiloAvax) + uTx := &txs.ImportTx{ + BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ + NetworkID: defaultCtx.NetworkID, + BlockchainID: defaultCtx.ChainID, + Ins: inputs, + Outs: outputs, + }}, + SourceChain: ids.GenerateTestID(), + ImportedInputs: []*avax.TransferableInput{{ + UTXOID: avax.UTXOID{ + TxID: ids.Empty.Prefix(1), + OutputIndex: 1, + }, + Asset: avax.Asset{ID: ids.ID{'a', 's', 's', 'e', 'r', 't'}}, + In: &secp256k1fx.TransferInput{ + Amt: 50000, + Input: secp256k1fx.Input{SigIndices: []uint32{0}}, + }, + }}, + } + stx, err := txs.NewSigned(uTx, txs.Codec, signers) + r.NoError(err) + + type test struct { + description string + cfgAndChainTimeF func() (*config.Config, time.Time) + expectedError error + checksF func(*testing.T, *FeeCalculator) + } + + tests := []test{ + { + description: "pre E fork", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(-1 * time.Second) + + cfg := &config.Config{ + FeeConfig: defaultFeeCfg, + DurangoTime: time.Time{}, // durango already active + EForkTime: eForkTime, + } + + return cfg, chainTime + }, + expectedError: nil, + checksF: func(t *testing.T, fc *FeeCalculator) { + require.Equal(t, fc.Config.AddPrimaryNetworkValidatorFee, fc.Fee) + }, + }, + { + description: "post E fork, success", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(time.Second) + + cfg := &config.Config{ + FeeConfig: defaultFeeCfg, + DurangoTime: time.Time{}, // durango already active + EForkTime: eForkTime, + } + + return cfg, chainTime + }, + expectedError: nil, + checksF: func(t *testing.T, fc *FeeCalculator) { + require.Equal(t, 5829*units.MicroAvax, fc.Fee) + require.Equal(t, + fees.Dimensions{ + uint64(len(stx.Bytes())), // this is a simple rule, can assert easily + 2180, // this is more complex rule, gotta check against hard-coded value + 262, // this is more complex rule, gotta check against hard-coded value + 0, + }, + fc.feeManager.GetCumulatedUnits(), + ) + }, + }, + { + description: "post E fork, utxos read cap breached", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(time.Second) + + cfg := &config.Config{ + FeeConfig: defaultFeeCfg, + DurangoTime: time.Time{}, // durango already active + EForkTime: eForkTime, + } + cfg.DefaultBlockMaxConsumedUnits[1] = 1090 - 1 + + return cfg, chainTime + }, + expectedError: errFailedConsumedUnitsCumulation, + checksF: func(t *testing.T, fc *FeeCalculator) {}, + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + cfg, chainTime := tt.cfgAndChainTimeF() + + fc := &FeeCalculator{ + feeManager: fees.NewManager(cfg.DefaultUnitFees), + Config: cfg, + ChainTime: chainTime, + Tx: stx, + } + err := uTx.Visit(fc) + r.ErrorIs(err, tt.expectedError) + tt.checksF(t, fc) + }) + } +} + +func TestExportTxFees(t *testing.T) { + // For simplicity, we define a single ExportTx + // and we change config parameters in the different test cases + r := require.New(t) + + defaultCtx := snowtest.Context(t, snowtest.PChainID) + defaultFeeCfg := config.FeeConfig{ + DefaultUnitFees: fees.Dimensions{ + 1 * units.MicroAvax, + 2 * units.MicroAvax, + 3 * units.MicroAvax, + 4 * units.MicroAvax, + }, + DefaultBlockMaxConsumedUnits: fees.Dimensions{ + 3000, + 2500, + 1000, + 1000, + }, + AddPrimaryNetworkValidatorFee: 0, + } + + // create a well formed AddValidatorTx + signers := [][]*secp256k1.PrivateKey{preFundedKeys} + inputs, outputs, _, _ := txsCreationHelpers(defaultCtx, 2*units.KiloAvax) + uTx := &txs.ExportTx{ + BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ + NetworkID: defaultCtx.NetworkID, + BlockchainID: defaultCtx.ChainID, + Ins: inputs, + Outs: outputs, + }}, + DestinationChain: ids.GenerateTestID(), + ExportedOutputs: outputs, + } + stx, err := txs.NewSigned(uTx, txs.Codec, signers) + r.NoError(err) + + type test struct { + description string + cfgAndChainTimeF func() (*config.Config, time.Time) + expectedError error + checksF func(*testing.T, *FeeCalculator) + } + + tests := []test{ + { + description: "pre E fork", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(-1 * time.Second) + + cfg := &config.Config{ + FeeConfig: defaultFeeCfg, + DurangoTime: time.Time{}, // durango already active + EForkTime: eForkTime, + } + + return cfg, chainTime + }, + expectedError: nil, + checksF: func(t *testing.T, fc *FeeCalculator) { + require.Equal(t, fc.Config.AddPrimaryNetworkValidatorFee, fc.Fee) + }, + }, + { + description: "post E fork, success", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(time.Second) + + cfg := &config.Config{ + FeeConfig: defaultFeeCfg, + DurangoTime: time.Time{}, // durango already active + EForkTime: eForkTime, + } + + return cfg, chainTime + }, + expectedError: nil, + checksF: func(t *testing.T, fc *FeeCalculator) { + require.Equal(t, 3617*units.MicroAvax, fc.Fee) + require.Equal(t, + fees.Dimensions{ + uint64(len(stx.Bytes())), // this is a simple rule, can assert easily + 1090, // this is more complex rule, gotta check against hard-coded value + 254, // this is more complex rule, gotta check against hard-coded value + 0, + }, + fc.feeManager.GetCumulatedUnits(), + ) + }, + }, + { + description: "post E fork, utxos read cap breached", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(time.Second) + + cfg := &config.Config{ + FeeConfig: defaultFeeCfg, + DurangoTime: time.Time{}, // durango already active + EForkTime: eForkTime, + } + cfg.DefaultBlockMaxConsumedUnits[1] = 1090 - 1 + + return cfg, chainTime + }, + expectedError: errFailedConsumedUnitsCumulation, + checksF: func(t *testing.T, fc *FeeCalculator) {}, + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + cfg, chainTime := tt.cfgAndChainTimeF() + + fc := &FeeCalculator{ + feeManager: fees.NewManager(cfg.DefaultUnitFees), + Config: cfg, + ChainTime: chainTime, + Tx: stx, + } + err := uTx.Visit(fc) + r.ErrorIs(err, tt.expectedError) + tt.checksF(t, fc) + }) + } +} + +func txsCreationHelpers(defaultCtx *snow.Context, stakeWeight uint64) ( + inputs []*avax.TransferableInput, + outputs []*avax.TransferableOutput, + stakes []*avax.TransferableOutput, + auth *secp256k1fx.Input, +) { + inputs = []*avax.TransferableInput{{ + UTXOID: avax.UTXOID{ + TxID: ids.ID{'t', 'x', 'I', 'D'}, + OutputIndex: 2, + }, + Asset: avax.Asset{ID: defaultCtx.AVAXAssetID}, + In: &secp256k1fx.TransferInput{ + Amt: uint64(5678), + Input: secp256k1fx.Input{SigIndices: []uint32{0}}, + }, + }} + outputs = []*avax.TransferableOutput{{ + Asset: avax.Asset{ID: defaultCtx.AVAXAssetID}, + Out: &secp256k1fx.TransferOutput{ + Amt: uint64(1234), + OutputOwners: secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{preFundedKeys[0].PublicKey().Address()}, + }, + }, + }} + stakes = []*avax.TransferableOutput{{ + Asset: avax.Asset{ID: defaultCtx.AVAXAssetID}, + Out: &stakeable.LockOut{ + Locktime: uint64(time.Now().Add(time.Second).Unix()), + TransferableOut: &secp256k1fx.TransferOutput{ + Amt: stakeWeight, + OutputOwners: secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{preFundedKeys[0].PublicKey().Address()}, + }, + }, + }, + }} + auth = &secp256k1fx.Input{ + SigIndices: []uint32{0, 1}, + } + return inputs, outputs, stakes, auth +} From cceccfdcdebaf1cb118f430646d839d9df6cad2c Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Tue, 9 Jan 2024 16:55:50 +0100 Subject: [PATCH 018/190] UTs cleanup --- .../txs/executor/fee_calculator_test.go | 727 +++++------------- 1 file changed, 195 insertions(+), 532 deletions(-) diff --git a/vms/platformvm/txs/executor/fee_calculator_test.go b/vms/platformvm/txs/executor/fee_calculator_test.go index fa4fc5977be6..773916ac38e4 100644 --- a/vms/platformvm/txs/executor/fee_calculator_test.go +++ b/vms/platformvm/txs/executor/fee_calculator_test.go @@ -25,13 +25,8 @@ import ( "github.com/ava-labs/avalanchego/vms/secp256k1fx" ) -func TestAddValidatorTxFees(t *testing.T) { - // For simplicity, we define a single AddValidatorTx - // and we change config parameters in the different test cases - r := require.New(t) - - defaultCtx := snowtest.Context(t, snowtest.PChainID) - defaultFeeCfg := config.FeeConfig{ +var ( + feeTestsDefaultCfg = config.FeeConfig{ DefaultUnitFees: fees.Dimensions{ 1 * units.MicroAvax, 2 * units.MicroAvax, @@ -39,30 +34,49 @@ func TestAddValidatorTxFees(t *testing.T) { 4 * units.MicroAvax, }, DefaultBlockMaxConsumedUnits: fees.Dimensions{ - 1000, - 1500, + 3000, + 3500, 1000, 1000, }, - AddPrimaryNetworkValidatorFee: 0, + + TxFee: 1 * units.Avax, + CreateAssetTxFee: 2 * units.Avax, + CreateSubnetTxFee: 3 * units.Avax, + TransformSubnetTxFee: 4 * units.Avax, + CreateBlockchainTxFee: 5 * units.Avax, + AddPrimaryNetworkValidatorFee: 6 * units.Avax, + AddPrimaryNetworkDelegatorFee: 7 * units.Avax, + AddSubnetValidatorFee: 8 * units.Avax, + AddSubnetDelegatorFee: 9 * units.Avax, } - // create a well formed AddValidatorTx - signers := [][]*secp256k1.PrivateKey{preFundedKeys} - validatorWeight := uint64(2024) - inputs, outputs, stakes, _ := txsCreationHelpers(defaultCtx, validatorWeight) + feeTestSigners = [][]*secp256k1.PrivateKey{preFundedKeys} + feeTestDefaultStakeWeight = uint64(2024) +) + +type feeTests struct { + description string + cfgAndChainTimeF func() (*config.Config, time.Time) + expectedError error + checksF func(*testing.T, *FeeCalculator) +} + +func TestAddValidatorTxFees(t *testing.T) { + // For simplicity, we define a single AddValidatorTx + // and we change config parameters in the different test cases + r := require.New(t) + + defaultCtx := snowtest.Context(t, snowtest.PChainID) + + baseTx, stakes, _ := txsCreationHelpers(defaultCtx) uTx := &txs.AddValidatorTx{ - BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ - NetworkID: defaultCtx.NetworkID, - BlockchainID: defaultCtx.ChainID, - Ins: inputs, - Outs: outputs, - }}, + BaseTx: baseTx, Validator: txs.Validator{ NodeID: defaultCtx.NodeID, Start: uint64(time.Now().Truncate(time.Second).Unix()), End: uint64(time.Now().Truncate(time.Second).Add(time.Hour).Unix()), - Wght: validatorWeight, + Wght: feeTestDefaultStakeWeight, }, StakeOuts: stakes, RewardsOwner: &secp256k1fx.OutputOwners{ @@ -72,17 +86,10 @@ func TestAddValidatorTxFees(t *testing.T) { }, DelegationShares: reward.PercentDenominator, } - stx, err := txs.NewSigned(uTx, txs.Codec, signers) + stx, err := txs.NewSigned(uTx, txs.Codec, feeTestSigners) r.NoError(err) - type test struct { - description string - cfgAndChainTimeF func() (*config.Config, time.Time) - expectedError error - checksF func(*testing.T, *FeeCalculator) - } - - tests := []test{ + tests := []feeTests{ { description: "pre E fork", cfgAndChainTimeF: func() (*config.Config, time.Time) { @@ -90,7 +97,7 @@ func TestAddValidatorTxFees(t *testing.T) { chainTime := eForkTime.Add(-1 * time.Second) cfg := &config.Config{ - FeeConfig: defaultFeeCfg, + FeeConfig: feeTestsDefaultCfg, DurangoTime: time.Time{}, // durango already active EForkTime: eForkTime, } @@ -109,7 +116,7 @@ func TestAddValidatorTxFees(t *testing.T) { chainTime := eForkTime.Add(time.Second) cfg := &config.Config{ - FeeConfig: defaultFeeCfg, + FeeConfig: feeTestsDefaultCfg, DurangoTime: time.Time{}, // durango already active EForkTime: eForkTime, } @@ -121,9 +128,9 @@ func TestAddValidatorTxFees(t *testing.T) { require.Equal(t, 3721*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ - uint64(len(stx.Bytes())), // this is a simple rule, can assert easily - 1090, // this is more complex rule, gotta check against hard-coded value - 266, // this is more complex rule, gotta check against hard-coded value + uint64(len(stx.Bytes())), + 1090, + 266, 0, }, fc.feeManager.GetCumulatedUnits(), @@ -137,7 +144,7 @@ func TestAddValidatorTxFees(t *testing.T) { chainTime := eForkTime.Add(time.Second) cfg := &config.Config{ - FeeConfig: defaultFeeCfg, + FeeConfig: feeTestsDefaultCfg, DurangoTime: time.Time{}, // durango already active EForkTime: eForkTime, } @@ -173,57 +180,26 @@ func TestAddSubnetValidatorTxFees(t *testing.T) { r := require.New(t) defaultCtx := snowtest.Context(t, snowtest.PChainID) - defaultFeeCfg := config.FeeConfig{ - DefaultUnitFees: fees.Dimensions{ - 1 * units.MicroAvax, - 2 * units.MicroAvax, - 3 * units.MicroAvax, - 4 * units.MicroAvax, - }, - DefaultBlockMaxConsumedUnits: fees.Dimensions{ - 1000, - 1500, - 1000, - 1000, - }, - AddPrimaryNetworkValidatorFee: 0, - } - // create a well formed AddValidatorTx - signers := [][]*secp256k1.PrivateKey{preFundedKeys} - validatorWeight := uint64(2024) subnetID := ids.GenerateTestID() - inputs, outputs, _, subnetAuth := txsCreationHelpers(defaultCtx, validatorWeight) + baseTx, _, subnetAuth := txsCreationHelpers(defaultCtx) uTx := &txs.AddSubnetValidatorTx{ - BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ - NetworkID: defaultCtx.NetworkID, - BlockchainID: defaultCtx.ChainID, - Ins: inputs, - Outs: outputs, - Memo: []byte{1, 2, 3, 4, 5, 6, 7, 8}, - }}, + BaseTx: baseTx, SubnetValidator: txs.SubnetValidator{ Validator: txs.Validator{ NodeID: defaultCtx.NodeID, Start: uint64(time.Now().Truncate(time.Second).Unix()), End: uint64(time.Now().Truncate(time.Second).Add(time.Hour).Unix()), - Wght: validatorWeight, + Wght: feeTestDefaultStakeWeight, }, Subnet: subnetID, }, SubnetAuth: subnetAuth, } - stx, err := txs.NewSigned(uTx, txs.Codec, signers) + stx, err := txs.NewSigned(uTx, txs.Codec, feeTestSigners) r.NoError(err) - type test struct { - description string - cfgAndChainTimeF func() (*config.Config, time.Time) - expectedError error - checksF func(*testing.T, *FeeCalculator) - } - - tests := []test{ + tests := []feeTests{ { description: "pre E fork", cfgAndChainTimeF: func() (*config.Config, time.Time) { @@ -231,7 +207,7 @@ func TestAddSubnetValidatorTxFees(t *testing.T) { chainTime := eForkTime.Add(-1 * time.Second) cfg := &config.Config{ - FeeConfig: defaultFeeCfg, + FeeConfig: feeTestsDefaultCfg, DurangoTime: time.Time{}, // durango already active EForkTime: eForkTime, } @@ -240,7 +216,7 @@ func TestAddSubnetValidatorTxFees(t *testing.T) { }, expectedError: nil, checksF: func(t *testing.T, fc *FeeCalculator) { - require.Equal(t, fc.Config.AddPrimaryNetworkValidatorFee, fc.Fee) + require.Equal(t, fc.Config.AddSubnetValidatorFee, fc.Fee) }, }, { @@ -250,7 +226,7 @@ func TestAddSubnetValidatorTxFees(t *testing.T) { chainTime := eForkTime.Add(time.Second) cfg := &config.Config{ - FeeConfig: defaultFeeCfg, + FeeConfig: feeTestsDefaultCfg, DurangoTime: time.Time{}, // durango already active EForkTime: eForkTime, } @@ -259,12 +235,12 @@ func TestAddSubnetValidatorTxFees(t *testing.T) { }, expectedError: nil, checksF: func(t *testing.T, fc *FeeCalculator) { - require.Equal(t, 3355*units.MicroAvax, fc.Fee) + require.Equal(t, 3347*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ - uint64(len(stx.Bytes())), // this is a simple rule, can assert easily - 1090, // this is more complex rule, gotta check against hard-coded value - 172, // this is more complex rule, gotta check against hard-coded value + uint64(len(stx.Bytes())), + 1090, + 172, 0, }, fc.feeManager.GetCumulatedUnits(), @@ -278,7 +254,7 @@ func TestAddSubnetValidatorTxFees(t *testing.T) { chainTime := eForkTime.Add(time.Second) cfg := &config.Config{ - FeeConfig: defaultFeeCfg, + FeeConfig: feeTestsDefaultCfg, DurangoTime: time.Time{}, // durango already active EForkTime: eForkTime, } @@ -314,39 +290,15 @@ func TestAddDelegatorTxFees(t *testing.T) { r := require.New(t) defaultCtx := snowtest.Context(t, snowtest.PChainID) - defaultFeeCfg := config.FeeConfig{ - DefaultUnitFees: fees.Dimensions{ - 1 * units.MicroAvax, - 2 * units.MicroAvax, - 3 * units.MicroAvax, - 4 * units.MicroAvax, - }, - DefaultBlockMaxConsumedUnits: fees.Dimensions{ - 1000, - 1500, - 1000, - 1000, - }, - AddPrimaryNetworkValidatorFee: 0, - } - // create a well formed AddValidatorTx - signers := [][]*secp256k1.PrivateKey{preFundedKeys} - validatorWeight := uint64(2024) - inputs, outputs, stakes, _ := txsCreationHelpers(defaultCtx, validatorWeight) + baseTx, stakes, _ := txsCreationHelpers(defaultCtx) uTx := &txs.AddDelegatorTx{ - BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ - NetworkID: defaultCtx.NetworkID, - BlockchainID: defaultCtx.ChainID, - Outs: outputs, - Ins: inputs, - Memo: []byte{1, 2, 3, 4, 5, 6, 7, 8}, - }}, + BaseTx: baseTx, Validator: txs.Validator{ NodeID: defaultCtx.NodeID, Start: uint64(time.Now().Truncate(time.Second).Unix()), End: uint64(time.Now().Truncate(time.Second).Add(time.Hour).Unix()), - Wght: validatorWeight, + Wght: feeTestDefaultStakeWeight, }, StakeOuts: stakes, DelegationRewardsOwner: &secp256k1fx.OutputOwners{ @@ -355,17 +307,10 @@ func TestAddDelegatorTxFees(t *testing.T) { Addrs: []ids.ShortID{preFundedKeys[0].PublicKey().Address()}, }, } - stx, err := txs.NewSigned(uTx, txs.Codec, signers) + stx, err := txs.NewSigned(uTx, txs.Codec, feeTestSigners) r.NoError(err) - type test struct { - description string - cfgAndChainTimeF func() (*config.Config, time.Time) - expectedError error - checksF func(*testing.T, *FeeCalculator) - } - - tests := []test{ + tests := []feeTests{ { description: "pre E fork", cfgAndChainTimeF: func() (*config.Config, time.Time) { @@ -373,7 +318,7 @@ func TestAddDelegatorTxFees(t *testing.T) { chainTime := eForkTime.Add(-1 * time.Second) cfg := &config.Config{ - FeeConfig: defaultFeeCfg, + FeeConfig: feeTestsDefaultCfg, DurangoTime: time.Time{}, // durango already active EForkTime: eForkTime, } @@ -382,7 +327,7 @@ func TestAddDelegatorTxFees(t *testing.T) { }, expectedError: nil, checksF: func(t *testing.T, fc *FeeCalculator) { - require.Equal(t, fc.Config.AddPrimaryNetworkValidatorFee, fc.Fee) + require.Equal(t, fc.Config.AddPrimaryNetworkDelegatorFee, fc.Fee) }, }, { @@ -392,7 +337,7 @@ func TestAddDelegatorTxFees(t *testing.T) { chainTime := eForkTime.Add(time.Second) cfg := &config.Config{ - FeeConfig: defaultFeeCfg, + FeeConfig: feeTestsDefaultCfg, DurangoTime: time.Time{}, // durango already active EForkTime: eForkTime, } @@ -401,12 +346,12 @@ func TestAddDelegatorTxFees(t *testing.T) { }, expectedError: nil, checksF: func(t *testing.T, fc *FeeCalculator) { - require.Equal(t, 3725*units.MicroAvax, fc.Fee) + require.Equal(t, 3717*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ - uint64(len(stx.Bytes())), // this is a simple rule, can assert easily - 1090, // this is more complex rule, gotta check against hard-coded value - 266, // this is more complex rule, gotta check against hard-coded value + uint64(len(stx.Bytes())), + 1090, + 266, 0, }, fc.feeManager.GetCumulatedUnits(), @@ -420,7 +365,7 @@ func TestAddDelegatorTxFees(t *testing.T) { chainTime := eForkTime.Add(time.Second) cfg := &config.Config{ - FeeConfig: defaultFeeCfg, + FeeConfig: feeTestsDefaultCfg, DurangoTime: time.Time{}, // durango already active EForkTime: eForkTime, } @@ -456,32 +401,10 @@ func TestCreateChainTxFees(t *testing.T) { r := require.New(t) defaultCtx := snowtest.Context(t, snowtest.PChainID) - defaultFeeCfg := config.FeeConfig{ - DefaultUnitFees: fees.Dimensions{ - 1 * units.MicroAvax, - 2 * units.MicroAvax, - 3 * units.MicroAvax, - 4 * units.MicroAvax, - }, - DefaultBlockMaxConsumedUnits: fees.Dimensions{ - 1000, - 1500, - 1000, - 1000, - }, - AddPrimaryNetworkValidatorFee: 0, - } - // create a well formed AddValidatorTx - signers := [][]*secp256k1.PrivateKey{preFundedKeys} - inputs, outputs, _, subnetAuth := txsCreationHelpers(defaultCtx, 0) + baseTx, _, subnetAuth := txsCreationHelpers(defaultCtx) uTx := &txs.CreateChainTx{ - BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ - NetworkID: defaultCtx.NetworkID, - BlockchainID: defaultCtx.ChainID, - Ins: inputs, - Outs: outputs, - }}, + BaseTx: baseTx, SubnetID: ids.GenerateTestID(), ChainName: "testingStuff", VMID: ids.GenerateTestID(), @@ -489,17 +412,10 @@ func TestCreateChainTxFees(t *testing.T) { GenesisData: []byte{0xff}, SubnetAuth: subnetAuth, } - stx, err := txs.NewSigned(uTx, txs.Codec, signers) + stx, err := txs.NewSigned(uTx, txs.Codec, feeTestSigners) r.NoError(err) - type test struct { - description string - cfgAndChainTimeF func() (*config.Config, time.Time) - expectedError error - checksF func(*testing.T, *FeeCalculator) - } - - tests := []test{ + tests := []feeTests{ { description: "pre E fork", cfgAndChainTimeF: func() (*config.Config, time.Time) { @@ -507,7 +423,7 @@ func TestCreateChainTxFees(t *testing.T) { chainTime := eForkTime.Add(-1 * time.Second) cfg := &config.Config{ - FeeConfig: defaultFeeCfg, + FeeConfig: feeTestsDefaultCfg, DurangoTime: time.Time{}, // durango already active EForkTime: eForkTime, } @@ -516,7 +432,7 @@ func TestCreateChainTxFees(t *testing.T) { }, expectedError: nil, checksF: func(t *testing.T, fc *FeeCalculator) { - require.Equal(t, fc.Config.AddPrimaryNetworkValidatorFee, fc.Fee) + require.Equal(t, fc.Config.CreateBlockchainTxFee, fc.Fee) }, }, { @@ -526,7 +442,7 @@ func TestCreateChainTxFees(t *testing.T) { chainTime := eForkTime.Add(time.Second) cfg := &config.Config{ - FeeConfig: defaultFeeCfg, + FeeConfig: feeTestsDefaultCfg, DurangoTime: time.Time{}, // durango already active EForkTime: eForkTime, } @@ -538,9 +454,9 @@ func TestCreateChainTxFees(t *testing.T) { require.Equal(t, 3390*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ - uint64(len(stx.Bytes())), // this is a simple rule, can assert easily - 1090, // this is more complex rule, gotta check against hard-coded value - 172, // this is more complex rule, gotta check against hard-coded value + uint64(len(stx.Bytes())), + 1090, + 172, 0, }, fc.feeManager.GetCumulatedUnits(), @@ -554,7 +470,7 @@ func TestCreateChainTxFees(t *testing.T) { chainTime := eForkTime.Add(time.Second) cfg := &config.Config{ - FeeConfig: defaultFeeCfg, + FeeConfig: feeTestsDefaultCfg, DurangoTime: time.Time{}, // durango already active EForkTime: eForkTime, } @@ -590,48 +506,19 @@ func TestCreateSubnetTxFees(t *testing.T) { r := require.New(t) defaultCtx := snowtest.Context(t, snowtest.PChainID) - defaultFeeCfg := config.FeeConfig{ - DefaultUnitFees: fees.Dimensions{ - 1 * units.MicroAvax, - 2 * units.MicroAvax, - 3 * units.MicroAvax, - 4 * units.MicroAvax, - }, - DefaultBlockMaxConsumedUnits: fees.Dimensions{ - 1000, - 1500, - 1000, - 1000, - }, - AddPrimaryNetworkValidatorFee: 0, - } - // create a well formed AddValidatorTx - signers := [][]*secp256k1.PrivateKey{preFundedKeys} - inputs, outputs, _, _ := txsCreationHelpers(defaultCtx, 0) + baseTx, _, _ := txsCreationHelpers(defaultCtx) uTx := &txs.CreateSubnetTx{ - BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ - NetworkID: defaultCtx.NetworkID, - BlockchainID: defaultCtx.ChainID, - Ins: inputs, - Outs: outputs, - }}, + BaseTx: baseTx, Owner: &secp256k1fx.OutputOwners{ Threshold: 1, Addrs: []ids.ShortID{preFundedKeys[0].PublicKey().Address()}, }, } - stx, err := txs.NewSigned(uTx, txs.Codec, signers) + stx, err := txs.NewSigned(uTx, txs.Codec, feeTestSigners) r.NoError(err) - type test struct { - description string - cfgAndChainTimeF func() (*config.Config, time.Time) - expectedError error - checksF func(*testing.T, *FeeCalculator) - } - - tests := []test{ + tests := []feeTests{ { description: "pre E fork", cfgAndChainTimeF: func() (*config.Config, time.Time) { @@ -639,7 +526,7 @@ func TestCreateSubnetTxFees(t *testing.T) { chainTime := eForkTime.Add(-1 * time.Second) cfg := &config.Config{ - FeeConfig: defaultFeeCfg, + FeeConfig: feeTestsDefaultCfg, DurangoTime: time.Time{}, // durango already active EForkTime: eForkTime, } @@ -648,7 +535,7 @@ func TestCreateSubnetTxFees(t *testing.T) { }, expectedError: nil, checksF: func(t *testing.T, fc *FeeCalculator) { - require.Equal(t, fc.Config.AddPrimaryNetworkValidatorFee, fc.Fee) + require.Equal(t, fc.Config.CreateSubnetTxFee, fc.Fee) }, }, { @@ -658,7 +545,7 @@ func TestCreateSubnetTxFees(t *testing.T) { chainTime := eForkTime.Add(time.Second) cfg := &config.Config{ - FeeConfig: defaultFeeCfg, + FeeConfig: feeTestsDefaultCfg, DurangoTime: time.Time{}, // durango already active EForkTime: eForkTime, } @@ -670,9 +557,9 @@ func TestCreateSubnetTxFees(t *testing.T) { require.Equal(t, 3295*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ - uint64(len(stx.Bytes())), // this is a simple rule, can assert easily - 1090, // this is more complex rule, gotta check against hard-coded value - 172, // this is more complex rule, gotta check against hard-coded value + uint64(len(stx.Bytes())), + 1090, + 172, 0, }, fc.feeManager.GetCumulatedUnits(), @@ -686,7 +573,7 @@ func TestCreateSubnetTxFees(t *testing.T) { chainTime := eForkTime.Add(time.Second) cfg := &config.Config{ - FeeConfig: defaultFeeCfg, + FeeConfig: feeTestsDefaultCfg, DurangoTime: time.Time{}, // durango already active EForkTime: eForkTime, } @@ -722,47 +609,18 @@ func TestRemoveSubnetValidatorTxFees(t *testing.T) { r := require.New(t) defaultCtx := snowtest.Context(t, snowtest.PChainID) - defaultFeeCfg := config.FeeConfig{ - DefaultUnitFees: fees.Dimensions{ - 1 * units.MicroAvax, - 2 * units.MicroAvax, - 3 * units.MicroAvax, - 4 * units.MicroAvax, - }, - DefaultBlockMaxConsumedUnits: fees.Dimensions{ - 1000, - 1500, - 1000, - 1000, - }, - AddPrimaryNetworkValidatorFee: 0, - } - // create a well formed AddValidatorTx - signers := [][]*secp256k1.PrivateKey{preFundedKeys} - inputs, outputs, _, auth := txsCreationHelpers(defaultCtx, 0) + baseTx, _, auth := txsCreationHelpers(defaultCtx) uTx := &txs.RemoveSubnetValidatorTx{ - BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ - NetworkID: defaultCtx.NetworkID, - BlockchainID: defaultCtx.ChainID, - Ins: inputs, - Outs: outputs, - }}, + BaseTx: baseTx, NodeID: ids.GenerateTestNodeID(), Subnet: ids.GenerateTestID(), SubnetAuth: auth, } - stx, err := txs.NewSigned(uTx, txs.Codec, signers) + stx, err := txs.NewSigned(uTx, txs.Codec, feeTestSigners) r.NoError(err) - type test struct { - description string - cfgAndChainTimeF func() (*config.Config, time.Time) - expectedError error - checksF func(*testing.T, *FeeCalculator) - } - - tests := []test{ + tests := []feeTests{ { description: "pre E fork", cfgAndChainTimeF: func() (*config.Config, time.Time) { @@ -770,7 +628,7 @@ func TestRemoveSubnetValidatorTxFees(t *testing.T) { chainTime := eForkTime.Add(-1 * time.Second) cfg := &config.Config{ - FeeConfig: defaultFeeCfg, + FeeConfig: feeTestsDefaultCfg, DurangoTime: time.Time{}, // durango already active EForkTime: eForkTime, } @@ -779,7 +637,7 @@ func TestRemoveSubnetValidatorTxFees(t *testing.T) { }, expectedError: nil, checksF: func(t *testing.T, fc *FeeCalculator) { - require.Equal(t, fc.Config.AddPrimaryNetworkValidatorFee, fc.Fee) + require.Equal(t, fc.Config.TxFee, fc.Fee) }, }, { @@ -789,7 +647,7 @@ func TestRemoveSubnetValidatorTxFees(t *testing.T) { chainTime := eForkTime.Add(time.Second) cfg := &config.Config{ - FeeConfig: defaultFeeCfg, + FeeConfig: feeTestsDefaultCfg, DurangoTime: time.Time{}, // durango already active EForkTime: eForkTime, } @@ -801,9 +659,9 @@ func TestRemoveSubnetValidatorTxFees(t *testing.T) { require.Equal(t, 3323*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ - uint64(len(stx.Bytes())), // this is a simple rule, can assert easily - 1090, // this is more complex rule, gotta check against hard-coded value - 172, // this is more complex rule, gotta check against hard-coded value + uint64(len(stx.Bytes())), + 1090, + 172, 0, }, fc.feeManager.GetCumulatedUnits(), @@ -817,7 +675,7 @@ func TestRemoveSubnetValidatorTxFees(t *testing.T) { chainTime := eForkTime.Add(time.Second) cfg := &config.Config{ - FeeConfig: defaultFeeCfg, + FeeConfig: feeTestsDefaultCfg, DurangoTime: time.Time{}, // durango already active EForkTime: eForkTime, } @@ -853,32 +711,10 @@ func TestTransformSubnetTxFees(t *testing.T) { r := require.New(t) defaultCtx := snowtest.Context(t, snowtest.PChainID) - defaultFeeCfg := config.FeeConfig{ - DefaultUnitFees: fees.Dimensions{ - 1 * units.MicroAvax, - 2 * units.MicroAvax, - 3 * units.MicroAvax, - 4 * units.MicroAvax, - }, - DefaultBlockMaxConsumedUnits: fees.Dimensions{ - 1000, - 1500, - 1000, - 1000, - }, - AddPrimaryNetworkValidatorFee: 0, - } - // create a well formed AddValidatorTx - signers := [][]*secp256k1.PrivateKey{preFundedKeys} - inputs, outputs, _, auth := txsCreationHelpers(defaultCtx, 0) + baseTx, _, auth := txsCreationHelpers(defaultCtx) uTx := &txs.TransformSubnetTx{ - BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ - NetworkID: defaultCtx.NetworkID, - BlockchainID: defaultCtx.ChainID, - Ins: inputs, - Outs: outputs, - }}, + BaseTx: baseTx, Subnet: ids.GenerateTestID(), AssetID: ids.GenerateTestID(), InitialSupply: 0x1000000000000000, @@ -895,17 +731,10 @@ func TestTransformSubnetTxFees(t *testing.T) { UptimeRequirement: 0, SubnetAuth: auth, } - stx, err := txs.NewSigned(uTx, txs.Codec, signers) + stx, err := txs.NewSigned(uTx, txs.Codec, feeTestSigners) r.NoError(err) - type test struct { - description string - cfgAndChainTimeF func() (*config.Config, time.Time) - expectedError error - checksF func(*testing.T, *FeeCalculator) - } - - tests := []test{ + tests := []feeTests{ { description: "pre E fork", cfgAndChainTimeF: func() (*config.Config, time.Time) { @@ -913,7 +742,7 @@ func TestTransformSubnetTxFees(t *testing.T) { chainTime := eForkTime.Add(-1 * time.Second) cfg := &config.Config{ - FeeConfig: defaultFeeCfg, + FeeConfig: feeTestsDefaultCfg, DurangoTime: time.Time{}, // durango already active EForkTime: eForkTime, } @@ -922,7 +751,7 @@ func TestTransformSubnetTxFees(t *testing.T) { }, expectedError: nil, checksF: func(t *testing.T, fc *FeeCalculator) { - require.Equal(t, fc.Config.AddPrimaryNetworkValidatorFee, fc.Fee) + require.Equal(t, fc.Config.TransformSubnetTxFee, fc.Fee) }, }, { @@ -932,7 +761,7 @@ func TestTransformSubnetTxFees(t *testing.T) { chainTime := eForkTime.Add(time.Second) cfg := &config.Config{ - FeeConfig: defaultFeeCfg, + FeeConfig: feeTestsDefaultCfg, DurangoTime: time.Time{}, // durango already active EForkTime: eForkTime, } @@ -944,9 +773,9 @@ func TestTransformSubnetTxFees(t *testing.T) { require.Equal(t, 3408*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ - uint64(len(stx.Bytes())), // this is a simple rule, can assert easily - 1090, // this is more complex rule, gotta check against hard-coded value - 172, // this is more complex rule, gotta check against hard-coded value + uint64(len(stx.Bytes())), + 1090, + 172, 0, }, fc.feeManager.GetCumulatedUnits(), @@ -960,7 +789,7 @@ func TestTransformSubnetTxFees(t *testing.T) { chainTime := eForkTime.Add(time.Second) cfg := &config.Config{ - FeeConfig: defaultFeeCfg, + FeeConfig: feeTestsDefaultCfg, DurangoTime: time.Time{}, // durango already active EForkTime: eForkTime, } @@ -996,32 +825,10 @@ func TestTransferSubnetOwnershipTxFees(t *testing.T) { r := require.New(t) defaultCtx := snowtest.Context(t, snowtest.PChainID) - defaultFeeCfg := config.FeeConfig{ - DefaultUnitFees: fees.Dimensions{ - 1 * units.MicroAvax, - 2 * units.MicroAvax, - 3 * units.MicroAvax, - 4 * units.MicroAvax, - }, - DefaultBlockMaxConsumedUnits: fees.Dimensions{ - 1000, - 1500, - 1000, - 1000, - }, - AddPrimaryNetworkValidatorFee: 0, - } - // create a well formed AddValidatorTx - signers := [][]*secp256k1.PrivateKey{preFundedKeys} - inputs, outputs, _, _ := txsCreationHelpers(defaultCtx, 0) + baseTx, _, _ := txsCreationHelpers(defaultCtx) uTx := &txs.TransferSubnetOwnershipTx{ - BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ - NetworkID: defaultCtx.NetworkID, - BlockchainID: defaultCtx.ChainID, - Ins: inputs, - Outs: outputs, - }}, + BaseTx: baseTx, Subnet: ids.GenerateTestID(), SubnetAuth: &secp256k1fx.Input{ SigIndices: []uint32{3}, @@ -1034,17 +841,10 @@ func TestTransferSubnetOwnershipTxFees(t *testing.T) { }, }, } - stx, err := txs.NewSigned(uTx, txs.Codec, signers) + stx, err := txs.NewSigned(uTx, txs.Codec, feeTestSigners) r.NoError(err) - type test struct { - description string - cfgAndChainTimeF func() (*config.Config, time.Time) - expectedError error - checksF func(*testing.T, *FeeCalculator) - } - - tests := []test{ + tests := []feeTests{ { description: "pre E fork", cfgAndChainTimeF: func() (*config.Config, time.Time) { @@ -1052,7 +852,7 @@ func TestTransferSubnetOwnershipTxFees(t *testing.T) { chainTime := eForkTime.Add(-1 * time.Second) cfg := &config.Config{ - FeeConfig: defaultFeeCfg, + FeeConfig: feeTestsDefaultCfg, DurangoTime: time.Time{}, // durango already active EForkTime: eForkTime, } @@ -1061,7 +861,7 @@ func TestTransferSubnetOwnershipTxFees(t *testing.T) { }, expectedError: nil, checksF: func(t *testing.T, fc *FeeCalculator) { - require.Equal(t, fc.Config.AddPrimaryNetworkValidatorFee, fc.Fee) + require.Equal(t, fc.Config.TxFee, fc.Fee) }, }, { @@ -1071,7 +871,7 @@ func TestTransferSubnetOwnershipTxFees(t *testing.T) { chainTime := eForkTime.Add(time.Second) cfg := &config.Config{ - FeeConfig: defaultFeeCfg, + FeeConfig: feeTestsDefaultCfg, DurangoTime: time.Time{}, // durango already active EForkTime: eForkTime, } @@ -1083,9 +883,9 @@ func TestTransferSubnetOwnershipTxFees(t *testing.T) { require.Equal(t, 3339*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ - uint64(len(stx.Bytes())), // this is a simple rule, can assert easily - 1090, // this is more complex rule, gotta check against hard-coded value - 172, // this is more complex rule, gotta check against hard-coded value + uint64(len(stx.Bytes())), + 1090, + 172, 0, }, fc.feeManager.GetCumulatedUnits(), @@ -1099,7 +899,7 @@ func TestTransferSubnetOwnershipTxFees(t *testing.T) { chainTime := eForkTime.Add(time.Second) cfg := &config.Config{ - FeeConfig: defaultFeeCfg, + FeeConfig: feeTestsDefaultCfg, DurangoTime: time.Time{}, // durango already active EForkTime: eForkTime, } @@ -1135,34 +935,12 @@ func TestAddPermissionlessValidatorTxFees(t *testing.T) { r := require.New(t) defaultCtx := snowtest.Context(t, snowtest.PChainID) - defaultFeeCfg := config.FeeConfig{ - DefaultUnitFees: fees.Dimensions{ - 1 * units.MicroAvax, - 2 * units.MicroAvax, - 3 * units.MicroAvax, - 4 * units.MicroAvax, - }, - DefaultBlockMaxConsumedUnits: fees.Dimensions{ - 1000, - 1500, - 1000, - 1000, - }, - AddPrimaryNetworkValidatorFee: 0, - } - // create a well formed AddValidatorTx - signers := [][]*secp256k1.PrivateKey{preFundedKeys} - inputs, outputs, stakes, _ := txsCreationHelpers(defaultCtx, 0) + baseTx, stakes, _ := txsCreationHelpers(defaultCtx) sk, err := bls.NewSecretKey() r.NoError(err) uTx := &txs.AddPermissionlessValidatorTx{ - BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ - NetworkID: defaultCtx.NetworkID, - BlockchainID: defaultCtx.ChainID, - Ins: inputs, - Outs: outputs, - }}, + BaseTx: baseTx, Subnet: ids.GenerateTestID(), Signer: signer.NewProofOfPossession(sk), StakeOuts: stakes, @@ -1182,17 +960,10 @@ func TestAddPermissionlessValidatorTxFees(t *testing.T) { }, DelegationShares: reward.PercentDenominator, } - stx, err := txs.NewSigned(uTx, txs.Codec, signers) + stx, err := txs.NewSigned(uTx, txs.Codec, feeTestSigners) r.NoError(err) - type test struct { - description string - cfgAndChainTimeF func() (*config.Config, time.Time) - expectedError error - checksF func(*testing.T, *FeeCalculator) - } - - tests := []test{ + tests := []feeTests{ { description: "pre E fork", cfgAndChainTimeF: func() (*config.Config, time.Time) { @@ -1200,7 +971,7 @@ func TestAddPermissionlessValidatorTxFees(t *testing.T) { chainTime := eForkTime.Add(-1 * time.Second) cfg := &config.Config{ - FeeConfig: defaultFeeCfg, + FeeConfig: feeTestsDefaultCfg, DurangoTime: time.Time{}, // durango already active EForkTime: eForkTime, } @@ -1209,7 +980,7 @@ func TestAddPermissionlessValidatorTxFees(t *testing.T) { }, expectedError: nil, checksF: func(t *testing.T, fc *FeeCalculator) { - require.Equal(t, fc.Config.AddPrimaryNetworkValidatorFee, fc.Fee) + require.Equal(t, fc.Config.AddSubnetValidatorFee, fc.Fee) }, }, { @@ -1219,7 +990,7 @@ func TestAddPermissionlessValidatorTxFees(t *testing.T) { chainTime := eForkTime.Add(time.Second) cfg := &config.Config{ - FeeConfig: defaultFeeCfg, + FeeConfig: feeTestsDefaultCfg, DurangoTime: time.Time{}, // durango already active EForkTime: eForkTime, } @@ -1231,9 +1002,9 @@ func TestAddPermissionlessValidatorTxFees(t *testing.T) { require.Equal(t, 3941*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ - uint64(len(stx.Bytes())), // this is a simple rule, can assert easily - 1090, // this is more complex rule, gotta check against hard-coded value - 266, // this is more complex rule, gotta check against hard-coded value + uint64(len(stx.Bytes())), + 1090, + 266, 0, }, fc.feeManager.GetCumulatedUnits(), @@ -1247,7 +1018,7 @@ func TestAddPermissionlessValidatorTxFees(t *testing.T) { chainTime := eForkTime.Add(time.Second) cfg := &config.Config{ - FeeConfig: defaultFeeCfg, + FeeConfig: feeTestsDefaultCfg, DurangoTime: time.Time{}, // durango already active EForkTime: eForkTime, } @@ -1283,32 +1054,10 @@ func TestAddPermissionlessDelegatorTxFees(t *testing.T) { r := require.New(t) defaultCtx := snowtest.Context(t, snowtest.PChainID) - defaultFeeCfg := config.FeeConfig{ - DefaultUnitFees: fees.Dimensions{ - 1 * units.MicroAvax, - 2 * units.MicroAvax, - 3 * units.MicroAvax, - 4 * units.MicroAvax, - }, - DefaultBlockMaxConsumedUnits: fees.Dimensions{ - 1000, - 1500, - 1000, - 1000, - }, - AddPrimaryNetworkValidatorFee: 0, - } - // create a well formed AddValidatorTx - signers := [][]*secp256k1.PrivateKey{preFundedKeys} - inputs, outputs, stakes, _ := txsCreationHelpers(defaultCtx, 2*units.KiloAvax) + baseTx, stakes, _ := txsCreationHelpers(defaultCtx) uTx := &txs.AddPermissionlessDelegatorTx{ - BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ - NetworkID: defaultCtx.NetworkID, - BlockchainID: defaultCtx.ChainID, - Ins: inputs, - Outs: outputs, - }}, + BaseTx: baseTx, Validator: txs.Validator{ NodeID: ids.GenerateTestNodeID(), Start: 12345, @@ -1325,17 +1074,10 @@ func TestAddPermissionlessDelegatorTxFees(t *testing.T) { }, }, } - stx, err := txs.NewSigned(uTx, txs.Codec, signers) + stx, err := txs.NewSigned(uTx, txs.Codec, feeTestSigners) r.NoError(err) - type test struct { - description string - cfgAndChainTimeF func() (*config.Config, time.Time) - expectedError error - checksF func(*testing.T, *FeeCalculator) - } - - tests := []test{ + tests := []feeTests{ { description: "pre E fork", cfgAndChainTimeF: func() (*config.Config, time.Time) { @@ -1343,7 +1085,7 @@ func TestAddPermissionlessDelegatorTxFees(t *testing.T) { chainTime := eForkTime.Add(-1 * time.Second) cfg := &config.Config{ - FeeConfig: defaultFeeCfg, + FeeConfig: feeTestsDefaultCfg, DurangoTime: time.Time{}, // durango already active EForkTime: eForkTime, } @@ -1352,7 +1094,7 @@ func TestAddPermissionlessDelegatorTxFees(t *testing.T) { }, expectedError: nil, checksF: func(t *testing.T, fc *FeeCalculator) { - require.Equal(t, fc.Config.AddPrimaryNetworkValidatorFee, fc.Fee) + require.Equal(t, fc.Config.AddSubnetDelegatorFee, fc.Fee) }, }, { @@ -1362,7 +1104,7 @@ func TestAddPermissionlessDelegatorTxFees(t *testing.T) { chainTime := eForkTime.Add(time.Second) cfg := &config.Config{ - FeeConfig: defaultFeeCfg, + FeeConfig: feeTestsDefaultCfg, DurangoTime: time.Time{}, // durango already active EForkTime: eForkTime, } @@ -1374,9 +1116,9 @@ func TestAddPermissionlessDelegatorTxFees(t *testing.T) { require.Equal(t, 3749*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ - uint64(len(stx.Bytes())), // this is a simple rule, can assert easily - 1090, // this is more complex rule, gotta check against hard-coded value - 266, // this is more complex rule, gotta check against hard-coded value + uint64(len(stx.Bytes())), + 1090, + 266, 0, }, fc.feeManager.GetCumulatedUnits(), @@ -1390,7 +1132,7 @@ func TestAddPermissionlessDelegatorTxFees(t *testing.T) { chainTime := eForkTime.Add(time.Second) cfg := &config.Config{ - FeeConfig: defaultFeeCfg, + FeeConfig: feeTestsDefaultCfg, DurangoTime: time.Time{}, // durango already active EForkTime: eForkTime, } @@ -1426,42 +1168,13 @@ func TestBaseTxFees(t *testing.T) { r := require.New(t) defaultCtx := snowtest.Context(t, snowtest.PChainID) - defaultFeeCfg := config.FeeConfig{ - DefaultUnitFees: fees.Dimensions{ - 1 * units.MicroAvax, - 2 * units.MicroAvax, - 3 * units.MicroAvax, - 4 * units.MicroAvax, - }, - DefaultBlockMaxConsumedUnits: fees.Dimensions{ - 1000, - 1500, - 1000, - 1000, - }, - AddPrimaryNetworkValidatorFee: 0, - } - // create a well formed AddValidatorTx - signers := [][]*secp256k1.PrivateKey{preFundedKeys} - inputs, outputs, _, _ := txsCreationHelpers(defaultCtx, 2*units.KiloAvax) - uTx := &txs.BaseTx{BaseTx: avax.BaseTx{ - NetworkID: defaultCtx.NetworkID, - BlockchainID: defaultCtx.ChainID, - Ins: inputs, - Outs: outputs, - }} - stx, err := txs.NewSigned(uTx, txs.Codec, signers) + baseTx, _, _ := txsCreationHelpers(defaultCtx) + uTx := &baseTx + stx, err := txs.NewSigned(uTx, txs.Codec, feeTestSigners) r.NoError(err) - type test struct { - description string - cfgAndChainTimeF func() (*config.Config, time.Time) - expectedError error - checksF func(*testing.T, *FeeCalculator) - } - - tests := []test{ + tests := []feeTests{ { description: "pre E fork", cfgAndChainTimeF: func() (*config.Config, time.Time) { @@ -1469,7 +1182,7 @@ func TestBaseTxFees(t *testing.T) { chainTime := eForkTime.Add(-1 * time.Second) cfg := &config.Config{ - FeeConfig: defaultFeeCfg, + FeeConfig: feeTestsDefaultCfg, DurangoTime: time.Time{}, // durango already active EForkTime: eForkTime, } @@ -1478,7 +1191,7 @@ func TestBaseTxFees(t *testing.T) { }, expectedError: nil, checksF: func(t *testing.T, fc *FeeCalculator) { - require.Equal(t, fc.Config.AddPrimaryNetworkValidatorFee, fc.Fee) + require.Equal(t, fc.Config.TxFee, fc.Fee) }, }, { @@ -1488,7 +1201,7 @@ func TestBaseTxFees(t *testing.T) { chainTime := eForkTime.Add(time.Second) cfg := &config.Config{ - FeeConfig: defaultFeeCfg, + FeeConfig: feeTestsDefaultCfg, DurangoTime: time.Time{}, // durango already active EForkTime: eForkTime, } @@ -1500,9 +1213,9 @@ func TestBaseTxFees(t *testing.T) { require.Equal(t, 3255*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ - uint64(len(stx.Bytes())), // this is a simple rule, can assert easily - 1090, // this is more complex rule, gotta check against hard-coded value - 172, // this is more complex rule, gotta check against hard-coded value + uint64(len(stx.Bytes())), + 1090, + 172, 0, }, fc.feeManager.GetCumulatedUnits(), @@ -1516,7 +1229,7 @@ func TestBaseTxFees(t *testing.T) { chainTime := eForkTime.Add(time.Second) cfg := &config.Config{ - FeeConfig: defaultFeeCfg, + FeeConfig: feeTestsDefaultCfg, DurangoTime: time.Time{}, // durango already active EForkTime: eForkTime, } @@ -1552,32 +1265,10 @@ func TestImportTxFees(t *testing.T) { r := require.New(t) defaultCtx := snowtest.Context(t, snowtest.PChainID) - defaultFeeCfg := config.FeeConfig{ - DefaultUnitFees: fees.Dimensions{ - 1 * units.MicroAvax, - 2 * units.MicroAvax, - 3 * units.MicroAvax, - 4 * units.MicroAvax, - }, - DefaultBlockMaxConsumedUnits: fees.Dimensions{ - 3000, - 2500, - 1000, - 1000, - }, - AddPrimaryNetworkValidatorFee: 0, - } - // create a well formed AddValidatorTx - signers := [][]*secp256k1.PrivateKey{preFundedKeys} - inputs, outputs, _, _ := txsCreationHelpers(defaultCtx, 2*units.KiloAvax) + baseTx, _, _ := txsCreationHelpers(defaultCtx) uTx := &txs.ImportTx{ - BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ - NetworkID: defaultCtx.NetworkID, - BlockchainID: defaultCtx.ChainID, - Ins: inputs, - Outs: outputs, - }}, + BaseTx: baseTx, SourceChain: ids.GenerateTestID(), ImportedInputs: []*avax.TransferableInput{{ UTXOID: avax.UTXOID{ @@ -1591,17 +1282,10 @@ func TestImportTxFees(t *testing.T) { }, }}, } - stx, err := txs.NewSigned(uTx, txs.Codec, signers) + stx, err := txs.NewSigned(uTx, txs.Codec, feeTestSigners) r.NoError(err) - type test struct { - description string - cfgAndChainTimeF func() (*config.Config, time.Time) - expectedError error - checksF func(*testing.T, *FeeCalculator) - } - - tests := []test{ + tests := []feeTests{ { description: "pre E fork", cfgAndChainTimeF: func() (*config.Config, time.Time) { @@ -1609,7 +1293,7 @@ func TestImportTxFees(t *testing.T) { chainTime := eForkTime.Add(-1 * time.Second) cfg := &config.Config{ - FeeConfig: defaultFeeCfg, + FeeConfig: feeTestsDefaultCfg, DurangoTime: time.Time{}, // durango already active EForkTime: eForkTime, } @@ -1618,7 +1302,7 @@ func TestImportTxFees(t *testing.T) { }, expectedError: nil, checksF: func(t *testing.T, fc *FeeCalculator) { - require.Equal(t, fc.Config.AddPrimaryNetworkValidatorFee, fc.Fee) + require.Equal(t, fc.Config.TxFee, fc.Fee) }, }, { @@ -1628,7 +1312,7 @@ func TestImportTxFees(t *testing.T) { chainTime := eForkTime.Add(time.Second) cfg := &config.Config{ - FeeConfig: defaultFeeCfg, + FeeConfig: feeTestsDefaultCfg, DurangoTime: time.Time{}, // durango already active EForkTime: eForkTime, } @@ -1640,9 +1324,9 @@ func TestImportTxFees(t *testing.T) { require.Equal(t, 5829*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ - uint64(len(stx.Bytes())), // this is a simple rule, can assert easily - 2180, // this is more complex rule, gotta check against hard-coded value - 262, // this is more complex rule, gotta check against hard-coded value + uint64(len(stx.Bytes())), + 2180, + 262, 0, }, fc.feeManager.GetCumulatedUnits(), @@ -1656,7 +1340,7 @@ func TestImportTxFees(t *testing.T) { chainTime := eForkTime.Add(time.Second) cfg := &config.Config{ - FeeConfig: defaultFeeCfg, + FeeConfig: feeTestsDefaultCfg, DurangoTime: time.Time{}, // durango already active EForkTime: eForkTime, } @@ -1692,46 +1376,17 @@ func TestExportTxFees(t *testing.T) { r := require.New(t) defaultCtx := snowtest.Context(t, snowtest.PChainID) - defaultFeeCfg := config.FeeConfig{ - DefaultUnitFees: fees.Dimensions{ - 1 * units.MicroAvax, - 2 * units.MicroAvax, - 3 * units.MicroAvax, - 4 * units.MicroAvax, - }, - DefaultBlockMaxConsumedUnits: fees.Dimensions{ - 3000, - 2500, - 1000, - 1000, - }, - AddPrimaryNetworkValidatorFee: 0, - } - // create a well formed AddValidatorTx - signers := [][]*secp256k1.PrivateKey{preFundedKeys} - inputs, outputs, _, _ := txsCreationHelpers(defaultCtx, 2*units.KiloAvax) + baseTx, outputs, _ := txsCreationHelpers(defaultCtx) uTx := &txs.ExportTx{ - BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ - NetworkID: defaultCtx.NetworkID, - BlockchainID: defaultCtx.ChainID, - Ins: inputs, - Outs: outputs, - }}, + BaseTx: baseTx, DestinationChain: ids.GenerateTestID(), ExportedOutputs: outputs, } - stx, err := txs.NewSigned(uTx, txs.Codec, signers) + stx, err := txs.NewSigned(uTx, txs.Codec, feeTestSigners) r.NoError(err) - type test struct { - description string - cfgAndChainTimeF func() (*config.Config, time.Time) - expectedError error - checksF func(*testing.T, *FeeCalculator) - } - - tests := []test{ + tests := []feeTests{ { description: "pre E fork", cfgAndChainTimeF: func() (*config.Config, time.Time) { @@ -1739,7 +1394,7 @@ func TestExportTxFees(t *testing.T) { chainTime := eForkTime.Add(-1 * time.Second) cfg := &config.Config{ - FeeConfig: defaultFeeCfg, + FeeConfig: feeTestsDefaultCfg, DurangoTime: time.Time{}, // durango already active EForkTime: eForkTime, } @@ -1748,7 +1403,7 @@ func TestExportTxFees(t *testing.T) { }, expectedError: nil, checksF: func(t *testing.T, fc *FeeCalculator) { - require.Equal(t, fc.Config.AddPrimaryNetworkValidatorFee, fc.Fee) + require.Equal(t, fc.Config.TxFee, fc.Fee) }, }, { @@ -1758,7 +1413,7 @@ func TestExportTxFees(t *testing.T) { chainTime := eForkTime.Add(time.Second) cfg := &config.Config{ - FeeConfig: defaultFeeCfg, + FeeConfig: feeTestsDefaultCfg, DurangoTime: time.Time{}, // durango already active EForkTime: eForkTime, } @@ -1767,12 +1422,12 @@ func TestExportTxFees(t *testing.T) { }, expectedError: nil, checksF: func(t *testing.T, fc *FeeCalculator) { - require.Equal(t, 3617*units.MicroAvax, fc.Fee) + require.Equal(t, 3665*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ - uint64(len(stx.Bytes())), // this is a simple rule, can assert easily - 1090, // this is more complex rule, gotta check against hard-coded value - 254, // this is more complex rule, gotta check against hard-coded value + uint64(len(stx.Bytes())), + 1090, + 266, 0, }, fc.feeManager.GetCumulatedUnits(), @@ -1786,7 +1441,7 @@ func TestExportTxFees(t *testing.T) { chainTime := eForkTime.Add(time.Second) cfg := &config.Config{ - FeeConfig: defaultFeeCfg, + FeeConfig: feeTestsDefaultCfg, DurangoTime: time.Time{}, // durango already active EForkTime: eForkTime, } @@ -1816,13 +1471,12 @@ func TestExportTxFees(t *testing.T) { } } -func txsCreationHelpers(defaultCtx *snow.Context, stakeWeight uint64) ( - inputs []*avax.TransferableInput, - outputs []*avax.TransferableOutput, +func txsCreationHelpers(defaultCtx *snow.Context) ( + baseTx txs.BaseTx, stakes []*avax.TransferableOutput, auth *secp256k1fx.Input, ) { - inputs = []*avax.TransferableInput{{ + inputs := []*avax.TransferableInput{{ UTXOID: avax.UTXOID{ TxID: ids.ID{'t', 'x', 'I', 'D'}, OutputIndex: 2, @@ -1833,7 +1487,7 @@ func txsCreationHelpers(defaultCtx *snow.Context, stakeWeight uint64) ( Input: secp256k1fx.Input{SigIndices: []uint32{0}}, }, }} - outputs = []*avax.TransferableOutput{{ + outputs := []*avax.TransferableOutput{{ Asset: avax.Asset{ID: defaultCtx.AVAXAssetID}, Out: &secp256k1fx.TransferOutput{ Amt: uint64(1234), @@ -1848,7 +1502,7 @@ func txsCreationHelpers(defaultCtx *snow.Context, stakeWeight uint64) ( Out: &stakeable.LockOut{ Locktime: uint64(time.Now().Add(time.Second).Unix()), TransferableOut: &secp256k1fx.TransferOutput{ - Amt: stakeWeight, + Amt: feeTestDefaultStakeWeight, OutputOwners: secp256k1fx.OutputOwners{ Threshold: 1, Addrs: []ids.ShortID{preFundedKeys[0].PublicKey().Address()}, @@ -1859,5 +1513,14 @@ func txsCreationHelpers(defaultCtx *snow.Context, stakeWeight uint64) ( auth = &secp256k1fx.Input{ SigIndices: []uint32{0, 1}, } - return inputs, outputs, stakes, auth + baseTx = txs.BaseTx{ + BaseTx: avax.BaseTx{ + NetworkID: defaultCtx.NetworkID, + BlockchainID: defaultCtx.ChainID, + Ins: inputs, + Outs: outputs, + }, + } + + return baseTx, stakes, auth } From 8df89e5e443a178482cc7b6b3839d71440a06de4 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Tue, 9 Jan 2024 19:05:16 +0100 Subject: [PATCH 019/190] added feeCalculator to avm --- node/node.go | 4 +- vms/avm/block/executor/block.go | 7 +- vms/avm/block/executor/block_test.go | 140 ++++++++++++++- vms/avm/block/executor/manager.go | 7 +- vms/avm/block/executor/manager_test.go | 36 +++- vms/avm/config/config.go | 33 +++- vms/avm/environment_test.go | 3 + vms/avm/index_test.go | 17 +- vms/avm/service_test.go | 36 +++- vms/avm/txs/executor/fee_calculator.go | 169 ++++++++++++++++++ vms/avm/txs/executor/syntactic_verifier.go | 66 ++++++- .../txs/executor/syntactic_verifier_test.go | 3 + vms/avm/vm.go | 7 +- vms/avm/vm_regression_test.go | 7 +- vms/avm/vm_test.go | 24 ++- 15 files changed, 518 insertions(+), 41 deletions(-) create mode 100644 vms/avm/txs/executor/fee_calculator.go diff --git a/node/node.go b/node/node.go index 7980acb113c8..b7bb1c3b271a 100644 --- a/node/node.go +++ b/node/node.go @@ -1078,6 +1078,7 @@ func (n *Node) initVMs() error { }) durangoTime := version.GetDurangoTime(n.Config.NetworkID) + eForkTime := version.GetEForkTime(n.Config.NetworkID) if err := txs.InitCodec(durangoTime); err != nil { return err } @@ -1122,7 +1123,7 @@ func (n *Node) initVMs() error { BanffTime: version.GetBanffTime(n.Config.NetworkID), CortinaTime: version.GetCortinaTime(n.Config.NetworkID), DurangoTime: durangoTime, - EForkTime: version.GetEForkTime(n.Config.NetworkID), + EForkTime: eForkTime, UseCurrentHeight: n.Config.UseCurrentHeight, }, }), @@ -1131,6 +1132,7 @@ func (n *Node) initVMs() error { TxFee: n.Config.TxFee, CreateAssetTxFee: n.Config.CreateAssetTxFee, DurangoTime: durangoTime, + EForkTime: eForkTime, }, }), vmRegisterer.Register(context.TODO(), constants.EVMID, &coreth.Factory{}), diff --git a/vms/avm/block/executor/block.go b/vms/avm/block/executor/block.go index 8663f27ba123..4312fac9f47c 100644 --- a/vms/avm/block/executor/block.go +++ b/vms/avm/block/executor/block.go @@ -19,6 +19,7 @@ import ( "github.com/ava-labs/avalanchego/vms/avm/block" "github.com/ava-labs/avalanchego/vms/avm/state" "github.com/ava-labs/avalanchego/vms/avm/txs/executor" + "github.com/ava-labs/avalanchego/vms/platformvm/fees" ) const SyncBound = 10 * time.Second @@ -77,8 +78,10 @@ func (b *Block) Verify(context.Context) error { // before performing any possible DB reads. for _, tx := range txs { err := tx.Unsigned.Visit(&executor.SyntacticVerifier{ - Backend: b.manager.backend, - Tx: tx, + Backend: b.manager.backend, + BlkFeeManager: fees.NewManager(b.manager.backend.Config.DefaultUnitFees), + BlkTimestamp: newChainTime, + Tx: tx, }) if err != nil { txID := tx.ID() diff --git a/vms/avm/block/executor/block_test.go b/vms/avm/block/executor/block_test.go index 0b6738822c6e..c44a69389568 100644 --- a/vms/avm/block/executor/block_test.go +++ b/vms/avm/block/executor/block_test.go @@ -23,6 +23,7 @@ import ( "github.com/ava-labs/avalanchego/utils/set" "github.com/ava-labs/avalanchego/utils/timer/mockable" "github.com/ava-labs/avalanchego/vms/avm/block" + "github.com/ava-labs/avalanchego/vms/avm/config" "github.com/ava-labs/avalanchego/vms/avm/metrics" "github.com/ava-labs/avalanchego/vms/avm/state" "github.com/ava-labs/avalanchego/vms/avm/txs" @@ -46,6 +47,12 @@ func TestBlockVerify(t *testing.T) { b := &Block{ Block: mockBlock, manager: &manager{ + backend: &executor.Backend{ + Config: &config.Config{ + DurangoTime: time.Time{}, + EForkTime: mockable.MaxTime, + }, + }, blkIDToState: map[ids.ID]*blockState{}, }, } @@ -63,8 +70,15 @@ func TestBlockVerify(t *testing.T) { mockBlock.EXPECT().ID().Return(ids.Empty).AnyTimes() mockBlock.EXPECT().MerkleRoot().Return(ids.GenerateTestID()).AnyTimes() return &Block{ - Block: mockBlock, - manager: &manager{}, + Block: mockBlock, + manager: &manager{ + backend: &executor.Backend{ + Config: &config.Config{ + DurangoTime: time.Time{}, + EForkTime: mockable.MaxTime, + }, + }, + }, } }, expectedErr: ErrUnexpectedMerkleRoot, @@ -83,6 +97,12 @@ func TestBlockVerify(t *testing.T) { return &Block{ Block: mockBlock, manager: &manager{ + backend: &executor.Backend{ + Config: &config.Config{ + DurangoTime: time.Time{}, + EForkTime: mockable.MaxTime, + }, + }, clk: clk, }, } @@ -100,6 +120,12 @@ func TestBlockVerify(t *testing.T) { return &Block{ Block: mockBlock, manager: &manager{ + backend: &executor.Backend{ + Config: &config.Config{ + DurangoTime: time.Time{}, + EForkTime: mockable.MaxTime, + }, + }, blkIDToState: map[ids.ID]*blockState{}, clk: &mockable.Clock{}, }, @@ -126,6 +152,12 @@ func TestBlockVerify(t *testing.T) { return &Block{ Block: mockBlock, manager: &manager{ + backend: &executor.Backend{ + Config: &config.Config{ + DurangoTime: time.Time{}, + EForkTime: mockable.MaxTime, + }, + }, mempool: mempool, metrics: metrics.NewMockMetrics(ctrl), blkIDToState: map[ids.ID]*blockState{}, @@ -158,6 +190,12 @@ func TestBlockVerify(t *testing.T) { return &Block{ Block: mockBlock, manager: &manager{ + backend: &executor.Backend{ + Config: &config.Config{ + DurangoTime: time.Time{}, + EForkTime: mockable.MaxTime, + }, + }, state: mockState, blkIDToState: map[ids.ID]*blockState{}, clk: &mockable.Clock{}, @@ -194,6 +232,12 @@ func TestBlockVerify(t *testing.T) { return &Block{ Block: mockBlock, manager: &manager{ + backend: &executor.Backend{ + Config: &config.Config{ + DurangoTime: time.Time{}, + EForkTime: mockable.MaxTime, + }, + }, state: mockState, blkIDToState: map[ids.ID]*blockState{}, clk: &mockable.Clock{}, @@ -233,6 +277,12 @@ func TestBlockVerify(t *testing.T) { return &Block{ Block: mockBlock, manager: &manager{ + backend: &executor.Backend{ + Config: &config.Config{ + DurangoTime: time.Time{}, + EForkTime: mockable.MaxTime, + }, + }, blkIDToState: map[ids.ID]*blockState{ parentID: { onAcceptState: mockParentState, @@ -280,6 +330,12 @@ func TestBlockVerify(t *testing.T) { return &Block{ Block: mockBlock, manager: &manager{ + backend: &executor.Backend{ + Config: &config.Config{ + DurangoTime: time.Time{}, + EForkTime: mockable.MaxTime, + }, + }, mempool: mempool, metrics: metrics.NewMockMetrics(ctrl), blkIDToState: map[ids.ID]*blockState{ @@ -332,7 +388,12 @@ func TestBlockVerify(t *testing.T) { manager: &manager{ mempool: mempool, metrics: metrics.NewMockMetrics(ctrl), - backend: &executor.Backend{}, + backend: &executor.Backend{ + Config: &config.Config{ + DurangoTime: time.Time{}, + EForkTime: mockable.MaxTime, + }, + }, blkIDToState: map[ids.ID]*blockState{ parentID: { onAcceptState: mockParentState, @@ -410,7 +471,12 @@ func TestBlockVerify(t *testing.T) { manager: &manager{ mempool: mempool, metrics: metrics.NewMockMetrics(ctrl), - backend: &executor.Backend{}, + backend: &executor.Backend{ + Config: &config.Config{ + DurangoTime: time.Time{}, + EForkTime: mockable.MaxTime, + }, + }, blkIDToState: map[ids.ID]*blockState{ parentID: { onAcceptState: mockParentState, @@ -468,7 +534,12 @@ func TestBlockVerify(t *testing.T) { return &Block{ Block: mockBlock, manager: &manager{ - backend: &executor.Backend{}, + backend: &executor.Backend{ + Config: &config.Config{ + DurangoTime: time.Time{}, + EForkTime: mockable.MaxTime, + }, + }, blkIDToState: map[ids.ID]*blockState{ parentID: { onAcceptState: mockParentState, @@ -520,7 +591,12 @@ func TestBlockVerify(t *testing.T) { manager: &manager{ mempool: mockMempool, metrics: metrics.NewMockMetrics(ctrl), - backend: &executor.Backend{}, + backend: &executor.Backend{ + Config: &config.Config{ + DurangoTime: time.Time{}, + EForkTime: mockable.MaxTime, + }, + }, blkIDToState: map[ids.ID]*blockState{ parentID: { onAcceptState: mockParentState, @@ -598,6 +674,10 @@ func TestBlockAccept(t *testing.T) { Ctx: &snow.Context{ Log: logging.NoLog{}, }, + Config: &config.Config{ + DurangoTime: time.Time{}, + EForkTime: mockable.MaxTime, + }, }, blkIDToState: map[ids.ID]*blockState{}, }, @@ -632,6 +712,10 @@ func TestBlockAccept(t *testing.T) { Ctx: &snow.Context{ Log: logging.NoLog{}, }, + Config: &config.Config{ + DurangoTime: time.Time{}, + EForkTime: mockable.MaxTime, + }, }, blkIDToState: map[ids.ID]*blockState{ blockID: { @@ -676,6 +760,10 @@ func TestBlockAccept(t *testing.T) { SharedMemory: mockSharedMemory, Log: logging.NoLog{}, }, + Config: &config.Config{ + DurangoTime: time.Time{}, + EForkTime: mockable.MaxTime, + }, }, blkIDToState: map[ids.ID]*blockState{ blockID: { @@ -724,6 +812,10 @@ func TestBlockAccept(t *testing.T) { SharedMemory: mockSharedMemory, Log: logging.NoLog{}, }, + Config: &config.Config{ + DurangoTime: time.Time{}, + EForkTime: mockable.MaxTime, + }, }, blkIDToState: map[ids.ID]*blockState{ blockID: { @@ -775,6 +867,10 @@ func TestBlockAccept(t *testing.T) { SharedMemory: mockSharedMemory, Log: logging.NoLog{}, }, + Config: &config.Config{ + DurangoTime: time.Time{}, + EForkTime: mockable.MaxTime, + }, }, blkIDToState: map[ids.ID]*blockState{ blockID: { @@ -872,6 +968,10 @@ func TestBlockReject(t *testing.T) { metrics: metrics.NewMockMetrics(ctrl), backend: &executor.Backend{ Bootstrapped: true, + Config: &config.Config{ + DurangoTime: time.Time{}, + EForkTime: mockable.MaxTime, + }, Ctx: &snow.Context{ Log: logging.NoLog{}, }, @@ -933,6 +1033,10 @@ func TestBlockReject(t *testing.T) { Ctx: &snow.Context{ Log: logging.NoLog{}, }, + Config: &config.Config{ + DurangoTime: time.Time{}, + EForkTime: mockable.MaxTime, + }, }, state: mockState, blkIDToState: map[ids.ID]*blockState{ @@ -982,6 +1086,12 @@ func TestBlockStatus(t *testing.T) { return &Block{ Block: mockBlock, manager: &manager{ + backend: &executor.Backend{ + Config: &config.Config{ + DurangoTime: time.Time{}, + EForkTime: mockable.MaxTime, + }, + }, lastAccepted: blockID, }, } @@ -997,6 +1107,12 @@ func TestBlockStatus(t *testing.T) { return &Block{ Block: mockBlock, manager: &manager{ + backend: &executor.Backend{ + Config: &config.Config{ + DurangoTime: time.Time{}, + EForkTime: mockable.MaxTime, + }, + }, blkIDToState: map[ids.ID]*blockState{ blockID: {}, }, @@ -1018,6 +1134,12 @@ func TestBlockStatus(t *testing.T) { return &Block{ Block: mockBlock, manager: &manager{ + backend: &executor.Backend{ + Config: &config.Config{ + DurangoTime: time.Time{}, + EForkTime: mockable.MaxTime, + }, + }, blkIDToState: map[ids.ID]*blockState{}, state: mockState, }, @@ -1038,6 +1160,12 @@ func TestBlockStatus(t *testing.T) { return &Block{ Block: mockBlock, manager: &manager{ + backend: &executor.Backend{ + Config: &config.Config{ + DurangoTime: time.Time{}, + EForkTime: mockable.MaxTime, + }, + }, blkIDToState: map[ids.ID]*blockState{}, state: mockState, }, diff --git a/vms/avm/block/executor/manager.go b/vms/avm/block/executor/manager.go index 9822743b7fd3..f9ad014f9eb8 100644 --- a/vms/avm/block/executor/manager.go +++ b/vms/avm/block/executor/manager.go @@ -17,6 +17,7 @@ import ( "github.com/ava-labs/avalanchego/vms/avm/txs" "github.com/ava-labs/avalanchego/vms/avm/txs/executor" "github.com/ava-labs/avalanchego/vms/avm/txs/mempool" + "github.com/ava-labs/avalanchego/vms/platformvm/fees" ) var ( @@ -148,8 +149,10 @@ func (m *manager) VerifyTx(tx *txs.Tx) error { } err := tx.Unsigned.Visit(&executor.SyntacticVerifier{ - Backend: m.backend, - Tx: tx, + Backend: m.backend, + BlkFeeManager: fees.NewManager(m.backend.Config.DefaultUnitFees), + BlkTimestamp: m.state.GetTimestamp(), + Tx: tx, }) if err != nil { return err diff --git a/vms/avm/block/executor/manager_test.go b/vms/avm/block/executor/manager_test.go index 012428d582e4..de09f434d904 100644 --- a/vms/avm/block/executor/manager_test.go +++ b/vms/avm/block/executor/manager_test.go @@ -14,7 +14,9 @@ import ( "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils/set" + "github.com/ava-labs/avalanchego/utils/timer/mockable" "github.com/ava-labs/avalanchego/vms/avm/block" + "github.com/ava-labs/avalanchego/vms/avm/config" "github.com/ava-labs/avalanchego/vms/avm/state" "github.com/ava-labs/avalanchego/vms/avm/txs" "github.com/ava-labs/avalanchego/vms/avm/txs/executor" @@ -124,7 +126,12 @@ func TestManagerVerifyTx(t *testing.T) { }, managerF: func(ctrl *gomock.Controller) *manager { return &manager{ - backend: &executor.Backend{}, + backend: &executor.Backend{ + Config: &config.Config{ + DurangoTime: time.Time{}, + EForkTime: mockable.MaxTime, + }, + }, } }, expectedErr: ErrChainNotSynced, @@ -138,11 +145,18 @@ func TestManagerVerifyTx(t *testing.T) { Unsigned: unsigned, } }, - managerF: func(*gomock.Controller) *manager { + managerF: func(ctrl *gomock.Controller) *manager { + state := state.NewMockState(ctrl) + state.EXPECT().GetTimestamp().Return(time.Time{}) return &manager{ backend: &executor.Backend{ Bootstrapped: true, + Config: &config.Config{ + DurangoTime: time.Time{}, + EForkTime: mockable.MaxTime, + }, }, + state: state, } }, expectedErr: errTestSyntacticVerifyFail, @@ -165,11 +179,15 @@ func TestManagerVerifyTx(t *testing.T) { // These values don't matter for this test state := state.NewMockState(ctrl) state.EXPECT().GetLastAccepted().Return(lastAcceptedID) - state.EXPECT().GetTimestamp().Return(time.Time{}) + state.EXPECT().GetTimestamp().Return(time.Time{}).Times(2) return &manager{ backend: &executor.Backend{ Bootstrapped: true, + Config: &config.Config{ + DurangoTime: time.Time{}, + EForkTime: mockable.MaxTime, + }, }, state: state, lastAccepted: lastAcceptedID, @@ -197,11 +215,15 @@ func TestManagerVerifyTx(t *testing.T) { // These values don't matter for this test state := state.NewMockState(ctrl) state.EXPECT().GetLastAccepted().Return(lastAcceptedID) - state.EXPECT().GetTimestamp().Return(time.Time{}) + state.EXPECT().GetTimestamp().Return(time.Time{}).Times(2) return &manager{ backend: &executor.Backend{ Bootstrapped: true, + Config: &config.Config{ + DurangoTime: time.Time{}, + EForkTime: mockable.MaxTime, + }, }, state: state, lastAccepted: lastAcceptedID, @@ -229,11 +251,15 @@ func TestManagerVerifyTx(t *testing.T) { // These values don't matter for this test state := state.NewMockState(ctrl) state.EXPECT().GetLastAccepted().Return(lastAcceptedID) - state.EXPECT().GetTimestamp().Return(time.Time{}) + state.EXPECT().GetTimestamp().Return(time.Time{}).Times(2) return &manager{ backend: &executor.Backend{ Bootstrapped: true, + Config: &config.Config{ + DurangoTime: time.Time{}, + EForkTime: mockable.MaxTime, + }, }, state: state, lastAccepted: lastAcceptedID, diff --git a/vms/avm/config/config.go b/vms/avm/config/config.go index df6e4f7de2ae..799f9a720e00 100644 --- a/vms/avm/config/config.go +++ b/vms/avm/config/config.go @@ -3,7 +3,12 @@ package config -import "time" +import ( + "math" + "time" + + "github.com/ava-labs/avalanchego/vms/platformvm/fees" +) // Struct collecting all the foundational parameters of the AVM type Config struct { @@ -13,6 +18,32 @@ type Config struct { // Fee that must be burned by every asset creating transaction CreateAssetTxFee uint64 + // Post E Fork, the unit fee for each dimension, denominated in Avax + // As long as fees are multidimensional but not dynamic, [DefaultUnitFees] + // will be the unit fees + DefaultUnitFees fees.Dimensions + + // Post E Fork, the max complexity of a block for each dimension + DefaultBlockMaxConsumedUnits fees.Dimensions + // Time of the Durango network upgrade DurangoTime time.Time + + // Time of the E network upgrade + EForkTime time.Time +} + +func (c *Config) IsEForkActivated(timestamp time.Time) bool { + return !timestamp.Before(c.EForkTime) +} + +func (c *Config) BlockMaxConsumedUnits(timestamp time.Time) fees.Dimensions { + if !c.IsEForkActivated(timestamp) { + var res fees.Dimensions + for i := fees.Dimension(0); i < fees.FeeDimensions; i++ { + res[i] = math.MaxUint64 + } + return res + } + return c.DefaultBlockMaxConsumedUnits } diff --git a/vms/avm/environment_test.go b/vms/avm/environment_test.go index 236c20875796..00a1b2725e47 100644 --- a/vms/avm/environment_test.go +++ b/vms/avm/environment_test.go @@ -29,6 +29,7 @@ import ( "github.com/ava-labs/avalanchego/utils/linkedhashmap" "github.com/ava-labs/avalanchego/utils/logging" "github.com/ava-labs/avalanchego/utils/sampler" + "github.com/ava-labs/avalanchego/utils/timer/mockable" "github.com/ava-labs/avalanchego/vms/avm/block/executor" "github.com/ava-labs/avalanchego/vms/avm/config" "github.com/ava-labs/avalanchego/vms/avm/fxs" @@ -149,6 +150,8 @@ func setup(tb testing.TB, c *envConfig) *environment { vmStaticConfig := config.Config{ TxFee: testTxFee, CreateAssetTxFee: testTxFee, + DurangoTime: time.Time{}, + EForkTime: mockable.MaxTime, } if c.vmStaticConfig != nil { vmStaticConfig = *c.vmStaticConfig diff --git a/vms/avm/index_test.go b/vms/avm/index_test.go index 03a2fd863c6a..642410951c9e 100644 --- a/vms/avm/index_test.go +++ b/vms/avm/index_test.go @@ -6,6 +6,7 @@ package avm import ( "context" "testing" + "time" "github.com/prometheus/client_golang/prometheus" @@ -20,6 +21,7 @@ import ( "github.com/ava-labs/avalanchego/utils/constants" "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" "github.com/ava-labs/avalanchego/utils/logging" + "github.com/ava-labs/avalanchego/utils/timer/mockable" "github.com/ava-labs/avalanchego/vms/avm/config" "github.com/ava-labs/avalanchego/vms/avm/txs" "github.com/ava-labs/avalanchego/vms/components/avax" @@ -31,7 +33,10 @@ func TestIndexTransaction_Ordered(t *testing.T) { require := require.New(t) env := setup(t, &envConfig{ - vmStaticConfig: &config.Config{}, + vmStaticConfig: &config.Config{ + DurangoTime: time.Time{}, + EForkTime: mockable.MaxTime, + }, }) defer func() { require.NoError(env.vm.Shutdown(context.Background())) @@ -75,7 +80,10 @@ func TestIndexTransaction_MultipleTransactions(t *testing.T) { require := require.New(t) env := setup(t, &envConfig{ - vmStaticConfig: &config.Config{}, + vmStaticConfig: &config.Config{ + DurangoTime: time.Time{}, + EForkTime: mockable.MaxTime, + }, }) defer func() { require.NoError(env.vm.Shutdown(context.Background())) @@ -123,7 +131,10 @@ func TestIndexTransaction_MultipleAddresses(t *testing.T) { require := require.New(t) env := setup(t, &envConfig{ - vmStaticConfig: &config.Config{}, + vmStaticConfig: &config.Config{ + DurangoTime: time.Time{}, + EForkTime: mockable.MaxTime, + }, }) defer func() { require.NoError(env.vm.Shutdown(context.Background())) diff --git a/vms/avm/service_test.go b/vms/avm/service_test.go index c659b8e9de9e..62f81d08f48c 100644 --- a/vms/avm/service_test.go +++ b/vms/avm/service_test.go @@ -34,6 +34,7 @@ import ( "github.com/ava-labs/avalanchego/utils/formatting/address" "github.com/ava-labs/avalanchego/utils/json" "github.com/ava-labs/avalanchego/utils/logging" + "github.com/ava-labs/avalanchego/utils/timer/mockable" "github.com/ava-labs/avalanchego/vms/avm/block" "github.com/ava-labs/avalanchego/vms/avm/block/executor" "github.com/ava-labs/avalanchego/vms/avm/config" @@ -703,7 +704,10 @@ func TestServiceGetTxJSON_CreateAssetTx(t *testing.T) { require := require.New(t) env := setup(t, &envConfig{ - vmStaticConfig: &config.Config{}, + vmStaticConfig: &config.Config{ + DurangoTime: time.Time{}, + EForkTime: mockable.MaxTime, + }, additionalFxs: []*common.Fx{{ ID: propertyfx.ID, Fx: &propertyfx.Fx{}, @@ -819,7 +823,10 @@ func TestServiceGetTxJSON_OperationTxWithNftxMintOp(t *testing.T) { require := require.New(t) env := setup(t, &envConfig{ - vmStaticConfig: &config.Config{}, + vmStaticConfig: &config.Config{ + DurangoTime: time.Time{}, + EForkTime: mockable.MaxTime, + }, additionalFxs: []*common.Fx{{ ID: propertyfx.ID, Fx: &propertyfx.Fx{}, @@ -918,7 +925,10 @@ func TestServiceGetTxJSON_OperationTxWithMultipleNftxMintOp(t *testing.T) { require := require.New(t) env := setup(t, &envConfig{ - vmStaticConfig: &config.Config{}, + vmStaticConfig: &config.Config{ + DurangoTime: time.Time{}, + EForkTime: mockable.MaxTime, + }, additionalFxs: []*common.Fx{{ ID: propertyfx.ID, Fx: &propertyfx.Fx{}, @@ -1056,7 +1066,10 @@ func TestServiceGetTxJSON_OperationTxWithSecpMintOp(t *testing.T) { require := require.New(t) env := setup(t, &envConfig{ - vmStaticConfig: &config.Config{}, + vmStaticConfig: &config.Config{ + DurangoTime: time.Time{}, + EForkTime: mockable.MaxTime, + }, additionalFxs: []*common.Fx{{ ID: propertyfx.ID, Fx: &propertyfx.Fx{}, @@ -1159,7 +1172,10 @@ func TestServiceGetTxJSON_OperationTxWithMultipleSecpMintOp(t *testing.T) { require := require.New(t) env := setup(t, &envConfig{ - vmStaticConfig: &config.Config{}, + vmStaticConfig: &config.Config{ + DurangoTime: time.Time{}, + EForkTime: mockable.MaxTime, + }, additionalFxs: []*common.Fx{{ ID: propertyfx.ID, Fx: &propertyfx.Fx{}, @@ -1305,7 +1321,10 @@ func TestServiceGetTxJSON_OperationTxWithPropertyFxMintOp(t *testing.T) { require := require.New(t) env := setup(t, &envConfig{ - vmStaticConfig: &config.Config{}, + vmStaticConfig: &config.Config{ + DurangoTime: time.Time{}, + EForkTime: mockable.MaxTime, + }, additionalFxs: []*common.Fx{{ ID: propertyfx.ID, Fx: &propertyfx.Fx{}, @@ -1405,7 +1424,10 @@ func TestServiceGetTxJSON_OperationTxWithPropertyFxMintOpMultiple(t *testing.T) require := require.New(t) env := setup(t, &envConfig{ - vmStaticConfig: &config.Config{}, + vmStaticConfig: &config.Config{ + DurangoTime: time.Time{}, + EForkTime: mockable.MaxTime, + }, additionalFxs: []*common.Fx{{ ID: propertyfx.ID, Fx: &propertyfx.Fx{}, diff --git a/vms/avm/txs/executor/fee_calculator.go b/vms/avm/txs/executor/fee_calculator.go new file mode 100644 index 000000000000..741fdbd21eff --- /dev/null +++ b/vms/avm/txs/executor/fee_calculator.go @@ -0,0 +1,169 @@ +// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package executor + +import ( + "errors" + "fmt" + "time" + + "github.com/ava-labs/avalanchego/codec" + "github.com/ava-labs/avalanchego/vms/avm/config" + "github.com/ava-labs/avalanchego/vms/avm/txs" + "github.com/ava-labs/avalanchego/vms/components/avax" + "github.com/ava-labs/avalanchego/vms/platformvm/fees" +) + +var ( + _ txs.Visitor = (*FeeCalculator)(nil) + + errFailedFeeCalculation = errors.New("failed fee calculation") + errFailedConsumedUnitsCumulation = errors.New("failed cumulating consumed units") +) + +type FeeCalculator struct { + // setup, to be filled before visitor methods are called + feeManager *fees.Manager + Codec codec.Manager + Config *config.Config + ChainTime time.Time + + // inputs, to be filled before visitor methods are called + Tx *txs.Tx + + // outputs of visitor execution + Fee uint64 +} + +func (fc *FeeCalculator) BaseTx(tx *txs.BaseTx) error { + if !fc.Config.IsEForkActivated(fc.ChainTime) { + fc.Fee = fc.Config.TxFee + return nil + } + + consumedUnits, err := commonConsumedUnits(fc.Codec, fc.Tx, tx.Outs, tx.Ins) + if err != nil { + return err + } + + fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) + return err +} + +func (fc *FeeCalculator) CreateAssetTx(tx *txs.CreateAssetTx) error { + if !fc.Config.IsEForkActivated(fc.ChainTime) { + fc.Fee = fc.Config.CreateAssetTxFee + return nil + } + + consumedUnits, err := commonConsumedUnits(fc.Codec, fc.Tx, tx.Outs, tx.Ins) + if err != nil { + return err + } + + fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) + return err +} + +func (fc *FeeCalculator) OperationTx(tx *txs.OperationTx) error { + if !fc.Config.IsEForkActivated(fc.ChainTime) { + fc.Fee = fc.Config.TxFee + return nil + } + + consumedUnits, err := commonConsumedUnits(fc.Codec, fc.Tx, tx.Outs, tx.Ins) + if err != nil { + return err + } + + fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) + return err +} + +func (fc *FeeCalculator) ImportTx(tx *txs.ImportTx) error { + if !fc.Config.IsEForkActivated(fc.ChainTime) { + fc.Fee = fc.Config.TxFee + return nil + } + + consumedUnits, err := commonConsumedUnits(fc.Codec, fc.Tx, tx.Outs, tx.Ins) + if err != nil { + return err + } + + fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) + return err +} + +func (fc *FeeCalculator) ExportTx(tx *txs.ExportTx) error { + if !fc.Config.IsEForkActivated(fc.ChainTime) { + fc.Fee = fc.Config.TxFee + return nil + } + + consumedUnits, err := commonConsumedUnits(fc.Codec, fc.Tx, tx.Outs, tx.Ins) + if err != nil { + return err + } + + fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) + return err +} + +func commonConsumedUnits( + codec codec.Manager, + sTx *txs.Tx, + allOuts []*avax.TransferableOutput, + allIns []*avax.TransferableInput, +) (fees.Dimensions, error) { + var consumedUnits fees.Dimensions + consumedUnits[fees.Bandwidth] = uint64(len(sTx.Bytes())) + + // TODO ABENEGIA: consider handling imports/exports differently + var ( + insCost uint64 + insSize uint64 + outsSize uint64 + ) + + for _, in := range allIns { + cost, err := in.In.Cost() + if err != nil { + return consumedUnits, fmt.Errorf("failed retrieving cost of input %s: %w", in.ID, err) + } + insCost += cost + + inSize, err := codec.Size(txs.CodecVersion, in) + if err != nil { + return consumedUnits, fmt.Errorf("failed retrieving size of input %s: %w", in.ID, err) + } + insSize += uint64(inSize) + } + + for _, out := range allOuts { + outSize, err := codec.Size(txs.CodecVersion, out) + if err != nil { + return consumedUnits, fmt.Errorf("failed retrieving size of output %s: %w", out.ID, err) + } + outsSize += uint64(outSize) + } + + consumedUnits[fees.UTXORead] = insCost + insSize // inputs are read + consumedUnits[fees.UTXOWrite] = insSize + outsSize // inputs are deleted, outputs are created + return consumedUnits, nil +} + +func processFees(cfg *config.Config, chainTime time.Time, fc *fees.Manager, consumedUnits fees.Dimensions) (uint64, error) { + boundBreached, dimension := fc.CumulateUnits(consumedUnits, cfg.BlockMaxConsumedUnits(chainTime)) + if boundBreached { + return 0, fmt.Errorf("%w: breached dimension %d", errFailedConsumedUnitsCumulation, dimension) + } + + fee, err := fc.CalculateFee(consumedUnits) + if err != nil { + return 0, fmt.Errorf("%w: %w", errFailedFeeCalculation, err) + } + + return fee, nil +} diff --git a/vms/avm/txs/executor/syntactic_verifier.go b/vms/avm/txs/executor/syntactic_verifier.go index 81a2f2a715f4..2c9adafb6d06 100644 --- a/vms/avm/txs/executor/syntactic_verifier.go +++ b/vms/avm/txs/executor/syntactic_verifier.go @@ -7,6 +7,7 @@ import ( "errors" "fmt" "strings" + "time" "unicode" "github.com/ava-labs/avalanchego/ids" @@ -14,6 +15,7 @@ import ( "github.com/ava-labs/avalanchego/utils/set" "github.com/ava-labs/avalanchego/vms/avm/txs" "github.com/ava-labs/avalanchego/vms/components/avax" + "github.com/ava-labs/avalanchego/vms/platformvm/fees" ) const ( @@ -47,7 +49,9 @@ var ( type SyntacticVerifier struct { *Backend - Tx *txs.Tx + BlkFeeManager *fees.Manager + BlkTimestamp time.Time + Tx *txs.Tx } func (v *SyntacticVerifier) BaseTx(tx *txs.BaseTx) error { @@ -55,8 +59,18 @@ func (v *SyntacticVerifier) BaseTx(tx *txs.BaseTx) error { return err } + feeCalculator := FeeCalculator{ + feeManager: v.BlkFeeManager, + Config: v.Config, + ChainTime: v.BlkTimestamp, + Tx: v.Tx, + } + if err := tx.Visit(&feeCalculator); err != nil { + return err + } + err := avax.VerifyTx( - v.Config.TxFee, + feeCalculator.Fee, v.FeeAssetID, [][]*avax.TransferableInput{tx.Ins}, [][]*avax.TransferableOutput{tx.Outs}, @@ -118,8 +132,18 @@ func (v *SyntacticVerifier) CreateAssetTx(tx *txs.CreateAssetTx) error { return err } + feeCalculator := FeeCalculator{ + feeManager: v.BlkFeeManager, + Config: v.Config, + ChainTime: v.BlkTimestamp, + Tx: v.Tx, + } + if err := tx.Visit(&feeCalculator); err != nil { + return err + } + err := avax.VerifyTx( - v.Config.CreateAssetTxFee, + feeCalculator.Fee, v.FeeAssetID, [][]*avax.TransferableInput{tx.Ins}, [][]*avax.TransferableOutput{tx.Outs}, @@ -166,8 +190,18 @@ func (v *SyntacticVerifier) OperationTx(tx *txs.OperationTx) error { return err } + feeCalculator := FeeCalculator{ + feeManager: v.BlkFeeManager, + Config: v.Config, + ChainTime: v.BlkTimestamp, + Tx: v.Tx, + } + if err := tx.Visit(&feeCalculator); err != nil { + return err + } + err := avax.VerifyTx( - v.Config.TxFee, + feeCalculator.Fee, v.FeeAssetID, [][]*avax.TransferableInput{tx.Ins}, [][]*avax.TransferableOutput{tx.Outs}, @@ -226,8 +260,18 @@ func (v *SyntacticVerifier) ImportTx(tx *txs.ImportTx) error { return err } + feeCalculator := FeeCalculator{ + feeManager: v.BlkFeeManager, + Config: v.Config, + ChainTime: v.BlkTimestamp, + Tx: v.Tx, + } + if err := tx.Visit(&feeCalculator); err != nil { + return err + } + err := avax.VerifyTx( - v.Config.TxFee, + feeCalculator.Fee, v.FeeAssetID, [][]*avax.TransferableInput{ tx.Ins, @@ -268,8 +312,18 @@ func (v *SyntacticVerifier) ExportTx(tx *txs.ExportTx) error { return err } + feeCalculator := FeeCalculator{ + feeManager: v.BlkFeeManager, + Config: v.Config, + ChainTime: v.BlkTimestamp, + Tx: v.Tx, + } + if err := tx.Visit(&feeCalculator); err != nil { + return err + } + err := avax.VerifyTx( - v.Config.TxFee, + feeCalculator.Fee, v.FeeAssetID, [][]*avax.TransferableInput{tx.Ins}, [][]*avax.TransferableOutput{ diff --git a/vms/avm/txs/executor/syntactic_verifier_test.go b/vms/avm/txs/executor/syntactic_verifier_test.go index 108ac9e94a60..3b5c05d42d07 100644 --- a/vms/avm/txs/executor/syntactic_verifier_test.go +++ b/vms/avm/txs/executor/syntactic_verifier_test.go @@ -15,6 +15,7 @@ import ( "github.com/ava-labs/avalanchego/snow/snowtest" "github.com/ava-labs/avalanchego/utils/constants" "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" + "github.com/ava-labs/avalanchego/utils/timer/mockable" "github.com/ava-labs/avalanchego/vms/avm/config" "github.com/ava-labs/avalanchego/vms/avm/fxs" "github.com/ava-labs/avalanchego/vms/avm/txs" @@ -30,6 +31,8 @@ var ( feeConfig = config.Config{ TxFee: 2, CreateAssetTxFee: 3, + DurangoTime: time.Time{}, + EForkTime: mockable.MaxTime, } ) diff --git a/vms/avm/vm.go b/vms/avm/vm.go index 59907c934e91..55cd94e965fb 100644 --- a/vms/avm/vm.go +++ b/vms/avm/vm.go @@ -44,6 +44,7 @@ import ( "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/components/index" "github.com/ava-labs/avalanchego/vms/components/keystore" + "github.com/ava-labs/avalanchego/vms/platformvm/fees" "github.com/ava-labs/avalanchego/vms/secp256k1fx" blockbuilder "github.com/ava-labs/avalanchego/vms/avm/block/builder" @@ -501,8 +502,10 @@ func (vm *VM) ParseTx(_ context.Context, bytes []byte) (snowstorm.Tx, error) { } err = tx.Unsigned.Visit(&txexecutor.SyntacticVerifier{ - Backend: vm.txBackend, - Tx: tx, + Backend: vm.txBackend, + BlkFeeManager: fees.NewManager(vm.Config.DefaultUnitFees), + BlkTimestamp: vm.state.GetTimestamp(), + Tx: tx, }) if err != nil { return nil, err diff --git a/vms/avm/vm_regression_test.go b/vms/avm/vm_regression_test.go index c6ac40df845d..1e4720f80fe1 100644 --- a/vms/avm/vm_regression_test.go +++ b/vms/avm/vm_regression_test.go @@ -6,12 +6,14 @@ package avm import ( "context" "testing" + "time" "github.com/stretchr/testify/require" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils/constants" "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" + "github.com/ava-labs/avalanchego/utils/timer/mockable" "github.com/ava-labs/avalanchego/vms/avm/config" "github.com/ava-labs/avalanchego/vms/avm/txs" "github.com/ava-labs/avalanchego/vms/components/avax" @@ -24,7 +26,10 @@ func TestVerifyFxUsage(t *testing.T) { require := require.New(t) env := setup(t, &envConfig{ - vmStaticConfig: &config.Config{}, + vmStaticConfig: &config.Config{ + DurangoTime: time.Time{}, + EForkTime: mockable.MaxTime, + }, }) env.vm.ctx.Lock.Unlock() defer func() { diff --git a/vms/avm/vm_test.go b/vms/avm/vm_test.go index d8aeaf3b8743..f7c7d11af0ea 100644 --- a/vms/avm/vm_test.go +++ b/vms/avm/vm_test.go @@ -7,6 +7,7 @@ import ( "context" "math" "testing" + "time" "github.com/stretchr/testify/require" @@ -19,6 +20,7 @@ import ( "github.com/ava-labs/avalanchego/snow/snowtest" "github.com/ava-labs/avalanchego/utils/constants" "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" + "github.com/ava-labs/avalanchego/utils/timer/mockable" "github.com/ava-labs/avalanchego/vms/avm/config" "github.com/ava-labs/avalanchego/vms/avm/fxs" "github.com/ava-labs/avalanchego/vms/avm/txs" @@ -132,7 +134,10 @@ func TestIssueNFT(t *testing.T) { require := require.New(t) env := setup(t, &envConfig{ - vmStaticConfig: &config.Config{}, + vmStaticConfig: &config.Config{ + DurangoTime: time.Time{}, + EForkTime: mockable.MaxTime, + }, }) env.vm.ctx.Lock.Unlock() defer func() { @@ -233,7 +238,10 @@ func TestIssueProperty(t *testing.T) { require := require.New(t) env := setup(t, &envConfig{ - vmStaticConfig: &config.Config{}, + vmStaticConfig: &config.Config{ + DurangoTime: time.Time{}, + EForkTime: mockable.MaxTime, + }, additionalFxs: []*common.Fx{{ ID: propertyfx.ID, Fx: &propertyfx.Fx{}, @@ -520,7 +528,10 @@ func TestIssueImportTx(t *testing.T) { require := require.New(t) env := setup(t, &envConfig{ - vmStaticConfig: &config.Config{}, + vmStaticConfig: &config.Config{ + DurangoTime: time.Time{}, + EForkTime: mockable.MaxTime, + }, }) defer func() { require.NoError(env.vm.Shutdown(context.Background())) @@ -620,8 +631,11 @@ func TestForceAcceptImportTx(t *testing.T) { require := require.New(t) env := setup(t, &envConfig{ - vmStaticConfig: &config.Config{}, - notLinearized: true, + vmStaticConfig: &config.Config{ + DurangoTime: time.Time{}, + EForkTime: mockable.MaxTime, + }, + notLinearized: true, }) defer func() { require.NoError(env.vm.Shutdown(context.Background())) From 136c81210c20ba6e5ddc4cea5bb573495d295c52 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Wed, 10 Jan 2024 09:36:01 +0100 Subject: [PATCH 020/190] fixed avm fee manager --- vms/avm/block/executor/block.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vms/avm/block/executor/block.go b/vms/avm/block/executor/block.go index 4312fac9f47c..678ef54189b0 100644 --- a/vms/avm/block/executor/block.go +++ b/vms/avm/block/executor/block.go @@ -76,10 +76,11 @@ func (b *Block) Verify(context.Context) error { // Syntactic verification is generally pretty fast, so we verify this first // before performing any possible DB reads. + feeManager := fees.NewManager(b.manager.backend.Config.DefaultUnitFees) for _, tx := range txs { err := tx.Unsigned.Visit(&executor.SyntacticVerifier{ Backend: b.manager.backend, - BlkFeeManager: fees.NewManager(b.manager.backend.Config.DefaultUnitFees), + BlkFeeManager: feeManager, BlkTimestamp: newChainTime, Tx: tx, }) From fbf219f89a2658261f2c893139f80c3ca2513f0b Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Wed, 10 Jan 2024 10:22:26 +0100 Subject: [PATCH 021/190] added avm UTs for fee calculator --- vms/avm/txs/executor/fee_calculator_test.go | 652 ++++++++++++++++++++ vms/avm/txs/executor/syntactic_verifier.go | 5 + 2 files changed, 657 insertions(+) create mode 100644 vms/avm/txs/executor/fee_calculator_test.go diff --git a/vms/avm/txs/executor/fee_calculator_test.go b/vms/avm/txs/executor/fee_calculator_test.go new file mode 100644 index 000000000000..4b500ad61caa --- /dev/null +++ b/vms/avm/txs/executor/fee_calculator_test.go @@ -0,0 +1,652 @@ +// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package executor + +import ( + "reflect" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/ava-labs/avalanchego/codec" + "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/snow" + "github.com/ava-labs/avalanchego/snow/snowtest" + "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" + "github.com/ava-labs/avalanchego/utils/timer/mockable" + "github.com/ava-labs/avalanchego/utils/units" + "github.com/ava-labs/avalanchego/vms/avm/block" + "github.com/ava-labs/avalanchego/vms/avm/config" + "github.com/ava-labs/avalanchego/vms/avm/fxs" + "github.com/ava-labs/avalanchego/vms/avm/txs" + "github.com/ava-labs/avalanchego/vms/components/avax" + "github.com/ava-labs/avalanchego/vms/components/verify" + "github.com/ava-labs/avalanchego/vms/nftfx" + "github.com/ava-labs/avalanchego/vms/platformvm/fees" + "github.com/ava-labs/avalanchego/vms/secp256k1fx" +) + +var ( + feeTestsDefaultCfg = config.Config{ + DefaultUnitFees: fees.Dimensions{ + 1 * units.MicroAvax, + 2 * units.MicroAvax, + 3 * units.MicroAvax, + 4 * units.MicroAvax, + }, + DefaultBlockMaxConsumedUnits: fees.Dimensions{ + 3000, + 3500, + 1000, + 1000, + }, + + TxFee: 1 * units.Avax, + CreateAssetTxFee: 2 * units.Avax, + } + + feeTestKeys = secp256k1.TestKeys() + feeTestSigners = [][]*secp256k1.PrivateKey{} + + durangoTime = time.Time{} // assume durango is active in these tests +) + +type feeTests struct { + description string + cfgAndChainTimeF func() (*config.Config, time.Time) + expectedError error + checksF func(*testing.T, *FeeCalculator) +} + +func TestBaseTxFees(t *testing.T) { + r := require.New(t) + + defaultCtx := snowtest.Context(t, snowtest.PChainID) + codec, err := createTestFeesCodec(defaultCtx) + r.NoError(err) + + baseTx, _ := txsCreationHelpers(defaultCtx) + uTx := &baseTx + sTx := &txs.Tx{ + Unsigned: uTx, + } + r.NoError(sTx.SignSECP256K1Fx(codec, feeTestSigners)) + + tests := []feeTests{ + { + description: "pre E fork", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(-1 * time.Second) + + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime + + return &cfg, chainTime + }, + expectedError: nil, + checksF: func(t *testing.T, fc *FeeCalculator) { + require.Equal(t, fc.Config.TxFee, fc.Fee) + }, + }, + { + description: "post E fork, success", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(time.Second) + + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime + + return &cfg, chainTime + }, + expectedError: nil, + checksF: func(t *testing.T, fc *FeeCalculator) { + require.Equal(t, 2922*units.MicroAvax, fc.Fee) + require.Equal(t, + fees.Dimensions{ + uint64(len(sTx.Bytes())), + 1090, + 172, + 0, + }, + fc.feeManager.GetCumulatedUnits(), + ) + }, + }, + { + description: "post E fork, utxos read cap breached", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(time.Second) + + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime + cfg.DefaultBlockMaxConsumedUnits[1] = 1090 - 1 + + return &cfg, chainTime + }, + expectedError: errFailedConsumedUnitsCumulation, + checksF: func(t *testing.T, fc *FeeCalculator) {}, + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + cfg, chainTime := tt.cfgAndChainTimeF() + + fc := &FeeCalculator{ + feeManager: fees.NewManager(cfg.DefaultUnitFees), + Codec: codec, + Config: cfg, + ChainTime: chainTime, + Tx: sTx, + } + err := uTx.Visit(fc) + r.ErrorIs(err, tt.expectedError) + tt.checksF(t, fc) + }) + } +} + +func TestCreateAssetTxFees(t *testing.T) { + r := require.New(t) + + defaultCtx := snowtest.Context(t, snowtest.PChainID) + codec, err := createTestFeesCodec(defaultCtx) + r.NoError(err) + + baseTx, _ := txsCreationHelpers(defaultCtx) + uTx := &txs.CreateAssetTx{ + BaseTx: baseTx, + Name: "name", + Symbol: "symb", + Denomination: 0, + States: []*txs.InitialState{ + { + FxIndex: 0, + Outs: []verify.State{ + &secp256k1fx.MintOutput{ + OutputOwners: secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{keys[0].PublicKey().Address()}, + }, + }, + }, + }, + }, + } + sTx := &txs.Tx{ + Unsigned: uTx, + } + r.NoError(sTx.SignSECP256K1Fx(codec, feeTestSigners)) + + tests := []feeTests{ + { + description: "pre E fork", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(-1 * time.Second) + + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime + + return &cfg, chainTime + }, + expectedError: nil, + checksF: func(t *testing.T, fc *FeeCalculator) { + require.Equal(t, fc.Config.CreateAssetTxFee, fc.Fee) + }, + }, + { + description: "post E fork, success", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(time.Second) + + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime + + return &cfg, chainTime + }, + expectedError: nil, + checksF: func(t *testing.T, fc *FeeCalculator) { + require.Equal(t, 2987*units.MicroAvax, fc.Fee) + require.Equal(t, + fees.Dimensions{ + uint64(len(sTx.Bytes())), + 1090, + 172, + 0, + }, + fc.feeManager.GetCumulatedUnits(), + ) + }, + }, + { + description: "post E fork, bandwidth cap breached", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(time.Second) + + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime + cfg.DefaultBlockMaxConsumedUnits[0] = uint64(len(sTx.Bytes())) - 1 + + return &cfg, chainTime + }, + expectedError: errFailedConsumedUnitsCumulation, + checksF: func(t *testing.T, fc *FeeCalculator) {}, + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + cfg, chainTime := tt.cfgAndChainTimeF() + + fc := &FeeCalculator{ + feeManager: fees.NewManager(cfg.DefaultUnitFees), + Codec: codec, + Config: cfg, + ChainTime: chainTime, + Tx: sTx, + } + err := uTx.Visit(fc) + r.ErrorIs(err, tt.expectedError) + tt.checksF(t, fc) + }) + } +} + +func TestOperationTxFees(t *testing.T) { + r := require.New(t) + + defaultCtx := snowtest.Context(t, snowtest.PChainID) + codec, err := createTestFeesCodec(defaultCtx) + r.NoError(err) + + baseTx, _ := txsCreationHelpers(defaultCtx) + assetID := ids.GenerateTestID() + uTx := &txs.OperationTx{ + BaseTx: baseTx, + Ops: []*txs.Operation{{ + Asset: avax.Asset{ID: assetID}, + UTXOIDs: []*avax.UTXOID{{ + TxID: assetID, + OutputIndex: 1, + }}, + Op: &nftfx.MintOperation{ + MintInput: secp256k1fx.Input{ + SigIndices: []uint32{0}, + }, + GroupID: 1, + Payload: []byte{'h', 'e', 'l', 'l', 'o'}, + Outputs: []*secp256k1fx.OutputOwners{{}}, + }, + }}, + } + sTx := &txs.Tx{ + Unsigned: uTx, + } + r.NoError(sTx.SignSECP256K1Fx(codec, feeTestSigners)) + + tests := []feeTests{ + { + description: "pre E fork", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(-1 * time.Second) + + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime + + return &cfg, chainTime + }, + expectedError: nil, + checksF: func(t *testing.T, fc *FeeCalculator) { + require.Equal(t, fc.Config.TxFee, fc.Fee) + }, + }, + { + description: "post E fork, success", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(time.Second) + + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime + + return &cfg, chainTime + }, + expectedError: nil, + checksF: func(t *testing.T, fc *FeeCalculator) { + require.Equal(t, 3043*units.MicroAvax, fc.Fee) + require.Equal(t, + fees.Dimensions{ + uint64(len(sTx.Bytes())), + 1090, + 172, + 0, + }, + fc.feeManager.GetCumulatedUnits(), + ) + }, + }, + { + description: "post E fork, utxos read cap breached", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(time.Second) + + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime + cfg.DefaultBlockMaxConsumedUnits[1] = 1090 - 1 + + return &cfg, chainTime + }, + expectedError: errFailedConsumedUnitsCumulation, + checksF: func(t *testing.T, fc *FeeCalculator) {}, + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + cfg, chainTime := tt.cfgAndChainTimeF() + + fc := &FeeCalculator{ + feeManager: fees.NewManager(cfg.DefaultUnitFees), + Codec: codec, + Config: cfg, + ChainTime: chainTime, + Tx: sTx, + } + err := uTx.Visit(fc) + r.ErrorIs(err, tt.expectedError) + tt.checksF(t, fc) + }) + } +} + +func TestImportTxFees(t *testing.T) { + r := require.New(t) + + defaultCtx := snowtest.Context(t, snowtest.PChainID) + codec, err := createTestFeesCodec(defaultCtx) + r.NoError(err) + + baseTx, _ := txsCreationHelpers(defaultCtx) + uTx := &txs.ImportTx{ + BaseTx: baseTx, + SourceChain: ids.GenerateTestID(), + ImportedIns: []*avax.TransferableInput{{ + UTXOID: avax.UTXOID{ + TxID: ids.Empty.Prefix(1), + OutputIndex: 1, + }, + Asset: avax.Asset{ID: ids.ID{'a', 's', 's', 'e', 'r', 't'}}, + In: &secp256k1fx.TransferInput{ + Amt: 50000, + Input: secp256k1fx.Input{SigIndices: []uint32{0}}, + }, + }}, + } + sTx := &txs.Tx{ + Unsigned: uTx, + } + r.NoError(sTx.SignSECP256K1Fx(codec, feeTestSigners)) + + tests := []feeTests{ + { + description: "pre E fork", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(-1 * time.Second) + + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime + + return &cfg, chainTime + }, + expectedError: nil, + checksF: func(t *testing.T, fc *FeeCalculator) { + require.Equal(t, fc.Config.TxFee, fc.Fee) + }, + }, + { + description: "post E fork, success", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(time.Second) + + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime + + return &cfg, chainTime + }, + expectedError: nil, + checksF: func(t *testing.T, fc *FeeCalculator) { + require.Equal(t, 3046*units.MicroAvax, fc.Fee) + require.Equal(t, + fees.Dimensions{ + uint64(len(sTx.Bytes())), + 1090, + 172, + 0, + }, + fc.feeManager.GetCumulatedUnits(), + ) + }, + }, + { + description: "post E fork, utxos read cap breached", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(time.Second) + + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime + cfg.DefaultBlockMaxConsumedUnits[1] = 1090 - 1 + + return &cfg, chainTime + }, + expectedError: errFailedConsumedUnitsCumulation, + checksF: func(t *testing.T, fc *FeeCalculator) {}, + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + cfg, chainTime := tt.cfgAndChainTimeF() + + fc := &FeeCalculator{ + feeManager: fees.NewManager(cfg.DefaultUnitFees), + Codec: codec, + Config: cfg, + ChainTime: chainTime, + Tx: sTx, + } + err := uTx.Visit(fc) + r.ErrorIs(err, tt.expectedError) + tt.checksF(t, fc) + }) + } +} + +func TestExportTxFees(t *testing.T) { + r := require.New(t) + + defaultCtx := snowtest.Context(t, snowtest.PChainID) + codec, err := createTestFeesCodec(defaultCtx) + r.NoError(err) + + baseTx, outputs := txsCreationHelpers(defaultCtx) + uTx := &txs.ExportTx{ + BaseTx: baseTx, + DestinationChain: ids.GenerateTestID(), + ExportedOuts: outputs, + } + sTx := &txs.Tx{ + Unsigned: uTx, + } + r.NoError(sTx.SignSECP256K1Fx(codec, feeTestSigners)) + + tests := []feeTests{ + { + description: "pre E fork", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(-1 * time.Second) + + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime + + return &cfg, chainTime + }, + expectedError: nil, + checksF: func(t *testing.T, fc *FeeCalculator) { + require.Equal(t, fc.Config.TxFee, fc.Fee) + }, + }, + { + description: "post E fork, success", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(time.Second) + + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime + + return &cfg, chainTime + }, + expectedError: nil, + checksF: func(t *testing.T, fc *FeeCalculator) { + require.Equal(t, 3038*units.MicroAvax, fc.Fee) + require.Equal(t, + fees.Dimensions{ + uint64(len(sTx.Bytes())), + 1090, + 172, + 0, + }, + fc.feeManager.GetCumulatedUnits(), + ) + }, + }, + { + description: "post E fork, utxos read cap breached", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(time.Second) + + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime + cfg.DefaultBlockMaxConsumedUnits[1] = 1090 - 1 + + return &cfg, chainTime + }, + expectedError: errFailedConsumedUnitsCumulation, + checksF: func(t *testing.T, fc *FeeCalculator) {}, + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + cfg, chainTime := tt.cfgAndChainTimeF() + + fc := &FeeCalculator{ + feeManager: fees.NewManager(cfg.DefaultUnitFees), + Codec: codec, + Config: cfg, + ChainTime: chainTime, + Tx: sTx, + } + err := uTx.Visit(fc) + r.ErrorIs(err, tt.expectedError) + tt.checksF(t, fc) + }) + } +} + +func createTestFeesCodec(defaultCtx *snow.Context) (codec.Manager, error) { + fxs := []fxs.Fx{ + &secp256k1fx.Fx{}, + &nftfx.Fx{}, + } + + parser, err := block.NewCustomParser( + durangoTime, + map[reflect.Type]int{}, + &mockable.Clock{}, + defaultCtx.Log, + fxs, + ) + if err != nil { + return nil, err + } + + return parser.Codec(), nil +} + +func txsCreationHelpers(defaultCtx *snow.Context) ( + baseTx txs.BaseTx, + otherOutputs []*avax.TransferableOutput, +) { + inputs := []*avax.TransferableInput{{ + UTXOID: avax.UTXOID{ + TxID: ids.ID{'t', 'x', 'I', 'D'}, + OutputIndex: 2, + }, + Asset: avax.Asset{ID: defaultCtx.AVAXAssetID}, + In: &secp256k1fx.TransferInput{ + Amt: uint64(5678), + Input: secp256k1fx.Input{SigIndices: []uint32{0}}, + }, + }} + outputs := []*avax.TransferableOutput{{ + Asset: avax.Asset{ID: defaultCtx.AVAXAssetID}, + Out: &secp256k1fx.TransferOutput{ + Amt: uint64(1234), + OutputOwners: secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{feeTestKeys[0].PublicKey().Address()}, + }, + }, + }} + otherOutputs = []*avax.TransferableOutput{{ + Asset: avax.Asset{ID: defaultCtx.AVAXAssetID}, + Out: &secp256k1fx.TransferOutput{ + Amt: uint64(4567), + OutputOwners: secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{feeTestKeys[1].PublicKey().Address()}, + }, + }, + }} + baseTx = txs.BaseTx{ + BaseTx: avax.BaseTx{ + NetworkID: defaultCtx.NetworkID, + BlockchainID: defaultCtx.ChainID, + Ins: inputs, + Outs: outputs, + }, + } + + return baseTx, otherOutputs +} diff --git a/vms/avm/txs/executor/syntactic_verifier.go b/vms/avm/txs/executor/syntactic_verifier.go index 2c9adafb6d06..baeed6973987 100644 --- a/vms/avm/txs/executor/syntactic_verifier.go +++ b/vms/avm/txs/executor/syntactic_verifier.go @@ -61,6 +61,7 @@ func (v *SyntacticVerifier) BaseTx(tx *txs.BaseTx) error { feeCalculator := FeeCalculator{ feeManager: v.BlkFeeManager, + Codec: v.Codec, Config: v.Config, ChainTime: v.BlkTimestamp, Tx: v.Tx, @@ -134,6 +135,7 @@ func (v *SyntacticVerifier) CreateAssetTx(tx *txs.CreateAssetTx) error { feeCalculator := FeeCalculator{ feeManager: v.BlkFeeManager, + Codec: v.Codec, Config: v.Config, ChainTime: v.BlkTimestamp, Tx: v.Tx, @@ -192,6 +194,7 @@ func (v *SyntacticVerifier) OperationTx(tx *txs.OperationTx) error { feeCalculator := FeeCalculator{ feeManager: v.BlkFeeManager, + Codec: v.Codec, Config: v.Config, ChainTime: v.BlkTimestamp, Tx: v.Tx, @@ -262,6 +265,7 @@ func (v *SyntacticVerifier) ImportTx(tx *txs.ImportTx) error { feeCalculator := FeeCalculator{ feeManager: v.BlkFeeManager, + Codec: v.Codec, Config: v.Config, ChainTime: v.BlkTimestamp, Tx: v.Tx, @@ -314,6 +318,7 @@ func (v *SyntacticVerifier) ExportTx(tx *txs.ExportTx) error { feeCalculator := FeeCalculator{ feeManager: v.BlkFeeManager, + Codec: v.Codec, Config: v.Config, ChainTime: v.BlkTimestamp, Tx: v.Tx, From 6c3939cd3a1770a20633f35ab311ffc6a6ce5cb5 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Wed, 10 Jan 2024 11:10:18 +0100 Subject: [PATCH 022/190] nit --- .../txs/executor/fee_calculator_test.go | 185 ++++++++---------- 1 file changed, 80 insertions(+), 105 deletions(-) diff --git a/vms/platformvm/txs/executor/fee_calculator_test.go b/vms/platformvm/txs/executor/fee_calculator_test.go index 773916ac38e4..7f262806531e 100644 --- a/vms/platformvm/txs/executor/fee_calculator_test.go +++ b/vms/platformvm/txs/executor/fee_calculator_test.go @@ -53,6 +53,7 @@ var ( feeTestSigners = [][]*secp256k1.PrivateKey{preFundedKeys} feeTestDefaultStakeWeight = uint64(2024) + durangoTime = time.Time{} // assume durango is active in these tests ) type feeTests struct { @@ -63,8 +64,6 @@ type feeTests struct { } func TestAddValidatorTxFees(t *testing.T) { - // For simplicity, we define a single AddValidatorTx - // and we change config parameters in the different test cases r := require.New(t) defaultCtx := snowtest.Context(t, snowtest.PChainID) @@ -86,7 +85,7 @@ func TestAddValidatorTxFees(t *testing.T) { }, DelegationShares: reward.PercentDenominator, } - stx, err := txs.NewSigned(uTx, txs.Codec, feeTestSigners) + sTx, err := txs.NewSigned(uTx, txs.Codec, feeTestSigners) r.NoError(err) tests := []feeTests{ @@ -98,7 +97,7 @@ func TestAddValidatorTxFees(t *testing.T) { cfg := &config.Config{ FeeConfig: feeTestsDefaultCfg, - DurangoTime: time.Time{}, // durango already active + DurangoTime: durangoTime, EForkTime: eForkTime, } @@ -117,7 +116,7 @@ func TestAddValidatorTxFees(t *testing.T) { cfg := &config.Config{ FeeConfig: feeTestsDefaultCfg, - DurangoTime: time.Time{}, // durango already active + DurangoTime: durangoTime, EForkTime: eForkTime, } @@ -128,7 +127,7 @@ func TestAddValidatorTxFees(t *testing.T) { require.Equal(t, 3721*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ - uint64(len(stx.Bytes())), + uint64(len(sTx.Bytes())), 1090, 266, 0, @@ -145,10 +144,10 @@ func TestAddValidatorTxFees(t *testing.T) { cfg := &config.Config{ FeeConfig: feeTestsDefaultCfg, - DurangoTime: time.Time{}, // durango already active + DurangoTime: durangoTime, EForkTime: eForkTime, } - cfg.DefaultBlockMaxConsumedUnits[0] = uint64(len(stx.Bytes())) - 1 + cfg.DefaultBlockMaxConsumedUnits[0] = uint64(len(sTx.Bytes())) - 1 return cfg, chainTime }, @@ -165,7 +164,7 @@ func TestAddValidatorTxFees(t *testing.T) { feeManager: fees.NewManager(cfg.DefaultUnitFees), Config: cfg, ChainTime: chainTime, - Tx: stx, + Tx: sTx, } err := uTx.Visit(fc) r.ErrorIs(err, tt.expectedError) @@ -175,8 +174,6 @@ func TestAddValidatorTxFees(t *testing.T) { } func TestAddSubnetValidatorTxFees(t *testing.T) { - // For simplicity, we define a single AddSubnetValidatorTx - // and we change config parameters in the different test cases r := require.New(t) defaultCtx := snowtest.Context(t, snowtest.PChainID) @@ -196,7 +193,7 @@ func TestAddSubnetValidatorTxFees(t *testing.T) { }, SubnetAuth: subnetAuth, } - stx, err := txs.NewSigned(uTx, txs.Codec, feeTestSigners) + sTx, err := txs.NewSigned(uTx, txs.Codec, feeTestSigners) r.NoError(err) tests := []feeTests{ @@ -208,7 +205,7 @@ func TestAddSubnetValidatorTxFees(t *testing.T) { cfg := &config.Config{ FeeConfig: feeTestsDefaultCfg, - DurangoTime: time.Time{}, // durango already active + DurangoTime: durangoTime, EForkTime: eForkTime, } @@ -227,7 +224,7 @@ func TestAddSubnetValidatorTxFees(t *testing.T) { cfg := &config.Config{ FeeConfig: feeTestsDefaultCfg, - DurangoTime: time.Time{}, // durango already active + DurangoTime: durangoTime, EForkTime: eForkTime, } @@ -238,7 +235,7 @@ func TestAddSubnetValidatorTxFees(t *testing.T) { require.Equal(t, 3347*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ - uint64(len(stx.Bytes())), + uint64(len(sTx.Bytes())), 1090, 172, 0, @@ -255,7 +252,7 @@ func TestAddSubnetValidatorTxFees(t *testing.T) { cfg := &config.Config{ FeeConfig: feeTestsDefaultCfg, - DurangoTime: time.Time{}, // durango already active + DurangoTime: durangoTime, EForkTime: eForkTime, } cfg.DefaultBlockMaxConsumedUnits[1] = 1090 - 1 @@ -275,7 +272,7 @@ func TestAddSubnetValidatorTxFees(t *testing.T) { feeManager: fees.NewManager(cfg.DefaultUnitFees), Config: cfg, ChainTime: chainTime, - Tx: stx, + Tx: sTx, } err := uTx.Visit(fc) r.ErrorIs(err, tt.expectedError) @@ -285,8 +282,6 @@ func TestAddSubnetValidatorTxFees(t *testing.T) { } func TestAddDelegatorTxFees(t *testing.T) { - // For simplicity, we define a single AddDelegatorTx - // and we change config parameters in the different test cases r := require.New(t) defaultCtx := snowtest.Context(t, snowtest.PChainID) @@ -307,7 +302,7 @@ func TestAddDelegatorTxFees(t *testing.T) { Addrs: []ids.ShortID{preFundedKeys[0].PublicKey().Address()}, }, } - stx, err := txs.NewSigned(uTx, txs.Codec, feeTestSigners) + sTx, err := txs.NewSigned(uTx, txs.Codec, feeTestSigners) r.NoError(err) tests := []feeTests{ @@ -319,7 +314,7 @@ func TestAddDelegatorTxFees(t *testing.T) { cfg := &config.Config{ FeeConfig: feeTestsDefaultCfg, - DurangoTime: time.Time{}, // durango already active + DurangoTime: durangoTime, EForkTime: eForkTime, } @@ -338,7 +333,7 @@ func TestAddDelegatorTxFees(t *testing.T) { cfg := &config.Config{ FeeConfig: feeTestsDefaultCfg, - DurangoTime: time.Time{}, // durango already active + DurangoTime: durangoTime, EForkTime: eForkTime, } @@ -349,7 +344,7 @@ func TestAddDelegatorTxFees(t *testing.T) { require.Equal(t, 3717*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ - uint64(len(stx.Bytes())), + uint64(len(sTx.Bytes())), 1090, 266, 0, @@ -366,7 +361,7 @@ func TestAddDelegatorTxFees(t *testing.T) { cfg := &config.Config{ FeeConfig: feeTestsDefaultCfg, - DurangoTime: time.Time{}, // durango already active + DurangoTime: durangoTime, EForkTime: eForkTime, } cfg.DefaultBlockMaxConsumedUnits[1] = 1090 - 1 @@ -386,7 +381,7 @@ func TestAddDelegatorTxFees(t *testing.T) { feeManager: fees.NewManager(cfg.DefaultUnitFees), Config: cfg, ChainTime: chainTime, - Tx: stx, + Tx: sTx, } err := uTx.Visit(fc) r.ErrorIs(err, tt.expectedError) @@ -396,8 +391,6 @@ func TestAddDelegatorTxFees(t *testing.T) { } func TestCreateChainTxFees(t *testing.T) { - // For simplicity, we define a single CreateChainTx - // and we change config parameters in the different test cases r := require.New(t) defaultCtx := snowtest.Context(t, snowtest.PChainID) @@ -412,7 +405,7 @@ func TestCreateChainTxFees(t *testing.T) { GenesisData: []byte{0xff}, SubnetAuth: subnetAuth, } - stx, err := txs.NewSigned(uTx, txs.Codec, feeTestSigners) + sTx, err := txs.NewSigned(uTx, txs.Codec, feeTestSigners) r.NoError(err) tests := []feeTests{ @@ -424,7 +417,7 @@ func TestCreateChainTxFees(t *testing.T) { cfg := &config.Config{ FeeConfig: feeTestsDefaultCfg, - DurangoTime: time.Time{}, // durango already active + DurangoTime: durangoTime, EForkTime: eForkTime, } @@ -443,7 +436,7 @@ func TestCreateChainTxFees(t *testing.T) { cfg := &config.Config{ FeeConfig: feeTestsDefaultCfg, - DurangoTime: time.Time{}, // durango already active + DurangoTime: durangoTime, EForkTime: eForkTime, } @@ -454,7 +447,7 @@ func TestCreateChainTxFees(t *testing.T) { require.Equal(t, 3390*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ - uint64(len(stx.Bytes())), + uint64(len(sTx.Bytes())), 1090, 172, 0, @@ -471,7 +464,7 @@ func TestCreateChainTxFees(t *testing.T) { cfg := &config.Config{ FeeConfig: feeTestsDefaultCfg, - DurangoTime: time.Time{}, // durango already active + DurangoTime: durangoTime, EForkTime: eForkTime, } cfg.DefaultBlockMaxConsumedUnits[1] = 1090 - 1 @@ -491,7 +484,7 @@ func TestCreateChainTxFees(t *testing.T) { feeManager: fees.NewManager(cfg.DefaultUnitFees), Config: cfg, ChainTime: chainTime, - Tx: stx, + Tx: sTx, } err := uTx.Visit(fc) r.ErrorIs(err, tt.expectedError) @@ -501,8 +494,6 @@ func TestCreateChainTxFees(t *testing.T) { } func TestCreateSubnetTxFees(t *testing.T) { - // For simplicity, we define a single CreateSubnetTx - // and we change config parameters in the different test cases r := require.New(t) defaultCtx := snowtest.Context(t, snowtest.PChainID) @@ -515,7 +506,7 @@ func TestCreateSubnetTxFees(t *testing.T) { Addrs: []ids.ShortID{preFundedKeys[0].PublicKey().Address()}, }, } - stx, err := txs.NewSigned(uTx, txs.Codec, feeTestSigners) + sTx, err := txs.NewSigned(uTx, txs.Codec, feeTestSigners) r.NoError(err) tests := []feeTests{ @@ -527,7 +518,7 @@ func TestCreateSubnetTxFees(t *testing.T) { cfg := &config.Config{ FeeConfig: feeTestsDefaultCfg, - DurangoTime: time.Time{}, // durango already active + DurangoTime: durangoTime, EForkTime: eForkTime, } @@ -546,7 +537,7 @@ func TestCreateSubnetTxFees(t *testing.T) { cfg := &config.Config{ FeeConfig: feeTestsDefaultCfg, - DurangoTime: time.Time{}, // durango already active + DurangoTime: durangoTime, EForkTime: eForkTime, } @@ -557,7 +548,7 @@ func TestCreateSubnetTxFees(t *testing.T) { require.Equal(t, 3295*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ - uint64(len(stx.Bytes())), + uint64(len(sTx.Bytes())), 1090, 172, 0, @@ -574,7 +565,7 @@ func TestCreateSubnetTxFees(t *testing.T) { cfg := &config.Config{ FeeConfig: feeTestsDefaultCfg, - DurangoTime: time.Time{}, // durango already active + DurangoTime: durangoTime, EForkTime: eForkTime, } cfg.DefaultBlockMaxConsumedUnits[1] = 1090 - 1 @@ -594,7 +585,7 @@ func TestCreateSubnetTxFees(t *testing.T) { feeManager: fees.NewManager(cfg.DefaultUnitFees), Config: cfg, ChainTime: chainTime, - Tx: stx, + Tx: sTx, } err := uTx.Visit(fc) r.ErrorIs(err, tt.expectedError) @@ -604,8 +595,6 @@ func TestCreateSubnetTxFees(t *testing.T) { } func TestRemoveSubnetValidatorTxFees(t *testing.T) { - // For simplicity, we define a single RemoveSubnetValidatorTx - // and we change config parameters in the different test cases r := require.New(t) defaultCtx := snowtest.Context(t, snowtest.PChainID) @@ -617,7 +606,7 @@ func TestRemoveSubnetValidatorTxFees(t *testing.T) { Subnet: ids.GenerateTestID(), SubnetAuth: auth, } - stx, err := txs.NewSigned(uTx, txs.Codec, feeTestSigners) + sTx, err := txs.NewSigned(uTx, txs.Codec, feeTestSigners) r.NoError(err) tests := []feeTests{ @@ -629,7 +618,7 @@ func TestRemoveSubnetValidatorTxFees(t *testing.T) { cfg := &config.Config{ FeeConfig: feeTestsDefaultCfg, - DurangoTime: time.Time{}, // durango already active + DurangoTime: durangoTime, EForkTime: eForkTime, } @@ -648,7 +637,7 @@ func TestRemoveSubnetValidatorTxFees(t *testing.T) { cfg := &config.Config{ FeeConfig: feeTestsDefaultCfg, - DurangoTime: time.Time{}, // durango already active + DurangoTime: durangoTime, EForkTime: eForkTime, } @@ -659,7 +648,7 @@ func TestRemoveSubnetValidatorTxFees(t *testing.T) { require.Equal(t, 3323*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ - uint64(len(stx.Bytes())), + uint64(len(sTx.Bytes())), 1090, 172, 0, @@ -676,7 +665,7 @@ func TestRemoveSubnetValidatorTxFees(t *testing.T) { cfg := &config.Config{ FeeConfig: feeTestsDefaultCfg, - DurangoTime: time.Time{}, // durango already active + DurangoTime: durangoTime, EForkTime: eForkTime, } cfg.DefaultBlockMaxConsumedUnits[1] = 1090 - 1 @@ -696,7 +685,7 @@ func TestRemoveSubnetValidatorTxFees(t *testing.T) { feeManager: fees.NewManager(cfg.DefaultUnitFees), Config: cfg, ChainTime: chainTime, - Tx: stx, + Tx: sTx, } err := uTx.Visit(fc) r.ErrorIs(err, tt.expectedError) @@ -706,8 +695,6 @@ func TestRemoveSubnetValidatorTxFees(t *testing.T) { } func TestTransformSubnetTxFees(t *testing.T) { - // For simplicity, we define a single TransformSubnetTx - // and we change config parameters in the different test cases r := require.New(t) defaultCtx := snowtest.Context(t, snowtest.PChainID) @@ -731,7 +718,7 @@ func TestTransformSubnetTxFees(t *testing.T) { UptimeRequirement: 0, SubnetAuth: auth, } - stx, err := txs.NewSigned(uTx, txs.Codec, feeTestSigners) + sTx, err := txs.NewSigned(uTx, txs.Codec, feeTestSigners) r.NoError(err) tests := []feeTests{ @@ -743,7 +730,7 @@ func TestTransformSubnetTxFees(t *testing.T) { cfg := &config.Config{ FeeConfig: feeTestsDefaultCfg, - DurangoTime: time.Time{}, // durango already active + DurangoTime: durangoTime, EForkTime: eForkTime, } @@ -762,7 +749,7 @@ func TestTransformSubnetTxFees(t *testing.T) { cfg := &config.Config{ FeeConfig: feeTestsDefaultCfg, - DurangoTime: time.Time{}, // durango already active + DurangoTime: durangoTime, EForkTime: eForkTime, } @@ -773,7 +760,7 @@ func TestTransformSubnetTxFees(t *testing.T) { require.Equal(t, 3408*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ - uint64(len(stx.Bytes())), + uint64(len(sTx.Bytes())), 1090, 172, 0, @@ -790,7 +777,7 @@ func TestTransformSubnetTxFees(t *testing.T) { cfg := &config.Config{ FeeConfig: feeTestsDefaultCfg, - DurangoTime: time.Time{}, // durango already active + DurangoTime: durangoTime, EForkTime: eForkTime, } cfg.DefaultBlockMaxConsumedUnits[1] = 1090 - 1 @@ -810,7 +797,7 @@ func TestTransformSubnetTxFees(t *testing.T) { feeManager: fees.NewManager(cfg.DefaultUnitFees), Config: cfg, ChainTime: chainTime, - Tx: stx, + Tx: sTx, } err := uTx.Visit(fc) r.ErrorIs(err, tt.expectedError) @@ -820,8 +807,6 @@ func TestTransformSubnetTxFees(t *testing.T) { } func TestTransferSubnetOwnershipTxFees(t *testing.T) { - // For simplicity, we define a single TransferSubnetOwnershipTx - // and we change config parameters in the different test cases r := require.New(t) defaultCtx := snowtest.Context(t, snowtest.PChainID) @@ -841,7 +826,7 @@ func TestTransferSubnetOwnershipTxFees(t *testing.T) { }, }, } - stx, err := txs.NewSigned(uTx, txs.Codec, feeTestSigners) + sTx, err := txs.NewSigned(uTx, txs.Codec, feeTestSigners) r.NoError(err) tests := []feeTests{ @@ -853,7 +838,7 @@ func TestTransferSubnetOwnershipTxFees(t *testing.T) { cfg := &config.Config{ FeeConfig: feeTestsDefaultCfg, - DurangoTime: time.Time{}, // durango already active + DurangoTime: durangoTime, EForkTime: eForkTime, } @@ -872,7 +857,7 @@ func TestTransferSubnetOwnershipTxFees(t *testing.T) { cfg := &config.Config{ FeeConfig: feeTestsDefaultCfg, - DurangoTime: time.Time{}, // durango already active + DurangoTime: durangoTime, EForkTime: eForkTime, } @@ -883,7 +868,7 @@ func TestTransferSubnetOwnershipTxFees(t *testing.T) { require.Equal(t, 3339*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ - uint64(len(stx.Bytes())), + uint64(len(sTx.Bytes())), 1090, 172, 0, @@ -900,7 +885,7 @@ func TestTransferSubnetOwnershipTxFees(t *testing.T) { cfg := &config.Config{ FeeConfig: feeTestsDefaultCfg, - DurangoTime: time.Time{}, // durango already active + DurangoTime: durangoTime, EForkTime: eForkTime, } cfg.DefaultBlockMaxConsumedUnits[1] = 1090 - 1 @@ -920,7 +905,7 @@ func TestTransferSubnetOwnershipTxFees(t *testing.T) { feeManager: fees.NewManager(cfg.DefaultUnitFees), Config: cfg, ChainTime: chainTime, - Tx: stx, + Tx: sTx, } err := uTx.Visit(fc) r.ErrorIs(err, tt.expectedError) @@ -930,8 +915,6 @@ func TestTransferSubnetOwnershipTxFees(t *testing.T) { } func TestAddPermissionlessValidatorTxFees(t *testing.T) { - // For simplicity, we define a single AddPermissionlessValidatorTx - // and we change config parameters in the different test cases r := require.New(t) defaultCtx := snowtest.Context(t, snowtest.PChainID) @@ -960,7 +943,7 @@ func TestAddPermissionlessValidatorTxFees(t *testing.T) { }, DelegationShares: reward.PercentDenominator, } - stx, err := txs.NewSigned(uTx, txs.Codec, feeTestSigners) + sTx, err := txs.NewSigned(uTx, txs.Codec, feeTestSigners) r.NoError(err) tests := []feeTests{ @@ -972,7 +955,7 @@ func TestAddPermissionlessValidatorTxFees(t *testing.T) { cfg := &config.Config{ FeeConfig: feeTestsDefaultCfg, - DurangoTime: time.Time{}, // durango already active + DurangoTime: durangoTime, EForkTime: eForkTime, } @@ -991,7 +974,7 @@ func TestAddPermissionlessValidatorTxFees(t *testing.T) { cfg := &config.Config{ FeeConfig: feeTestsDefaultCfg, - DurangoTime: time.Time{}, // durango already active + DurangoTime: durangoTime, EForkTime: eForkTime, } @@ -1002,7 +985,7 @@ func TestAddPermissionlessValidatorTxFees(t *testing.T) { require.Equal(t, 3941*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ - uint64(len(stx.Bytes())), + uint64(len(sTx.Bytes())), 1090, 266, 0, @@ -1019,7 +1002,7 @@ func TestAddPermissionlessValidatorTxFees(t *testing.T) { cfg := &config.Config{ FeeConfig: feeTestsDefaultCfg, - DurangoTime: time.Time{}, // durango already active + DurangoTime: durangoTime, EForkTime: eForkTime, } cfg.DefaultBlockMaxConsumedUnits[1] = 1090 - 1 @@ -1039,7 +1022,7 @@ func TestAddPermissionlessValidatorTxFees(t *testing.T) { feeManager: fees.NewManager(cfg.DefaultUnitFees), Config: cfg, ChainTime: chainTime, - Tx: stx, + Tx: sTx, } err := uTx.Visit(fc) r.ErrorIs(err, tt.expectedError) @@ -1049,8 +1032,6 @@ func TestAddPermissionlessValidatorTxFees(t *testing.T) { } func TestAddPermissionlessDelegatorTxFees(t *testing.T) { - // For simplicity, we define a single AddPermissionlessDelegatorTx - // and we change config parameters in the different test cases r := require.New(t) defaultCtx := snowtest.Context(t, snowtest.PChainID) @@ -1074,7 +1055,7 @@ func TestAddPermissionlessDelegatorTxFees(t *testing.T) { }, }, } - stx, err := txs.NewSigned(uTx, txs.Codec, feeTestSigners) + sTx, err := txs.NewSigned(uTx, txs.Codec, feeTestSigners) r.NoError(err) tests := []feeTests{ @@ -1086,7 +1067,7 @@ func TestAddPermissionlessDelegatorTxFees(t *testing.T) { cfg := &config.Config{ FeeConfig: feeTestsDefaultCfg, - DurangoTime: time.Time{}, // durango already active + DurangoTime: durangoTime, EForkTime: eForkTime, } @@ -1105,7 +1086,7 @@ func TestAddPermissionlessDelegatorTxFees(t *testing.T) { cfg := &config.Config{ FeeConfig: feeTestsDefaultCfg, - DurangoTime: time.Time{}, // durango already active + DurangoTime: durangoTime, EForkTime: eForkTime, } @@ -1116,7 +1097,7 @@ func TestAddPermissionlessDelegatorTxFees(t *testing.T) { require.Equal(t, 3749*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ - uint64(len(stx.Bytes())), + uint64(len(sTx.Bytes())), 1090, 266, 0, @@ -1133,7 +1114,7 @@ func TestAddPermissionlessDelegatorTxFees(t *testing.T) { cfg := &config.Config{ FeeConfig: feeTestsDefaultCfg, - DurangoTime: time.Time{}, // durango already active + DurangoTime: durangoTime, EForkTime: eForkTime, } cfg.DefaultBlockMaxConsumedUnits[1] = 1090 - 1 @@ -1153,7 +1134,7 @@ func TestAddPermissionlessDelegatorTxFees(t *testing.T) { feeManager: fees.NewManager(cfg.DefaultUnitFees), Config: cfg, ChainTime: chainTime, - Tx: stx, + Tx: sTx, } err := uTx.Visit(fc) r.ErrorIs(err, tt.expectedError) @@ -1163,15 +1144,13 @@ func TestAddPermissionlessDelegatorTxFees(t *testing.T) { } func TestBaseTxFees(t *testing.T) { - // For simplicity, we define a single BaseTx - // and we change config parameters in the different test cases r := require.New(t) defaultCtx := snowtest.Context(t, snowtest.PChainID) baseTx, _, _ := txsCreationHelpers(defaultCtx) uTx := &baseTx - stx, err := txs.NewSigned(uTx, txs.Codec, feeTestSigners) + sTx, err := txs.NewSigned(uTx, txs.Codec, feeTestSigners) r.NoError(err) tests := []feeTests{ @@ -1183,7 +1162,7 @@ func TestBaseTxFees(t *testing.T) { cfg := &config.Config{ FeeConfig: feeTestsDefaultCfg, - DurangoTime: time.Time{}, // durango already active + DurangoTime: durangoTime, EForkTime: eForkTime, } @@ -1202,7 +1181,7 @@ func TestBaseTxFees(t *testing.T) { cfg := &config.Config{ FeeConfig: feeTestsDefaultCfg, - DurangoTime: time.Time{}, // durango already active + DurangoTime: durangoTime, EForkTime: eForkTime, } @@ -1213,7 +1192,7 @@ func TestBaseTxFees(t *testing.T) { require.Equal(t, 3255*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ - uint64(len(stx.Bytes())), + uint64(len(sTx.Bytes())), 1090, 172, 0, @@ -1230,7 +1209,7 @@ func TestBaseTxFees(t *testing.T) { cfg := &config.Config{ FeeConfig: feeTestsDefaultCfg, - DurangoTime: time.Time{}, // durango already active + DurangoTime: durangoTime, EForkTime: eForkTime, } cfg.DefaultBlockMaxConsumedUnits[1] = 1090 - 1 @@ -1250,7 +1229,7 @@ func TestBaseTxFees(t *testing.T) { feeManager: fees.NewManager(cfg.DefaultUnitFees), Config: cfg, ChainTime: chainTime, - Tx: stx, + Tx: sTx, } err := uTx.Visit(fc) r.ErrorIs(err, tt.expectedError) @@ -1260,8 +1239,6 @@ func TestBaseTxFees(t *testing.T) { } func TestImportTxFees(t *testing.T) { - // For simplicity, we define a single ImportTx - // and we change config parameters in the different test cases r := require.New(t) defaultCtx := snowtest.Context(t, snowtest.PChainID) @@ -1282,7 +1259,7 @@ func TestImportTxFees(t *testing.T) { }, }}, } - stx, err := txs.NewSigned(uTx, txs.Codec, feeTestSigners) + sTx, err := txs.NewSigned(uTx, txs.Codec, feeTestSigners) r.NoError(err) tests := []feeTests{ @@ -1294,7 +1271,7 @@ func TestImportTxFees(t *testing.T) { cfg := &config.Config{ FeeConfig: feeTestsDefaultCfg, - DurangoTime: time.Time{}, // durango already active + DurangoTime: durangoTime, EForkTime: eForkTime, } @@ -1313,7 +1290,7 @@ func TestImportTxFees(t *testing.T) { cfg := &config.Config{ FeeConfig: feeTestsDefaultCfg, - DurangoTime: time.Time{}, // durango already active + DurangoTime: durangoTime, EForkTime: eForkTime, } @@ -1324,7 +1301,7 @@ func TestImportTxFees(t *testing.T) { require.Equal(t, 5829*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ - uint64(len(stx.Bytes())), + uint64(len(sTx.Bytes())), 2180, 262, 0, @@ -1341,7 +1318,7 @@ func TestImportTxFees(t *testing.T) { cfg := &config.Config{ FeeConfig: feeTestsDefaultCfg, - DurangoTime: time.Time{}, // durango already active + DurangoTime: durangoTime, EForkTime: eForkTime, } cfg.DefaultBlockMaxConsumedUnits[1] = 1090 - 1 @@ -1361,7 +1338,7 @@ func TestImportTxFees(t *testing.T) { feeManager: fees.NewManager(cfg.DefaultUnitFees), Config: cfg, ChainTime: chainTime, - Tx: stx, + Tx: sTx, } err := uTx.Visit(fc) r.ErrorIs(err, tt.expectedError) @@ -1371,8 +1348,6 @@ func TestImportTxFees(t *testing.T) { } func TestExportTxFees(t *testing.T) { - // For simplicity, we define a single ExportTx - // and we change config parameters in the different test cases r := require.New(t) defaultCtx := snowtest.Context(t, snowtest.PChainID) @@ -1383,7 +1358,7 @@ func TestExportTxFees(t *testing.T) { DestinationChain: ids.GenerateTestID(), ExportedOutputs: outputs, } - stx, err := txs.NewSigned(uTx, txs.Codec, feeTestSigners) + sTx, err := txs.NewSigned(uTx, txs.Codec, feeTestSigners) r.NoError(err) tests := []feeTests{ @@ -1395,7 +1370,7 @@ func TestExportTxFees(t *testing.T) { cfg := &config.Config{ FeeConfig: feeTestsDefaultCfg, - DurangoTime: time.Time{}, // durango already active + DurangoTime: durangoTime, EForkTime: eForkTime, } @@ -1414,7 +1389,7 @@ func TestExportTxFees(t *testing.T) { cfg := &config.Config{ FeeConfig: feeTestsDefaultCfg, - DurangoTime: time.Time{}, // durango already active + DurangoTime: durangoTime, EForkTime: eForkTime, } @@ -1425,7 +1400,7 @@ func TestExportTxFees(t *testing.T) { require.Equal(t, 3665*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ - uint64(len(stx.Bytes())), + uint64(len(sTx.Bytes())), 1090, 266, 0, @@ -1442,7 +1417,7 @@ func TestExportTxFees(t *testing.T) { cfg := &config.Config{ FeeConfig: feeTestsDefaultCfg, - DurangoTime: time.Time{}, // durango already active + DurangoTime: durangoTime, EForkTime: eForkTime, } cfg.DefaultBlockMaxConsumedUnits[1] = 1090 - 1 @@ -1462,7 +1437,7 @@ func TestExportTxFees(t *testing.T) { feeManager: fees.NewManager(cfg.DefaultUnitFees), Config: cfg, ChainTime: chainTime, - Tx: stx, + Tx: sTx, } err := uTx.Visit(fc) r.ErrorIs(err, tt.expectedError) From d77ee0edbd1b3c0963bf797c0648299e124f9f37 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 11 Jan 2024 11:43:33 +0100 Subject: [PATCH 023/190] refactored fees --- vms/platformvm/txs/executor/fee_calculator.go | 49 ++++-- .../txs/executor/fee_calculator_test.go | 158 +++++++++--------- .../txs/executor/staker_tx_verification.go | 56 +++---- .../txs/executor/standard_tx_executor.go | 40 ++--- 4 files changed, 158 insertions(+), 145 deletions(-) diff --git a/vms/platformvm/txs/executor/fee_calculator.go b/vms/platformvm/txs/executor/fee_calculator.go index b464d8afc082..063d43975da9 100644 --- a/vms/platformvm/txs/executor/fee_calculator.go +++ b/vms/platformvm/txs/executor/fee_calculator.go @@ -10,6 +10,7 @@ import ( "github.com/ava-labs/avalanchego/utils/constants" "github.com/ava-labs/avalanchego/vms/components/avax" + "github.com/ava-labs/avalanchego/vms/components/verify" "github.com/ava-labs/avalanchego/vms/platformvm/config" "github.com/ava-labs/avalanchego/vms/platformvm/fees" "github.com/ava-labs/avalanchego/vms/platformvm/txs" @@ -29,7 +30,7 @@ type FeeCalculator struct { ChainTime time.Time // inputs, to be filled before visitor methods are called - Tx *txs.Tx + Credentials []verify.Verifiable // outputs of visitor execution Fee uint64 @@ -45,7 +46,7 @@ func (fc *FeeCalculator) AddValidatorTx(tx *txs.AddValidatorTx) error { copy(outs, tx.Outs) copy(outs[len(tx.Outs):], tx.StakeOuts) - consumedUnits, err := commonConsumedUnits(fc.Tx, outs, tx.Ins) + consumedUnits, err := commonConsumedUnits(tx, fc.Credentials, outs, tx.Ins) if err != nil { return err } @@ -60,7 +61,7 @@ func (fc *FeeCalculator) AddSubnetValidatorTx(tx *txs.AddSubnetValidatorTx) erro return nil } - consumedUnits, err := commonConsumedUnits(fc.Tx, tx.Outs, tx.Ins) + consumedUnits, err := commonConsumedUnits(tx, fc.Credentials, tx.Outs, tx.Ins) if err != nil { return err } @@ -79,7 +80,7 @@ func (fc *FeeCalculator) AddDelegatorTx(tx *txs.AddDelegatorTx) error { copy(outs, tx.Outs) copy(outs[len(tx.Outs):], tx.StakeOuts) - consumedUnits, err := commonConsumedUnits(fc.Tx, outs, tx.Ins) + consumedUnits, err := commonConsumedUnits(tx, fc.Credentials, outs, tx.Ins) if err != nil { return err } @@ -94,7 +95,7 @@ func (fc *FeeCalculator) CreateChainTx(tx *txs.CreateChainTx) error { return nil } - consumedUnits, err := commonConsumedUnits(fc.Tx, tx.Outs, tx.Ins) + consumedUnits, err := commonConsumedUnits(tx, fc.Credentials, tx.Outs, tx.Ins) if err != nil { return err } @@ -109,7 +110,7 @@ func (fc *FeeCalculator) CreateSubnetTx(tx *txs.CreateSubnetTx) error { return nil } - consumedUnits, err := commonConsumedUnits(fc.Tx, tx.Outs, tx.Ins) + consumedUnits, err := commonConsumedUnits(tx, fc.Credentials, tx.Outs, tx.Ins) if err != nil { return err } @@ -132,7 +133,7 @@ func (fc *FeeCalculator) RemoveSubnetValidatorTx(tx *txs.RemoveSubnetValidatorTx return nil } - consumedUnits, err := commonConsumedUnits(fc.Tx, tx.Outs, tx.Ins) + consumedUnits, err := commonConsumedUnits(tx, fc.Credentials, tx.Outs, tx.Ins) if err != nil { return err } @@ -147,7 +148,7 @@ func (fc *FeeCalculator) TransformSubnetTx(tx *txs.TransformSubnetTx) error { return nil } - consumedUnits, err := commonConsumedUnits(fc.Tx, tx.Outs, tx.Ins) + consumedUnits, err := commonConsumedUnits(tx, fc.Credentials, tx.Outs, tx.Ins) if err != nil { return err } @@ -162,7 +163,7 @@ func (fc *FeeCalculator) TransferSubnetOwnershipTx(tx *txs.TransferSubnetOwnersh return nil } - consumedUnits, err := commonConsumedUnits(fc.Tx, tx.Outs, tx.Ins) + consumedUnits, err := commonConsumedUnits(tx, fc.Credentials, tx.Outs, tx.Ins) if err != nil { return err } @@ -185,7 +186,7 @@ func (fc *FeeCalculator) AddPermissionlessValidatorTx(tx *txs.AddPermissionlessV copy(outs, tx.Outs) copy(outs[len(tx.Outs):], tx.StakeOuts) - consumedUnits, err := commonConsumedUnits(fc.Tx, outs, tx.Ins) + consumedUnits, err := commonConsumedUnits(tx, fc.Credentials, outs, tx.Ins) if err != nil { return err } @@ -208,7 +209,7 @@ func (fc *FeeCalculator) AddPermissionlessDelegatorTx(tx *txs.AddPermissionlessD copy(outs, tx.Outs) copy(outs[len(tx.Outs):], tx.StakeOuts) - consumedUnits, err := commonConsumedUnits(fc.Tx, outs, tx.Ins) + consumedUnits, err := commonConsumedUnits(tx, fc.Credentials, outs, tx.Ins) if err != nil { return err } @@ -223,7 +224,7 @@ func (fc *FeeCalculator) BaseTx(tx *txs.BaseTx) error { return nil } - consumedUnits, err := commonConsumedUnits(fc.Tx, tx.Outs, tx.Ins) + consumedUnits, err := commonConsumedUnits(tx, fc.Credentials, tx.Outs, tx.Ins) if err != nil { return err } @@ -242,7 +243,7 @@ func (fc *FeeCalculator) ImportTx(tx *txs.ImportTx) error { copy(ins, tx.Ins) copy(ins[len(tx.Ins):], tx.ImportedInputs) - consumedUnits, err := commonConsumedUnits(fc.Tx, tx.Outs, ins) + consumedUnits, err := commonConsumedUnits(tx, fc.Credentials, tx.Outs, ins) if err != nil { return err } @@ -261,7 +262,7 @@ func (fc *FeeCalculator) ExportTx(tx *txs.ExportTx) error { copy(outs, tx.Outs) copy(outs[len(tx.Outs):], tx.ExportedOutputs) - consumedUnits, err := commonConsumedUnits(fc.Tx, outs, tx.Ins) + consumedUnits, err := commonConsumedUnits(tx, fc.Credentials, outs, tx.Ins) if err != nil { return err } @@ -270,17 +271,29 @@ func (fc *FeeCalculator) ExportTx(tx *txs.ExportTx) error { return err } -func commonConsumedUnits(sTx *txs.Tx, allOuts []*avax.TransferableOutput, allIns []*avax.TransferableInput) (fees.Dimensions, error) { +func commonConsumedUnits( + uTx txs.UnsignedTx, + credentials []verify.Verifiable, + allOuts []*avax.TransferableOutput, + allIns []*avax.TransferableInput, +) (fees.Dimensions, error) { var consumedUnits fees.Dimensions - consumedUnits[fees.Bandwidth] = uint64(len(sTx.Bytes())) - // TODO ABENEGIA: consider handling imports/exports differently + uTxSize, err := txs.Codec.Size(txs.CodecVersion, uTx) + if err != nil { + return consumedUnits, fmt.Errorf("couldn't calculate UnsignedTx marshal length: %w", err) + } + credsSize, err := txs.Codec.Size(txs.CodecVersion, credentials) + if err != nil { + return consumedUnits, fmt.Errorf("failed retrieving size of credentials: %w", err) + } + consumedUnits[fees.Bandwidth] = uint64(uTxSize + credsSize) + var ( insCost uint64 insSize uint64 outsSize uint64 ) - for _, in := range allIns { cost, err := in.In.Cost() if err != nil { diff --git a/vms/platformvm/txs/executor/fee_calculator_test.go b/vms/platformvm/txs/executor/fee_calculator_test.go index 7f262806531e..976ef90dd0ab 100644 --- a/vms/platformvm/txs/executor/fee_calculator_test.go +++ b/vms/platformvm/txs/executor/fee_calculator_test.go @@ -124,10 +124,10 @@ func TestAddValidatorTxFees(t *testing.T) { }, expectedError: nil, checksF: func(t *testing.T, fc *FeeCalculator) { - require.Equal(t, 3721*units.MicroAvax, fc.Fee) + require.Equal(t, 3719*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ - uint64(len(sTx.Bytes())), + 741, 1090, 266, 0, @@ -147,7 +147,7 @@ func TestAddValidatorTxFees(t *testing.T) { DurangoTime: durangoTime, EForkTime: eForkTime, } - cfg.DefaultBlockMaxConsumedUnits[0] = uint64(len(sTx.Bytes())) - 1 + cfg.DefaultBlockMaxConsumedUnits[0] = 741 - 1 return cfg, chainTime }, @@ -161,10 +161,10 @@ func TestAddValidatorTxFees(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() fc := &FeeCalculator{ - feeManager: fees.NewManager(cfg.DefaultUnitFees), - Config: cfg, - ChainTime: chainTime, - Tx: sTx, + feeManager: fees.NewManager(cfg.DefaultUnitFees), + Config: cfg, + ChainTime: chainTime, + Credentials: sTx.Creds, } err := uTx.Visit(fc) r.ErrorIs(err, tt.expectedError) @@ -232,10 +232,10 @@ func TestAddSubnetValidatorTxFees(t *testing.T) { }, expectedError: nil, checksF: func(t *testing.T, fc *FeeCalculator) { - require.Equal(t, 3347*units.MicroAvax, fc.Fee) + require.Equal(t, 3345*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ - uint64(len(sTx.Bytes())), + 649, 1090, 172, 0, @@ -269,10 +269,10 @@ func TestAddSubnetValidatorTxFees(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() fc := &FeeCalculator{ - feeManager: fees.NewManager(cfg.DefaultUnitFees), - Config: cfg, - ChainTime: chainTime, - Tx: sTx, + feeManager: fees.NewManager(cfg.DefaultUnitFees), + Config: cfg, + ChainTime: chainTime, + Credentials: sTx.Creds, } err := uTx.Visit(fc) r.ErrorIs(err, tt.expectedError) @@ -341,10 +341,10 @@ func TestAddDelegatorTxFees(t *testing.T) { }, expectedError: nil, checksF: func(t *testing.T, fc *FeeCalculator) { - require.Equal(t, 3717*units.MicroAvax, fc.Fee) + require.Equal(t, 3715*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ - uint64(len(sTx.Bytes())), + 737, 1090, 266, 0, @@ -378,10 +378,10 @@ func TestAddDelegatorTxFees(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() fc := &FeeCalculator{ - feeManager: fees.NewManager(cfg.DefaultUnitFees), - Config: cfg, - ChainTime: chainTime, - Tx: sTx, + feeManager: fees.NewManager(cfg.DefaultUnitFees), + Config: cfg, + ChainTime: chainTime, + Credentials: sTx.Creds, } err := uTx.Visit(fc) r.ErrorIs(err, tt.expectedError) @@ -444,10 +444,10 @@ func TestCreateChainTxFees(t *testing.T) { }, expectedError: nil, checksF: func(t *testing.T, fc *FeeCalculator) { - require.Equal(t, 3390*units.MicroAvax, fc.Fee) + require.Equal(t, 3388*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ - uint64(len(sTx.Bytes())), + 692, 1090, 172, 0, @@ -481,10 +481,10 @@ func TestCreateChainTxFees(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() fc := &FeeCalculator{ - feeManager: fees.NewManager(cfg.DefaultUnitFees), - Config: cfg, - ChainTime: chainTime, - Tx: sTx, + feeManager: fees.NewManager(cfg.DefaultUnitFees), + Config: cfg, + ChainTime: chainTime, + Credentials: sTx.Creds, } err := uTx.Visit(fc) r.ErrorIs(err, tt.expectedError) @@ -545,10 +545,10 @@ func TestCreateSubnetTxFees(t *testing.T) { }, expectedError: nil, checksF: func(t *testing.T, fc *FeeCalculator) { - require.Equal(t, 3295*units.MicroAvax, fc.Fee) + require.Equal(t, 3293*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ - uint64(len(sTx.Bytes())), + 597, 1090, 172, 0, @@ -582,10 +582,10 @@ func TestCreateSubnetTxFees(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() fc := &FeeCalculator{ - feeManager: fees.NewManager(cfg.DefaultUnitFees), - Config: cfg, - ChainTime: chainTime, - Tx: sTx, + feeManager: fees.NewManager(cfg.DefaultUnitFees), + Config: cfg, + ChainTime: chainTime, + Credentials: sTx.Creds, } err := uTx.Visit(fc) r.ErrorIs(err, tt.expectedError) @@ -645,10 +645,10 @@ func TestRemoveSubnetValidatorTxFees(t *testing.T) { }, expectedError: nil, checksF: func(t *testing.T, fc *FeeCalculator) { - require.Equal(t, 3323*units.MicroAvax, fc.Fee) + require.Equal(t, 3321*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ - uint64(len(sTx.Bytes())), + 625, 1090, 172, 0, @@ -682,10 +682,10 @@ func TestRemoveSubnetValidatorTxFees(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() fc := &FeeCalculator{ - feeManager: fees.NewManager(cfg.DefaultUnitFees), - Config: cfg, - ChainTime: chainTime, - Tx: sTx, + feeManager: fees.NewManager(cfg.DefaultUnitFees), + Config: cfg, + ChainTime: chainTime, + Credentials: sTx.Creds, } err := uTx.Visit(fc) r.ErrorIs(err, tt.expectedError) @@ -757,10 +757,10 @@ func TestTransformSubnetTxFees(t *testing.T) { }, expectedError: nil, checksF: func(t *testing.T, fc *FeeCalculator) { - require.Equal(t, 3408*units.MicroAvax, fc.Fee) + require.Equal(t, 3406*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ - uint64(len(sTx.Bytes())), + 710, 1090, 172, 0, @@ -794,10 +794,10 @@ func TestTransformSubnetTxFees(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() fc := &FeeCalculator{ - feeManager: fees.NewManager(cfg.DefaultUnitFees), - Config: cfg, - ChainTime: chainTime, - Tx: sTx, + feeManager: fees.NewManager(cfg.DefaultUnitFees), + Config: cfg, + ChainTime: chainTime, + Credentials: sTx.Creds, } err := uTx.Visit(fc) r.ErrorIs(err, tt.expectedError) @@ -865,10 +865,10 @@ func TestTransferSubnetOwnershipTxFees(t *testing.T) { }, expectedError: nil, checksF: func(t *testing.T, fc *FeeCalculator) { - require.Equal(t, 3339*units.MicroAvax, fc.Fee) + require.Equal(t, 3337*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ - uint64(len(sTx.Bytes())), + 641, 1090, 172, 0, @@ -902,10 +902,10 @@ func TestTransferSubnetOwnershipTxFees(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() fc := &FeeCalculator{ - feeManager: fees.NewManager(cfg.DefaultUnitFees), - Config: cfg, - ChainTime: chainTime, - Tx: sTx, + feeManager: fees.NewManager(cfg.DefaultUnitFees), + Config: cfg, + ChainTime: chainTime, + Credentials: sTx.Creds, } err := uTx.Visit(fc) r.ErrorIs(err, tt.expectedError) @@ -982,10 +982,10 @@ func TestAddPermissionlessValidatorTxFees(t *testing.T) { }, expectedError: nil, checksF: func(t *testing.T, fc *FeeCalculator) { - require.Equal(t, 3941*units.MicroAvax, fc.Fee) + require.Equal(t, 3939*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ - uint64(len(sTx.Bytes())), + 961, 1090, 266, 0, @@ -1019,10 +1019,10 @@ func TestAddPermissionlessValidatorTxFees(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() fc := &FeeCalculator{ - feeManager: fees.NewManager(cfg.DefaultUnitFees), - Config: cfg, - ChainTime: chainTime, - Tx: sTx, + feeManager: fees.NewManager(cfg.DefaultUnitFees), + Config: cfg, + ChainTime: chainTime, + Credentials: sTx.Creds, } err := uTx.Visit(fc) r.ErrorIs(err, tt.expectedError) @@ -1094,10 +1094,10 @@ func TestAddPermissionlessDelegatorTxFees(t *testing.T) { }, expectedError: nil, checksF: func(t *testing.T, fc *FeeCalculator) { - require.Equal(t, 3749*units.MicroAvax, fc.Fee) + require.Equal(t, 3747*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ - uint64(len(sTx.Bytes())), + 769, 1090, 266, 0, @@ -1131,10 +1131,10 @@ func TestAddPermissionlessDelegatorTxFees(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() fc := &FeeCalculator{ - feeManager: fees.NewManager(cfg.DefaultUnitFees), - Config: cfg, - ChainTime: chainTime, - Tx: sTx, + feeManager: fees.NewManager(cfg.DefaultUnitFees), + Config: cfg, + ChainTime: chainTime, + Credentials: sTx.Creds, } err := uTx.Visit(fc) r.ErrorIs(err, tt.expectedError) @@ -1189,10 +1189,10 @@ func TestBaseTxFees(t *testing.T) { }, expectedError: nil, checksF: func(t *testing.T, fc *FeeCalculator) { - require.Equal(t, 3255*units.MicroAvax, fc.Fee) + require.Equal(t, 3253*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ - uint64(len(sTx.Bytes())), + 557, 1090, 172, 0, @@ -1226,10 +1226,10 @@ func TestBaseTxFees(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() fc := &FeeCalculator{ - feeManager: fees.NewManager(cfg.DefaultUnitFees), - Config: cfg, - ChainTime: chainTime, - Tx: sTx, + feeManager: fees.NewManager(cfg.DefaultUnitFees), + Config: cfg, + ChainTime: chainTime, + Credentials: sTx.Creds, } err := uTx.Visit(fc) r.ErrorIs(err, tt.expectedError) @@ -1298,10 +1298,10 @@ func TestImportTxFees(t *testing.T) { }, expectedError: nil, checksF: func(t *testing.T, fc *FeeCalculator) { - require.Equal(t, 5829*units.MicroAvax, fc.Fee) + require.Equal(t, 5827*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ - uint64(len(sTx.Bytes())), + 681, 2180, 262, 0, @@ -1335,10 +1335,10 @@ func TestImportTxFees(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() fc := &FeeCalculator{ - feeManager: fees.NewManager(cfg.DefaultUnitFees), - Config: cfg, - ChainTime: chainTime, - Tx: sTx, + feeManager: fees.NewManager(cfg.DefaultUnitFees), + Config: cfg, + ChainTime: chainTime, + Credentials: sTx.Creds, } err := uTx.Visit(fc) r.ErrorIs(err, tt.expectedError) @@ -1397,10 +1397,10 @@ func TestExportTxFees(t *testing.T) { }, expectedError: nil, checksF: func(t *testing.T, fc *FeeCalculator) { - require.Equal(t, 3665*units.MicroAvax, fc.Fee) + require.Equal(t, 3663*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ - uint64(len(sTx.Bytes())), + 685, 1090, 266, 0, @@ -1434,10 +1434,10 @@ func TestExportTxFees(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() fc := &FeeCalculator{ - feeManager: fees.NewManager(cfg.DefaultUnitFees), - Config: cfg, - ChainTime: chainTime, - Tx: sTx, + feeManager: fees.NewManager(cfg.DefaultUnitFees), + Config: cfg, + ChainTime: chainTime, + Credentials: sTx.Creds, } err := uTx.Visit(fc) r.ErrorIs(err, tt.expectedError) diff --git a/vms/platformvm/txs/executor/staker_tx_verification.go b/vms/platformvm/txs/executor/staker_tx_verification.go index b90d057780d0..3287b6c2c73d 100644 --- a/vms/platformvm/txs/executor/staker_tx_verification.go +++ b/vms/platformvm/txs/executor/staker_tx_verification.go @@ -163,10 +163,10 @@ func verifyAddValidatorTx( // Verify the flowcheck feeCalculator := FeeCalculator{ - feeManager: feeManager, - Config: backend.Config, - ChainTime: currentTimestamp, - Tx: sTx, + feeManager: feeManager, + Config: backend.Config, + ChainTime: currentTimestamp, + Credentials: sTx.Creds, } if err := tx.Visit(&feeCalculator); err != nil { return nil, err @@ -260,10 +260,10 @@ func verifyAddSubnetValidatorTx( // Verify the flowcheck feeCalculator := FeeCalculator{ - feeManager: feeManager, - Config: backend.Config, - ChainTime: currentTimestamp, - Tx: sTx, + feeManager: feeManager, + Config: backend.Config, + ChainTime: currentTimestamp, + Credentials: sTx.Creds, } if err := tx.Visit(&feeCalculator); err != nil { return err @@ -340,10 +340,10 @@ func verifyRemoveSubnetValidatorTx( // Verify the flowcheck feeCalculator := FeeCalculator{ - feeManager: feeManager, - Config: backend.Config, - ChainTime: chainState.GetTimestamp(), - Tx: sTx, + feeManager: feeManager, + Config: backend.Config, + ChainTime: chainState.GetTimestamp(), + Credentials: sTx.Creds, } if err := tx.Visit(&feeCalculator); err != nil { return nil, false, err @@ -463,10 +463,10 @@ func verifyAddDelegatorTx( // Verify the flowcheck feeCalculator := FeeCalculator{ - feeManager: feeManager, - Config: backend.Config, - ChainTime: chainState.GetTimestamp(), - Tx: sTx, + feeManager: feeManager, + Config: backend.Config, + ChainTime: chainState.GetTimestamp(), + Credentials: sTx.Creds, } if err := tx.Visit(&feeCalculator); err != nil { return nil, err @@ -589,10 +589,10 @@ func verifyAddPermissionlessValidatorTx( // Verify the flowcheck feeCalculator := FeeCalculator{ - feeManager: feeManager, - Config: backend.Config, - ChainTime: currentTimestamp, - Tx: sTx, + feeManager: feeManager, + Config: backend.Config, + ChainTime: currentTimestamp, + Credentials: sTx.Creds, } if err := tx.Visit(&feeCalculator); err != nil { return err @@ -738,10 +738,10 @@ func verifyAddPermissionlessDelegatorTx( // Verify the flowcheck feeCalculator := FeeCalculator{ - feeManager: feeManager, - Config: backend.Config, - ChainTime: currentTimestamp, - Tx: sTx, + feeManager: feeManager, + Config: backend.Config, + ChainTime: currentTimestamp, + Credentials: sTx.Creds, } if err := tx.Visit(&feeCalculator); err != nil { return err @@ -798,10 +798,10 @@ func verifyTransferSubnetOwnershipTx( // Verify the flowcheck feeCalculator := FeeCalculator{ - feeManager: feeManager, - Config: backend.Config, - ChainTime: chainState.GetTimestamp(), - Tx: sTx, + feeManager: feeManager, + Config: backend.Config, + ChainTime: chainState.GetTimestamp(), + Credentials: sTx.Creds, } if err := tx.Visit(&feeCalculator); err != nil { return err diff --git a/vms/platformvm/txs/executor/standard_tx_executor.go b/vms/platformvm/txs/executor/standard_tx_executor.go index 7fef238361cd..d26002cade2a 100644 --- a/vms/platformvm/txs/executor/standard_tx_executor.go +++ b/vms/platformvm/txs/executor/standard_tx_executor.go @@ -63,10 +63,10 @@ func (e *StandardTxExecutor) CreateChainTx(tx *txs.CreateChainTx) error { // Verify the flowcheck feeCalculator := FeeCalculator{ - feeManager: e.BlkFeeManager, - Config: e.Backend.Config, - ChainTime: e.State.GetTimestamp(), - Tx: e.Tx, + feeManager: e.BlkFeeManager, + Config: e.Backend.Config, + ChainTime: e.State.GetTimestamp(), + Credentials: e.Tx.Creds, } if err := tx.Visit(&feeCalculator); err != nil { return err @@ -110,10 +110,10 @@ func (e *StandardTxExecutor) CreateSubnetTx(tx *txs.CreateSubnetTx) error { // Verify the flowcheck feeCalculator := FeeCalculator{ - feeManager: e.BlkFeeManager, - Config: e.Backend.Config, - ChainTime: e.State.GetTimestamp(), - Tx: e.Tx, + feeManager: e.BlkFeeManager, + Config: e.Backend.Config, + ChainTime: e.State.GetTimestamp(), + Credentials: e.Tx.Creds, } if err := tx.Visit(&feeCalculator); err != nil { return err @@ -192,10 +192,10 @@ func (e *StandardTxExecutor) ImportTx(tx *txs.ImportTx) error { // Verify the flowcheck feeCalculator := FeeCalculator{ - feeManager: e.BlkFeeManager, - Config: e.Backend.Config, - ChainTime: e.State.GetTimestamp(), - Tx: e.Tx, + feeManager: e.BlkFeeManager, + Config: e.Backend.Config, + ChainTime: e.State.GetTimestamp(), + Credentials: e.Tx.Creds, } if err := tx.Visit(&feeCalculator); err != nil { return err @@ -250,10 +250,10 @@ func (e *StandardTxExecutor) ExportTx(tx *txs.ExportTx) error { // Verify the flowcheck feeCalculator := FeeCalculator{ - feeManager: e.BlkFeeManager, - Config: e.Backend.Config, - ChainTime: e.State.GetTimestamp(), - Tx: e.Tx, + feeManager: e.BlkFeeManager, + Config: e.Backend.Config, + ChainTime: e.State.GetTimestamp(), + Credentials: e.Tx.Creds, } if err := tx.Visit(&feeCalculator); err != nil { return err @@ -560,10 +560,10 @@ func (e *StandardTxExecutor) BaseTx(tx *txs.BaseTx) error { // Verify the flowcheck feeCalculator := FeeCalculator{ - feeManager: e.BlkFeeManager, - Config: e.Backend.Config, - ChainTime: e.State.GetTimestamp(), - Tx: e.Tx, + feeManager: e.BlkFeeManager, + Config: e.Backend.Config, + ChainTime: e.State.GetTimestamp(), + Credentials: e.Tx.Creds, } if err := tx.Visit(&feeCalculator); err != nil { return err From 85ae0692087f521471ffa3bb088992600c80532b Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 11 Jan 2024 16:49:53 +0100 Subject: [PATCH 024/190] repackaging --- vms/avm/block/executor/block.go | 2 +- vms/avm/block/executor/manager.go | 2 +- vms/avm/config/config.go | 2 +- vms/avm/txs/executor/fee_calculator.go | 2 +- vms/avm/txs/executor/fee_calculator_test.go | 2 +- vms/avm/txs/executor/syntactic_verifier.go | 2 +- vms/avm/vm.go | 2 +- vms/{platformvm => components}/fees/manager.go | 0 vms/platformvm/block/builder/builder.go | 2 +- vms/platformvm/block/builder/helpers_test.go | 2 +- vms/platformvm/block/executor/helpers_test.go | 2 +- vms/platformvm/block/executor/verifier.go | 2 +- vms/platformvm/config/config.go | 2 +- vms/platformvm/config/fee_config.go | 2 +- vms/platformvm/txs/executor/atomic_tx_executor.go | 2 +- vms/platformvm/txs/executor/create_chain_test.go | 2 +- vms/platformvm/txs/executor/create_subnet_test.go | 2 +- vms/platformvm/txs/executor/fee_calculator.go | 2 +- vms/platformvm/txs/executor/fee_calculator_test.go | 2 +- vms/platformvm/txs/executor/helpers_test.go | 2 +- vms/platformvm/txs/executor/proposal_tx_executor.go | 2 +- vms/platformvm/txs/executor/staker_tx_verification.go | 2 +- vms/platformvm/txs/executor/staker_tx_verification_test.go | 2 +- vms/platformvm/txs/executor/standard_tx_executor.go | 2 +- vms/platformvm/txs/executor/standard_tx_executor_test.go | 2 +- vms/platformvm/txs/executor/tx_mempool_verifier.go | 2 +- 26 files changed, 25 insertions(+), 25 deletions(-) rename vms/{platformvm => components}/fees/manager.go (100%) diff --git a/vms/avm/block/executor/block.go b/vms/avm/block/executor/block.go index 678ef54189b0..d0473737d67a 100644 --- a/vms/avm/block/executor/block.go +++ b/vms/avm/block/executor/block.go @@ -19,7 +19,7 @@ import ( "github.com/ava-labs/avalanchego/vms/avm/block" "github.com/ava-labs/avalanchego/vms/avm/state" "github.com/ava-labs/avalanchego/vms/avm/txs/executor" - "github.com/ava-labs/avalanchego/vms/platformvm/fees" + "github.com/ava-labs/avalanchego/vms/components/fees" ) const SyncBound = 10 * time.Second diff --git a/vms/avm/block/executor/manager.go b/vms/avm/block/executor/manager.go index f9ad014f9eb8..1ee0f7aef266 100644 --- a/vms/avm/block/executor/manager.go +++ b/vms/avm/block/executor/manager.go @@ -17,7 +17,7 @@ import ( "github.com/ava-labs/avalanchego/vms/avm/txs" "github.com/ava-labs/avalanchego/vms/avm/txs/executor" "github.com/ava-labs/avalanchego/vms/avm/txs/mempool" - "github.com/ava-labs/avalanchego/vms/platformvm/fees" + "github.com/ava-labs/avalanchego/vms/components/fees" ) var ( diff --git a/vms/avm/config/config.go b/vms/avm/config/config.go index 799f9a720e00..0561047f009d 100644 --- a/vms/avm/config/config.go +++ b/vms/avm/config/config.go @@ -7,7 +7,7 @@ import ( "math" "time" - "github.com/ava-labs/avalanchego/vms/platformvm/fees" + "github.com/ava-labs/avalanchego/vms/components/fees" ) // Struct collecting all the foundational parameters of the AVM diff --git a/vms/avm/txs/executor/fee_calculator.go b/vms/avm/txs/executor/fee_calculator.go index 741fdbd21eff..3702be1287a3 100644 --- a/vms/avm/txs/executor/fee_calculator.go +++ b/vms/avm/txs/executor/fee_calculator.go @@ -12,7 +12,7 @@ import ( "github.com/ava-labs/avalanchego/vms/avm/config" "github.com/ava-labs/avalanchego/vms/avm/txs" "github.com/ava-labs/avalanchego/vms/components/avax" - "github.com/ava-labs/avalanchego/vms/platformvm/fees" + "github.com/ava-labs/avalanchego/vms/components/fees" ) var ( diff --git a/vms/avm/txs/executor/fee_calculator_test.go b/vms/avm/txs/executor/fee_calculator_test.go index 4b500ad61caa..1a7cc6ccec91 100644 --- a/vms/avm/txs/executor/fee_calculator_test.go +++ b/vms/avm/txs/executor/fee_calculator_test.go @@ -22,9 +22,9 @@ import ( "github.com/ava-labs/avalanchego/vms/avm/fxs" "github.com/ava-labs/avalanchego/vms/avm/txs" "github.com/ava-labs/avalanchego/vms/components/avax" + "github.com/ava-labs/avalanchego/vms/components/fees" "github.com/ava-labs/avalanchego/vms/components/verify" "github.com/ava-labs/avalanchego/vms/nftfx" - "github.com/ava-labs/avalanchego/vms/platformvm/fees" "github.com/ava-labs/avalanchego/vms/secp256k1fx" ) diff --git a/vms/avm/txs/executor/syntactic_verifier.go b/vms/avm/txs/executor/syntactic_verifier.go index baeed6973987..7543eed8d249 100644 --- a/vms/avm/txs/executor/syntactic_verifier.go +++ b/vms/avm/txs/executor/syntactic_verifier.go @@ -15,7 +15,7 @@ import ( "github.com/ava-labs/avalanchego/utils/set" "github.com/ava-labs/avalanchego/vms/avm/txs" "github.com/ava-labs/avalanchego/vms/components/avax" - "github.com/ava-labs/avalanchego/vms/platformvm/fees" + "github.com/ava-labs/avalanchego/vms/components/fees" ) const ( diff --git a/vms/avm/vm.go b/vms/avm/vm.go index 55cd94e965fb..f42f0f8a83e1 100644 --- a/vms/avm/vm.go +++ b/vms/avm/vm.go @@ -42,9 +42,9 @@ import ( "github.com/ava-labs/avalanchego/vms/avm/txs/mempool" "github.com/ava-labs/avalanchego/vms/avm/utxo" "github.com/ava-labs/avalanchego/vms/components/avax" + "github.com/ava-labs/avalanchego/vms/components/fees" "github.com/ava-labs/avalanchego/vms/components/index" "github.com/ava-labs/avalanchego/vms/components/keystore" - "github.com/ava-labs/avalanchego/vms/platformvm/fees" "github.com/ava-labs/avalanchego/vms/secp256k1fx" blockbuilder "github.com/ava-labs/avalanchego/vms/avm/block/builder" diff --git a/vms/platformvm/fees/manager.go b/vms/components/fees/manager.go similarity index 100% rename from vms/platformvm/fees/manager.go rename to vms/components/fees/manager.go diff --git a/vms/platformvm/block/builder/builder.go b/vms/platformvm/block/builder/builder.go index d1e65e7e8a21..82f92076a91c 100644 --- a/vms/platformvm/block/builder/builder.go +++ b/vms/platformvm/block/builder/builder.go @@ -17,8 +17,8 @@ import ( "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/fees" "github.com/ava-labs/avalanchego/vms/platformvm/block" - "github.com/ava-labs/avalanchego/vms/platformvm/fees" "github.com/ava-labs/avalanchego/vms/platformvm/state" "github.com/ava-labs/avalanchego/vms/platformvm/status" "github.com/ava-labs/avalanchego/vms/platformvm/txs" diff --git a/vms/platformvm/block/builder/helpers_test.go b/vms/platformvm/block/builder/helpers_test.go index 3f563a0c55bd..ceacb117f14b 100644 --- a/vms/platformvm/block/builder/helpers_test.go +++ b/vms/platformvm/block/builder/helpers_test.go @@ -36,9 +36,9 @@ import ( "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/fees" "github.com/ava-labs/avalanchego/vms/platformvm/api" "github.com/ava-labs/avalanchego/vms/platformvm/config" - "github.com/ava-labs/avalanchego/vms/platformvm/fees" "github.com/ava-labs/avalanchego/vms/platformvm/fx" "github.com/ava-labs/avalanchego/vms/platformvm/metrics" "github.com/ava-labs/avalanchego/vms/platformvm/network" diff --git a/vms/platformvm/block/executor/helpers_test.go b/vms/platformvm/block/executor/helpers_test.go index 5e9278417923..2a848823dff5 100644 --- a/vms/platformvm/block/executor/helpers_test.go +++ b/vms/platformvm/block/executor/helpers_test.go @@ -36,9 +36,9 @@ import ( "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/fees" "github.com/ava-labs/avalanchego/vms/platformvm/api" "github.com/ava-labs/avalanchego/vms/platformvm/config" - "github.com/ava-labs/avalanchego/vms/platformvm/fees" "github.com/ava-labs/avalanchego/vms/platformvm/fx" "github.com/ava-labs/avalanchego/vms/platformvm/metrics" "github.com/ava-labs/avalanchego/vms/platformvm/reward" diff --git a/vms/platformvm/block/executor/verifier.go b/vms/platformvm/block/executor/verifier.go index 28502a51fef5..f880e5530b3c 100644 --- a/vms/platformvm/block/executor/verifier.go +++ b/vms/platformvm/block/executor/verifier.go @@ -10,8 +10,8 @@ import ( "github.com/ava-labs/avalanchego/chains/atomic" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils/set" + "github.com/ava-labs/avalanchego/vms/components/fees" "github.com/ava-labs/avalanchego/vms/platformvm/block" - "github.com/ava-labs/avalanchego/vms/platformvm/fees" "github.com/ava-labs/avalanchego/vms/platformvm/state" "github.com/ava-labs/avalanchego/vms/platformvm/status" "github.com/ava-labs/avalanchego/vms/platformvm/txs" diff --git a/vms/platformvm/config/config.go b/vms/platformvm/config/config.go index 83d421546011..00073586ddae 100644 --- a/vms/platformvm/config/config.go +++ b/vms/platformvm/config/config.go @@ -13,7 +13,7 @@ import ( "github.com/ava-labs/avalanchego/snow/validators" "github.com/ava-labs/avalanchego/utils/constants" "github.com/ava-labs/avalanchego/utils/set" - "github.com/ava-labs/avalanchego/vms/platformvm/fees" + "github.com/ava-labs/avalanchego/vms/components/fees" "github.com/ava-labs/avalanchego/vms/platformvm/reward" "github.com/ava-labs/avalanchego/vms/platformvm/txs" ) diff --git a/vms/platformvm/config/fee_config.go b/vms/platformvm/config/fee_config.go index 866ca53bfe2d..bb8c3b5ee99e 100644 --- a/vms/platformvm/config/fee_config.go +++ b/vms/platformvm/config/fee_config.go @@ -3,7 +3,7 @@ package config -import "github.com/ava-labs/avalanchego/vms/platformvm/fees" +import "github.com/ava-labs/avalanchego/vms/components/fees" type FeeConfig struct { // Post E Fork, the unit fee for each dimension, denominated in Avax diff --git a/vms/platformvm/txs/executor/atomic_tx_executor.go b/vms/platformvm/txs/executor/atomic_tx_executor.go index e89d6ca40e8c..987ff4cf51d7 100644 --- a/vms/platformvm/txs/executor/atomic_tx_executor.go +++ b/vms/platformvm/txs/executor/atomic_tx_executor.go @@ -7,7 +7,7 @@ import ( "github.com/ava-labs/avalanchego/chains/atomic" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils/set" - "github.com/ava-labs/avalanchego/vms/platformvm/fees" + "github.com/ava-labs/avalanchego/vms/components/fees" "github.com/ava-labs/avalanchego/vms/platformvm/state" "github.com/ava-labs/avalanchego/vms/platformvm/txs" ) diff --git a/vms/platformvm/txs/executor/create_chain_test.go b/vms/platformvm/txs/executor/create_chain_test.go index ecaf05a4ca20..18a8fb86eab1 100644 --- a/vms/platformvm/txs/executor/create_chain_test.go +++ b/vms/platformvm/txs/executor/create_chain_test.go @@ -16,7 +16,7 @@ import ( "github.com/ava-labs/avalanchego/utils/hashing" "github.com/ava-labs/avalanchego/utils/units" "github.com/ava-labs/avalanchego/vms/components/avax" - "github.com/ava-labs/avalanchego/vms/platformvm/fees" + "github.com/ava-labs/avalanchego/vms/components/fees" "github.com/ava-labs/avalanchego/vms/platformvm/state" "github.com/ava-labs/avalanchego/vms/platformvm/txs" "github.com/ava-labs/avalanchego/vms/platformvm/utxo" diff --git a/vms/platformvm/txs/executor/create_subnet_test.go b/vms/platformvm/txs/executor/create_subnet_test.go index 237f2986b2f6..666fa32f6e08 100644 --- a/vms/platformvm/txs/executor/create_subnet_test.go +++ b/vms/platformvm/txs/executor/create_subnet_test.go @@ -12,7 +12,7 @@ import ( "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils/units" "github.com/ava-labs/avalanchego/vms/components/avax" - "github.com/ava-labs/avalanchego/vms/platformvm/fees" + "github.com/ava-labs/avalanchego/vms/components/fees" "github.com/ava-labs/avalanchego/vms/platformvm/state" "github.com/ava-labs/avalanchego/vms/platformvm/txs" "github.com/ava-labs/avalanchego/vms/platformvm/utxo" diff --git a/vms/platformvm/txs/executor/fee_calculator.go b/vms/platformvm/txs/executor/fee_calculator.go index 063d43975da9..209b9d49ca0c 100644 --- a/vms/platformvm/txs/executor/fee_calculator.go +++ b/vms/platformvm/txs/executor/fee_calculator.go @@ -10,9 +10,9 @@ import ( "github.com/ava-labs/avalanchego/utils/constants" "github.com/ava-labs/avalanchego/vms/components/avax" + "github.com/ava-labs/avalanchego/vms/components/fees" "github.com/ava-labs/avalanchego/vms/components/verify" "github.com/ava-labs/avalanchego/vms/platformvm/config" - "github.com/ava-labs/avalanchego/vms/platformvm/fees" "github.com/ava-labs/avalanchego/vms/platformvm/txs" ) diff --git a/vms/platformvm/txs/executor/fee_calculator_test.go b/vms/platformvm/txs/executor/fee_calculator_test.go index 976ef90dd0ab..986561d6cb4d 100644 --- a/vms/platformvm/txs/executor/fee_calculator_test.go +++ b/vms/platformvm/txs/executor/fee_calculator_test.go @@ -16,8 +16,8 @@ import ( "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" "github.com/ava-labs/avalanchego/utils/units" "github.com/ava-labs/avalanchego/vms/components/avax" + "github.com/ava-labs/avalanchego/vms/components/fees" "github.com/ava-labs/avalanchego/vms/platformvm/config" - "github.com/ava-labs/avalanchego/vms/platformvm/fees" "github.com/ava-labs/avalanchego/vms/platformvm/reward" "github.com/ava-labs/avalanchego/vms/platformvm/signer" "github.com/ava-labs/avalanchego/vms/platformvm/stakeable" diff --git a/vms/platformvm/txs/executor/helpers_test.go b/vms/platformvm/txs/executor/helpers_test.go index 9043299e0e90..f80ff8fe5963 100644 --- a/vms/platformvm/txs/executor/helpers_test.go +++ b/vms/platformvm/txs/executor/helpers_test.go @@ -35,9 +35,9 @@ import ( "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/fees" "github.com/ava-labs/avalanchego/vms/platformvm/api" "github.com/ava-labs/avalanchego/vms/platformvm/config" - "github.com/ava-labs/avalanchego/vms/platformvm/fees" "github.com/ava-labs/avalanchego/vms/platformvm/fx" "github.com/ava-labs/avalanchego/vms/platformvm/metrics" "github.com/ava-labs/avalanchego/vms/platformvm/reward" diff --git a/vms/platformvm/txs/executor/proposal_tx_executor.go b/vms/platformvm/txs/executor/proposal_tx_executor.go index adb2d4da6ebb..18e5aa5b8675 100644 --- a/vms/platformvm/txs/executor/proposal_tx_executor.go +++ b/vms/platformvm/txs/executor/proposal_tx_executor.go @@ -13,8 +13,8 @@ import ( "github.com/ava-labs/avalanchego/utils/constants" "github.com/ava-labs/avalanchego/utils/math" "github.com/ava-labs/avalanchego/vms/components/avax" + "github.com/ava-labs/avalanchego/vms/components/fees" "github.com/ava-labs/avalanchego/vms/components/verify" - "github.com/ava-labs/avalanchego/vms/platformvm/fees" "github.com/ava-labs/avalanchego/vms/platformvm/reward" "github.com/ava-labs/avalanchego/vms/platformvm/state" "github.com/ava-labs/avalanchego/vms/platformvm/txs" diff --git a/vms/platformvm/txs/executor/staker_tx_verification.go b/vms/platformvm/txs/executor/staker_tx_verification.go index 3287b6c2c73d..b0ab5a369000 100644 --- a/vms/platformvm/txs/executor/staker_tx_verification.go +++ b/vms/platformvm/txs/executor/staker_tx_verification.go @@ -13,7 +13,7 @@ import ( "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils/constants" "github.com/ava-labs/avalanchego/vms/components/avax" - "github.com/ava-labs/avalanchego/vms/platformvm/fees" + "github.com/ava-labs/avalanchego/vms/components/fees" "github.com/ava-labs/avalanchego/vms/platformvm/state" "github.com/ava-labs/avalanchego/vms/platformvm/txs" diff --git a/vms/platformvm/txs/executor/staker_tx_verification_test.go b/vms/platformvm/txs/executor/staker_tx_verification_test.go index 844f5d8b33d7..7347c9a0f32e 100644 --- a/vms/platformvm/txs/executor/staker_tx_verification_test.go +++ b/vms/platformvm/txs/executor/staker_tx_verification_test.go @@ -19,9 +19,9 @@ import ( "github.com/ava-labs/avalanchego/utils/constants" "github.com/ava-labs/avalanchego/utils/timer/mockable" "github.com/ava-labs/avalanchego/vms/components/avax" + "github.com/ava-labs/avalanchego/vms/components/fees" "github.com/ava-labs/avalanchego/vms/components/verify" "github.com/ava-labs/avalanchego/vms/platformvm/config" - "github.com/ava-labs/avalanchego/vms/platformvm/fees" "github.com/ava-labs/avalanchego/vms/platformvm/state" "github.com/ava-labs/avalanchego/vms/platformvm/txs" "github.com/ava-labs/avalanchego/vms/platformvm/utxo" diff --git a/vms/platformvm/txs/executor/standard_tx_executor.go b/vms/platformvm/txs/executor/standard_tx_executor.go index d26002cade2a..2e50dc7119d5 100644 --- a/vms/platformvm/txs/executor/standard_tx_executor.go +++ b/vms/platformvm/txs/executor/standard_tx_executor.go @@ -16,8 +16,8 @@ import ( "github.com/ava-labs/avalanchego/utils/constants" "github.com/ava-labs/avalanchego/utils/set" "github.com/ava-labs/avalanchego/vms/components/avax" + "github.com/ava-labs/avalanchego/vms/components/fees" "github.com/ava-labs/avalanchego/vms/components/verify" - "github.com/ava-labs/avalanchego/vms/platformvm/fees" "github.com/ava-labs/avalanchego/vms/platformvm/state" "github.com/ava-labs/avalanchego/vms/platformvm/txs" ) diff --git a/vms/platformvm/txs/executor/standard_tx_executor_test.go b/vms/platformvm/txs/executor/standard_tx_executor_test.go index 424e548c3f43..c7e089f17fe0 100644 --- a/vms/platformvm/txs/executor/standard_tx_executor_test.go +++ b/vms/platformvm/txs/executor/standard_tx_executor_test.go @@ -23,9 +23,9 @@ import ( "github.com/ava-labs/avalanchego/utils/hashing" "github.com/ava-labs/avalanchego/utils/timer/mockable" "github.com/ava-labs/avalanchego/vms/components/avax" + "github.com/ava-labs/avalanchego/vms/components/fees" "github.com/ava-labs/avalanchego/vms/components/verify" "github.com/ava-labs/avalanchego/vms/platformvm/config" - "github.com/ava-labs/avalanchego/vms/platformvm/fees" "github.com/ava-labs/avalanchego/vms/platformvm/fx" "github.com/ava-labs/avalanchego/vms/platformvm/reward" "github.com/ava-labs/avalanchego/vms/platformvm/state" diff --git a/vms/platformvm/txs/executor/tx_mempool_verifier.go b/vms/platformvm/txs/executor/tx_mempool_verifier.go index 7a356aabfb38..83a13c86ff66 100644 --- a/vms/platformvm/txs/executor/tx_mempool_verifier.go +++ b/vms/platformvm/txs/executor/tx_mempool_verifier.go @@ -10,7 +10,7 @@ import ( "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils/timer/mockable" - "github.com/ava-labs/avalanchego/vms/platformvm/fees" + "github.com/ava-labs/avalanchego/vms/components/fees" "github.com/ava-labs/avalanchego/vms/platformvm/state" "github.com/ava-labs/avalanchego/vms/platformvm/txs" ) From e2742b1d9ed20f0c9b0e8b149f96e771443d2b8b Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 11 Jan 2024 16:58:15 +0100 Subject: [PATCH 025/190] p-chain fee calculator repackaging --- .../txs/executor/staker_tx_verification.go | 45 ++--- .../txs/executor/standard_tx_executor.go | 26 +-- .../fee_calculator.go => fees/calculator.go} | 64 +++---- .../calculator_test.go} | 161 +++++++++--------- 4 files changed, 150 insertions(+), 146 deletions(-) rename vms/platformvm/txs/{executor/fee_calculator.go => fees/calculator.go} (77%) rename vms/platformvm/txs/{executor/fee_calculator_test.go => fees/calculator_test.go} (90%) diff --git a/vms/platformvm/txs/executor/staker_tx_verification.go b/vms/platformvm/txs/executor/staker_tx_verification.go index b0ab5a369000..76832480359f 100644 --- a/vms/platformvm/txs/executor/staker_tx_verification.go +++ b/vms/platformvm/txs/executor/staker_tx_verification.go @@ -13,11 +13,12 @@ import ( "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils/constants" "github.com/ava-labs/avalanchego/vms/components/avax" - "github.com/ava-labs/avalanchego/vms/components/fees" "github.com/ava-labs/avalanchego/vms/platformvm/state" "github.com/ava-labs/avalanchego/vms/platformvm/txs" + "github.com/ava-labs/avalanchego/vms/platformvm/txs/fees" safemath "github.com/ava-labs/avalanchego/utils/math" + commonFees "github.com/ava-labs/avalanchego/vms/components/fees" ) var ( @@ -89,7 +90,7 @@ func verifySubnetValidatorPrimaryNetworkRequirements( // added to the staking set. func verifyAddValidatorTx( backend *Backend, - feeManager *fees.Manager, + feeManager *commonFees.Manager, chainState state.Chain, sTx *txs.Tx, tx *txs.AddValidatorTx, @@ -162,8 +163,8 @@ func verifyAddValidatorTx( } // Verify the flowcheck - feeCalculator := FeeCalculator{ - feeManager: feeManager, + feeCalculator := fees.Calculator{ + FeeManager: feeManager, Config: backend.Config, ChainTime: currentTimestamp, Credentials: sTx.Creds, @@ -194,7 +195,7 @@ func verifyAddValidatorTx( // AddSubnetValidatorTx. func verifyAddSubnetValidatorTx( backend *Backend, - feeManager *fees.Manager, + feeManager *commonFees.Manager, chainState state.Chain, sTx *txs.Tx, tx *txs.AddSubnetValidatorTx, @@ -259,8 +260,8 @@ func verifyAddSubnetValidatorTx( } // Verify the flowcheck - feeCalculator := FeeCalculator{ - feeManager: feeManager, + feeCalculator := fees.Calculator{ + FeeManager: feeManager, Config: backend.Config, ChainTime: currentTimestamp, Credentials: sTx.Creds, @@ -297,7 +298,7 @@ func verifyAddSubnetValidatorTx( // * The flow checker passes. func verifyRemoveSubnetValidatorTx( backend *Backend, - feeManager *fees.Manager, + feeManager *commonFees.Manager, chainState state.Chain, sTx *txs.Tx, tx *txs.RemoveSubnetValidatorTx, @@ -339,8 +340,8 @@ func verifyRemoveSubnetValidatorTx( } // Verify the flowcheck - feeCalculator := FeeCalculator{ - feeManager: feeManager, + feeCalculator := fees.Calculator{ + FeeManager: feeManager, Config: backend.Config, ChainTime: chainState.GetTimestamp(), Credentials: sTx.Creds, @@ -370,7 +371,7 @@ func verifyRemoveSubnetValidatorTx( // added to the staking set. func verifyAddDelegatorTx( backend *Backend, - feeManager *fees.Manager, + feeManager *commonFees.Manager, chainState state.Chain, sTx *txs.Tx, tx *txs.AddDelegatorTx, @@ -462,8 +463,8 @@ func verifyAddDelegatorTx( } // Verify the flowcheck - feeCalculator := FeeCalculator{ - feeManager: feeManager, + feeCalculator := fees.Calculator{ + FeeManager: feeManager, Config: backend.Config, ChainTime: chainState.GetTimestamp(), Credentials: sTx.Creds, @@ -494,7 +495,7 @@ func verifyAddDelegatorTx( // AddPermissionlessValidatorTx. func verifyAddPermissionlessValidatorTx( backend *Backend, - feeManager *fees.Manager, + feeManager *commonFees.Manager, chainState state.Chain, sTx *txs.Tx, tx *txs.AddPermissionlessValidatorTx, @@ -588,8 +589,8 @@ func verifyAddPermissionlessValidatorTx( copy(outs[len(tx.Outs):], tx.StakeOuts) // Verify the flowcheck - feeCalculator := FeeCalculator{ - feeManager: feeManager, + feeCalculator := fees.Calculator{ + FeeManager: feeManager, Config: backend.Config, ChainTime: currentTimestamp, Credentials: sTx.Creds, @@ -620,7 +621,7 @@ func verifyAddPermissionlessValidatorTx( // AddPermissionlessDelegatorTx. func verifyAddPermissionlessDelegatorTx( backend *Backend, - feeManager *fees.Manager, + feeManager *commonFees.Manager, chainState state.Chain, sTx *txs.Tx, tx *txs.AddPermissionlessDelegatorTx, @@ -737,8 +738,8 @@ func verifyAddPermissionlessDelegatorTx( } // Verify the flowcheck - feeCalculator := FeeCalculator{ - feeManager: feeManager, + feeCalculator := fees.Calculator{ + FeeManager: feeManager, Config: backend.Config, ChainTime: currentTimestamp, Credentials: sTx.Creds, @@ -772,7 +773,7 @@ func verifyAddPermissionlessDelegatorTx( // * The flow checker passes. func verifyTransferSubnetOwnershipTx( backend *Backend, - feeManager *fees.Manager, + feeManager *commonFees.Manager, chainState state.Chain, sTx *txs.Tx, tx *txs.TransferSubnetOwnershipTx, @@ -797,8 +798,8 @@ func verifyTransferSubnetOwnershipTx( } // Verify the flowcheck - feeCalculator := FeeCalculator{ - feeManager: feeManager, + feeCalculator := fees.Calculator{ + FeeManager: feeManager, Config: backend.Config, ChainTime: chainState.GetTimestamp(), Credentials: sTx.Creds, diff --git a/vms/platformvm/txs/executor/standard_tx_executor.go b/vms/platformvm/txs/executor/standard_tx_executor.go index 2e50dc7119d5..0abc86f9d099 100644 --- a/vms/platformvm/txs/executor/standard_tx_executor.go +++ b/vms/platformvm/txs/executor/standard_tx_executor.go @@ -16,10 +16,12 @@ import ( "github.com/ava-labs/avalanchego/utils/constants" "github.com/ava-labs/avalanchego/utils/set" "github.com/ava-labs/avalanchego/vms/components/avax" - "github.com/ava-labs/avalanchego/vms/components/fees" "github.com/ava-labs/avalanchego/vms/components/verify" "github.com/ava-labs/avalanchego/vms/platformvm/state" "github.com/ava-labs/avalanchego/vms/platformvm/txs" + "github.com/ava-labs/avalanchego/vms/platformvm/txs/fees" + + commonFees "github.com/ava-labs/avalanchego/vms/components/fees" ) var ( @@ -33,7 +35,7 @@ var ( type StandardTxExecutor struct { // inputs, to be filled before visitor methods are called *Backend - BlkFeeManager *fees.Manager + BlkFeeManager *commonFees.Manager State state.Diff // state is expected to be modified Tx *txs.Tx @@ -62,8 +64,8 @@ func (e *StandardTxExecutor) CreateChainTx(tx *txs.CreateChainTx) error { } // Verify the flowcheck - feeCalculator := FeeCalculator{ - feeManager: e.BlkFeeManager, + feeCalculator := fees.Calculator{ + FeeManager: e.BlkFeeManager, Config: e.Backend.Config, ChainTime: e.State.GetTimestamp(), Credentials: e.Tx.Creds, @@ -109,8 +111,8 @@ func (e *StandardTxExecutor) CreateSubnetTx(tx *txs.CreateSubnetTx) error { } // Verify the flowcheck - feeCalculator := FeeCalculator{ - feeManager: e.BlkFeeManager, + feeCalculator := fees.Calculator{ + FeeManager: e.BlkFeeManager, Config: e.Backend.Config, ChainTime: e.State.GetTimestamp(), Credentials: e.Tx.Creds, @@ -191,8 +193,8 @@ func (e *StandardTxExecutor) ImportTx(tx *txs.ImportTx) error { copy(ins[len(tx.Ins):], tx.ImportedInputs) // Verify the flowcheck - feeCalculator := FeeCalculator{ - feeManager: e.BlkFeeManager, + feeCalculator := fees.Calculator{ + FeeManager: e.BlkFeeManager, Config: e.Backend.Config, ChainTime: e.State.GetTimestamp(), Credentials: e.Tx.Creds, @@ -249,8 +251,8 @@ func (e *StandardTxExecutor) ExportTx(tx *txs.ExportTx) error { } // Verify the flowcheck - feeCalculator := FeeCalculator{ - feeManager: e.BlkFeeManager, + feeCalculator := fees.Calculator{ + FeeManager: e.BlkFeeManager, Config: e.Backend.Config, ChainTime: e.State.GetTimestamp(), Credentials: e.Tx.Creds, @@ -559,8 +561,8 @@ func (e *StandardTxExecutor) BaseTx(tx *txs.BaseTx) error { } // Verify the flowcheck - feeCalculator := FeeCalculator{ - feeManager: e.BlkFeeManager, + feeCalculator := fees.Calculator{ + FeeManager: e.BlkFeeManager, Config: e.Backend.Config, ChainTime: e.State.GetTimestamp(), Credentials: e.Tx.Creds, diff --git a/vms/platformvm/txs/executor/fee_calculator.go b/vms/platformvm/txs/fees/calculator.go similarity index 77% rename from vms/platformvm/txs/executor/fee_calculator.go rename to vms/platformvm/txs/fees/calculator.go index 209b9d49ca0c..441e26eddafe 100644 --- a/vms/platformvm/txs/executor/fee_calculator.go +++ b/vms/platformvm/txs/fees/calculator.go @@ -1,7 +1,7 @@ // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. // See the file LICENSE for licensing terms. -package executor +package fees import ( "errors" @@ -17,15 +17,15 @@ import ( ) var ( - _ txs.Visitor = (*FeeCalculator)(nil) + _ txs.Visitor = (*Calculator)(nil) errFailedFeeCalculation = errors.New("failed fee calculation") errFailedConsumedUnitsCumulation = errors.New("failed cumulating consumed units") ) -type FeeCalculator struct { +type Calculator struct { // setup, to be filled before visitor methods are called - feeManager *fees.Manager + FeeManager *fees.Manager Config *config.Config ChainTime time.Time @@ -36,7 +36,7 @@ type FeeCalculator struct { Fee uint64 } -func (fc *FeeCalculator) AddValidatorTx(tx *txs.AddValidatorTx) error { +func (fc *Calculator) AddValidatorTx(tx *txs.AddValidatorTx) error { if !fc.Config.IsEForkActivated(fc.ChainTime) { fc.Fee = fc.Config.AddPrimaryNetworkValidatorFee return nil @@ -51,11 +51,11 @@ func (fc *FeeCalculator) AddValidatorTx(tx *txs.AddValidatorTx) error { return err } - fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) + fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.FeeManager, consumedUnits) return err } -func (fc *FeeCalculator) AddSubnetValidatorTx(tx *txs.AddSubnetValidatorTx) error { +func (fc *Calculator) AddSubnetValidatorTx(tx *txs.AddSubnetValidatorTx) error { if !fc.Config.IsEForkActivated(fc.ChainTime) { fc.Fee = fc.Config.AddSubnetValidatorFee return nil @@ -66,11 +66,11 @@ func (fc *FeeCalculator) AddSubnetValidatorTx(tx *txs.AddSubnetValidatorTx) erro return err } - fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) + fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.FeeManager, consumedUnits) return err } -func (fc *FeeCalculator) AddDelegatorTx(tx *txs.AddDelegatorTx) error { +func (fc *Calculator) AddDelegatorTx(tx *txs.AddDelegatorTx) error { if !fc.Config.IsEForkActivated(fc.ChainTime) { fc.Fee = fc.Config.AddPrimaryNetworkDelegatorFee return nil @@ -85,11 +85,11 @@ func (fc *FeeCalculator) AddDelegatorTx(tx *txs.AddDelegatorTx) error { return err } - fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) + fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.FeeManager, consumedUnits) return err } -func (fc *FeeCalculator) CreateChainTx(tx *txs.CreateChainTx) error { +func (fc *Calculator) CreateChainTx(tx *txs.CreateChainTx) error { if !fc.Config.IsEForkActivated(fc.ChainTime) { fc.Fee = fc.Config.GetCreateBlockchainTxFee(fc.ChainTime) return nil @@ -100,11 +100,11 @@ func (fc *FeeCalculator) CreateChainTx(tx *txs.CreateChainTx) error { return err } - fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) + fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.FeeManager, consumedUnits) return err } -func (fc *FeeCalculator) CreateSubnetTx(tx *txs.CreateSubnetTx) error { +func (fc *Calculator) CreateSubnetTx(tx *txs.CreateSubnetTx) error { if !fc.Config.IsEForkActivated(fc.ChainTime) { fc.Fee = fc.Config.GetCreateSubnetTxFee(fc.ChainTime) return nil @@ -115,19 +115,19 @@ func (fc *FeeCalculator) CreateSubnetTx(tx *txs.CreateSubnetTx) error { return err } - fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) + fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.FeeManager, consumedUnits) return err } -func (*FeeCalculator) AdvanceTimeTx(*txs.AdvanceTimeTx) error { +func (*Calculator) AdvanceTimeTx(*txs.AdvanceTimeTx) error { return nil // no fees } -func (*FeeCalculator) RewardValidatorTx(*txs.RewardValidatorTx) error { +func (*Calculator) RewardValidatorTx(*txs.RewardValidatorTx) error { return nil // no fees } -func (fc *FeeCalculator) RemoveSubnetValidatorTx(tx *txs.RemoveSubnetValidatorTx) error { +func (fc *Calculator) RemoveSubnetValidatorTx(tx *txs.RemoveSubnetValidatorTx) error { if !fc.Config.IsEForkActivated(fc.ChainTime) { fc.Fee = fc.Config.TxFee return nil @@ -138,11 +138,11 @@ func (fc *FeeCalculator) RemoveSubnetValidatorTx(tx *txs.RemoveSubnetValidatorTx return err } - fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) + fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.FeeManager, consumedUnits) return err } -func (fc *FeeCalculator) TransformSubnetTx(tx *txs.TransformSubnetTx) error { +func (fc *Calculator) TransformSubnetTx(tx *txs.TransformSubnetTx) error { if !fc.Config.IsEForkActivated(fc.ChainTime) { fc.Fee = fc.Config.TransformSubnetTxFee return nil @@ -153,11 +153,11 @@ func (fc *FeeCalculator) TransformSubnetTx(tx *txs.TransformSubnetTx) error { return err } - fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) + fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.FeeManager, consumedUnits) return err } -func (fc *FeeCalculator) TransferSubnetOwnershipTx(tx *txs.TransferSubnetOwnershipTx) error { +func (fc *Calculator) TransferSubnetOwnershipTx(tx *txs.TransferSubnetOwnershipTx) error { if !fc.Config.IsEForkActivated(fc.ChainTime) { fc.Fee = fc.Config.TxFee return nil @@ -168,11 +168,11 @@ func (fc *FeeCalculator) TransferSubnetOwnershipTx(tx *txs.TransferSubnetOwnersh return err } - fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) + fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.FeeManager, consumedUnits) return err } -func (fc *FeeCalculator) AddPermissionlessValidatorTx(tx *txs.AddPermissionlessValidatorTx) error { +func (fc *Calculator) AddPermissionlessValidatorTx(tx *txs.AddPermissionlessValidatorTx) error { if !fc.Config.IsEForkActivated(fc.ChainTime) { if tx.Subnet != constants.PrimaryNetworkID { fc.Fee = fc.Config.AddSubnetValidatorFee @@ -191,11 +191,11 @@ func (fc *FeeCalculator) AddPermissionlessValidatorTx(tx *txs.AddPermissionlessV return err } - fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) + fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.FeeManager, consumedUnits) return err } -func (fc *FeeCalculator) AddPermissionlessDelegatorTx(tx *txs.AddPermissionlessDelegatorTx) error { +func (fc *Calculator) AddPermissionlessDelegatorTx(tx *txs.AddPermissionlessDelegatorTx) error { if !fc.Config.IsEForkActivated(fc.ChainTime) { if tx.Subnet != constants.PrimaryNetworkID { fc.Fee = fc.Config.AddSubnetDelegatorFee @@ -214,11 +214,11 @@ func (fc *FeeCalculator) AddPermissionlessDelegatorTx(tx *txs.AddPermissionlessD return err } - fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) + fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.FeeManager, consumedUnits) return err } -func (fc *FeeCalculator) BaseTx(tx *txs.BaseTx) error { +func (fc *Calculator) BaseTx(tx *txs.BaseTx) error { if !fc.Config.IsEForkActivated(fc.ChainTime) { fc.Fee = fc.Config.TxFee return nil @@ -229,11 +229,11 @@ func (fc *FeeCalculator) BaseTx(tx *txs.BaseTx) error { return err } - fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) + fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.FeeManager, consumedUnits) return err } -func (fc *FeeCalculator) ImportTx(tx *txs.ImportTx) error { +func (fc *Calculator) ImportTx(tx *txs.ImportTx) error { if !fc.Config.IsEForkActivated(fc.ChainTime) { fc.Fee = fc.Config.TxFee return nil @@ -248,11 +248,11 @@ func (fc *FeeCalculator) ImportTx(tx *txs.ImportTx) error { return err } - fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) + fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.FeeManager, consumedUnits) return err } -func (fc *FeeCalculator) ExportTx(tx *txs.ExportTx) error { +func (fc *Calculator) ExportTx(tx *txs.ExportTx) error { if !fc.Config.IsEForkActivated(fc.ChainTime) { fc.Fee = fc.Config.TxFee return nil @@ -267,7 +267,7 @@ func (fc *FeeCalculator) ExportTx(tx *txs.ExportTx) error { return err } - fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) + fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.FeeManager, consumedUnits) return err } diff --git a/vms/platformvm/txs/executor/fee_calculator_test.go b/vms/platformvm/txs/fees/calculator_test.go similarity index 90% rename from vms/platformvm/txs/executor/fee_calculator_test.go rename to vms/platformvm/txs/fees/calculator_test.go index 986561d6cb4d..d4e2065b0285 100644 --- a/vms/platformvm/txs/executor/fee_calculator_test.go +++ b/vms/platformvm/txs/fees/calculator_test.go @@ -1,7 +1,7 @@ // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. // See the file LICENSE for licensing terms. -package executor +package fees import ( "testing" @@ -51,6 +51,7 @@ var ( AddSubnetDelegatorFee: 9 * units.Avax, } + preFundedKeys = secp256k1.TestKeys() feeTestSigners = [][]*secp256k1.PrivateKey{preFundedKeys} feeTestDefaultStakeWeight = uint64(2024) durangoTime = time.Time{} // assume durango is active in these tests @@ -60,7 +61,7 @@ type feeTests struct { description string cfgAndChainTimeF func() (*config.Config, time.Time) expectedError error - checksF func(*testing.T, *FeeCalculator) + checksF func(*testing.T, *Calculator) } func TestAddValidatorTxFees(t *testing.T) { @@ -104,7 +105,7 @@ func TestAddValidatorTxFees(t *testing.T) { return cfg, chainTime }, expectedError: nil, - checksF: func(t *testing.T, fc *FeeCalculator) { + checksF: func(t *testing.T, fc *Calculator) { require.Equal(t, fc.Config.AddPrimaryNetworkValidatorFee, fc.Fee) }, }, @@ -123,7 +124,7 @@ func TestAddValidatorTxFees(t *testing.T) { return cfg, chainTime }, expectedError: nil, - checksF: func(t *testing.T, fc *FeeCalculator) { + checksF: func(t *testing.T, fc *Calculator) { require.Equal(t, 3719*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ @@ -132,7 +133,7 @@ func TestAddValidatorTxFees(t *testing.T) { 266, 0, }, - fc.feeManager.GetCumulatedUnits(), + fc.FeeManager.GetCumulatedUnits(), ) }, }, @@ -152,7 +153,7 @@ func TestAddValidatorTxFees(t *testing.T) { return cfg, chainTime }, expectedError: errFailedConsumedUnitsCumulation, - checksF: func(t *testing.T, fc *FeeCalculator) {}, + checksF: func(t *testing.T, fc *Calculator) {}, }, } @@ -160,8 +161,8 @@ func TestAddValidatorTxFees(t *testing.T) { t.Run(tt.description, func(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() - fc := &FeeCalculator{ - feeManager: fees.NewManager(cfg.DefaultUnitFees), + fc := &Calculator{ + FeeManager: fees.NewManager(cfg.DefaultUnitFees), Config: cfg, ChainTime: chainTime, Credentials: sTx.Creds, @@ -212,7 +213,7 @@ func TestAddSubnetValidatorTxFees(t *testing.T) { return cfg, chainTime }, expectedError: nil, - checksF: func(t *testing.T, fc *FeeCalculator) { + checksF: func(t *testing.T, fc *Calculator) { require.Equal(t, fc.Config.AddSubnetValidatorFee, fc.Fee) }, }, @@ -231,7 +232,7 @@ func TestAddSubnetValidatorTxFees(t *testing.T) { return cfg, chainTime }, expectedError: nil, - checksF: func(t *testing.T, fc *FeeCalculator) { + checksF: func(t *testing.T, fc *Calculator) { require.Equal(t, 3345*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ @@ -240,7 +241,7 @@ func TestAddSubnetValidatorTxFees(t *testing.T) { 172, 0, }, - fc.feeManager.GetCumulatedUnits(), + fc.FeeManager.GetCumulatedUnits(), ) }, }, @@ -260,7 +261,7 @@ func TestAddSubnetValidatorTxFees(t *testing.T) { return cfg, chainTime }, expectedError: errFailedConsumedUnitsCumulation, - checksF: func(t *testing.T, fc *FeeCalculator) {}, + checksF: func(t *testing.T, fc *Calculator) {}, }, } @@ -268,8 +269,8 @@ func TestAddSubnetValidatorTxFees(t *testing.T) { t.Run(tt.description, func(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() - fc := &FeeCalculator{ - feeManager: fees.NewManager(cfg.DefaultUnitFees), + fc := &Calculator{ + FeeManager: fees.NewManager(cfg.DefaultUnitFees), Config: cfg, ChainTime: chainTime, Credentials: sTx.Creds, @@ -321,7 +322,7 @@ func TestAddDelegatorTxFees(t *testing.T) { return cfg, chainTime }, expectedError: nil, - checksF: func(t *testing.T, fc *FeeCalculator) { + checksF: func(t *testing.T, fc *Calculator) { require.Equal(t, fc.Config.AddPrimaryNetworkDelegatorFee, fc.Fee) }, }, @@ -340,7 +341,7 @@ func TestAddDelegatorTxFees(t *testing.T) { return cfg, chainTime }, expectedError: nil, - checksF: func(t *testing.T, fc *FeeCalculator) { + checksF: func(t *testing.T, fc *Calculator) { require.Equal(t, 3715*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ @@ -349,7 +350,7 @@ func TestAddDelegatorTxFees(t *testing.T) { 266, 0, }, - fc.feeManager.GetCumulatedUnits(), + fc.FeeManager.GetCumulatedUnits(), ) }, }, @@ -369,7 +370,7 @@ func TestAddDelegatorTxFees(t *testing.T) { return cfg, chainTime }, expectedError: errFailedConsumedUnitsCumulation, - checksF: func(t *testing.T, fc *FeeCalculator) {}, + checksF: func(t *testing.T, fc *Calculator) {}, }, } @@ -377,8 +378,8 @@ func TestAddDelegatorTxFees(t *testing.T) { t.Run(tt.description, func(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() - fc := &FeeCalculator{ - feeManager: fees.NewManager(cfg.DefaultUnitFees), + fc := &Calculator{ + FeeManager: fees.NewManager(cfg.DefaultUnitFees), Config: cfg, ChainTime: chainTime, Credentials: sTx.Creds, @@ -424,7 +425,7 @@ func TestCreateChainTxFees(t *testing.T) { return cfg, chainTime }, expectedError: nil, - checksF: func(t *testing.T, fc *FeeCalculator) { + checksF: func(t *testing.T, fc *Calculator) { require.Equal(t, fc.Config.CreateBlockchainTxFee, fc.Fee) }, }, @@ -443,7 +444,7 @@ func TestCreateChainTxFees(t *testing.T) { return cfg, chainTime }, expectedError: nil, - checksF: func(t *testing.T, fc *FeeCalculator) { + checksF: func(t *testing.T, fc *Calculator) { require.Equal(t, 3388*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ @@ -452,7 +453,7 @@ func TestCreateChainTxFees(t *testing.T) { 172, 0, }, - fc.feeManager.GetCumulatedUnits(), + fc.FeeManager.GetCumulatedUnits(), ) }, }, @@ -472,7 +473,7 @@ func TestCreateChainTxFees(t *testing.T) { return cfg, chainTime }, expectedError: errFailedConsumedUnitsCumulation, - checksF: func(t *testing.T, fc *FeeCalculator) {}, + checksF: func(t *testing.T, fc *Calculator) {}, }, } @@ -480,8 +481,8 @@ func TestCreateChainTxFees(t *testing.T) { t.Run(tt.description, func(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() - fc := &FeeCalculator{ - feeManager: fees.NewManager(cfg.DefaultUnitFees), + fc := &Calculator{ + FeeManager: fees.NewManager(cfg.DefaultUnitFees), Config: cfg, ChainTime: chainTime, Credentials: sTx.Creds, @@ -525,7 +526,7 @@ func TestCreateSubnetTxFees(t *testing.T) { return cfg, chainTime }, expectedError: nil, - checksF: func(t *testing.T, fc *FeeCalculator) { + checksF: func(t *testing.T, fc *Calculator) { require.Equal(t, fc.Config.CreateSubnetTxFee, fc.Fee) }, }, @@ -544,7 +545,7 @@ func TestCreateSubnetTxFees(t *testing.T) { return cfg, chainTime }, expectedError: nil, - checksF: func(t *testing.T, fc *FeeCalculator) { + checksF: func(t *testing.T, fc *Calculator) { require.Equal(t, 3293*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ @@ -553,7 +554,7 @@ func TestCreateSubnetTxFees(t *testing.T) { 172, 0, }, - fc.feeManager.GetCumulatedUnits(), + fc.FeeManager.GetCumulatedUnits(), ) }, }, @@ -573,7 +574,7 @@ func TestCreateSubnetTxFees(t *testing.T) { return cfg, chainTime }, expectedError: errFailedConsumedUnitsCumulation, - checksF: func(t *testing.T, fc *FeeCalculator) {}, + checksF: func(t *testing.T, fc *Calculator) {}, }, } @@ -581,8 +582,8 @@ func TestCreateSubnetTxFees(t *testing.T) { t.Run(tt.description, func(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() - fc := &FeeCalculator{ - feeManager: fees.NewManager(cfg.DefaultUnitFees), + fc := &Calculator{ + FeeManager: fees.NewManager(cfg.DefaultUnitFees), Config: cfg, ChainTime: chainTime, Credentials: sTx.Creds, @@ -625,7 +626,7 @@ func TestRemoveSubnetValidatorTxFees(t *testing.T) { return cfg, chainTime }, expectedError: nil, - checksF: func(t *testing.T, fc *FeeCalculator) { + checksF: func(t *testing.T, fc *Calculator) { require.Equal(t, fc.Config.TxFee, fc.Fee) }, }, @@ -644,7 +645,7 @@ func TestRemoveSubnetValidatorTxFees(t *testing.T) { return cfg, chainTime }, expectedError: nil, - checksF: func(t *testing.T, fc *FeeCalculator) { + checksF: func(t *testing.T, fc *Calculator) { require.Equal(t, 3321*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ @@ -653,7 +654,7 @@ func TestRemoveSubnetValidatorTxFees(t *testing.T) { 172, 0, }, - fc.feeManager.GetCumulatedUnits(), + fc.FeeManager.GetCumulatedUnits(), ) }, }, @@ -673,7 +674,7 @@ func TestRemoveSubnetValidatorTxFees(t *testing.T) { return cfg, chainTime }, expectedError: errFailedConsumedUnitsCumulation, - checksF: func(t *testing.T, fc *FeeCalculator) {}, + checksF: func(t *testing.T, fc *Calculator) {}, }, } @@ -681,8 +682,8 @@ func TestRemoveSubnetValidatorTxFees(t *testing.T) { t.Run(tt.description, func(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() - fc := &FeeCalculator{ - feeManager: fees.NewManager(cfg.DefaultUnitFees), + fc := &Calculator{ + FeeManager: fees.NewManager(cfg.DefaultUnitFees), Config: cfg, ChainTime: chainTime, Credentials: sTx.Creds, @@ -737,7 +738,7 @@ func TestTransformSubnetTxFees(t *testing.T) { return cfg, chainTime }, expectedError: nil, - checksF: func(t *testing.T, fc *FeeCalculator) { + checksF: func(t *testing.T, fc *Calculator) { require.Equal(t, fc.Config.TransformSubnetTxFee, fc.Fee) }, }, @@ -756,7 +757,7 @@ func TestTransformSubnetTxFees(t *testing.T) { return cfg, chainTime }, expectedError: nil, - checksF: func(t *testing.T, fc *FeeCalculator) { + checksF: func(t *testing.T, fc *Calculator) { require.Equal(t, 3406*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ @@ -765,7 +766,7 @@ func TestTransformSubnetTxFees(t *testing.T) { 172, 0, }, - fc.feeManager.GetCumulatedUnits(), + fc.FeeManager.GetCumulatedUnits(), ) }, }, @@ -785,7 +786,7 @@ func TestTransformSubnetTxFees(t *testing.T) { return cfg, chainTime }, expectedError: errFailedConsumedUnitsCumulation, - checksF: func(t *testing.T, fc *FeeCalculator) {}, + checksF: func(t *testing.T, fc *Calculator) {}, }, } @@ -793,8 +794,8 @@ func TestTransformSubnetTxFees(t *testing.T) { t.Run(tt.description, func(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() - fc := &FeeCalculator{ - feeManager: fees.NewManager(cfg.DefaultUnitFees), + fc := &Calculator{ + FeeManager: fees.NewManager(cfg.DefaultUnitFees), Config: cfg, ChainTime: chainTime, Credentials: sTx.Creds, @@ -845,7 +846,7 @@ func TestTransferSubnetOwnershipTxFees(t *testing.T) { return cfg, chainTime }, expectedError: nil, - checksF: func(t *testing.T, fc *FeeCalculator) { + checksF: func(t *testing.T, fc *Calculator) { require.Equal(t, fc.Config.TxFee, fc.Fee) }, }, @@ -864,7 +865,7 @@ func TestTransferSubnetOwnershipTxFees(t *testing.T) { return cfg, chainTime }, expectedError: nil, - checksF: func(t *testing.T, fc *FeeCalculator) { + checksF: func(t *testing.T, fc *Calculator) { require.Equal(t, 3337*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ @@ -873,7 +874,7 @@ func TestTransferSubnetOwnershipTxFees(t *testing.T) { 172, 0, }, - fc.feeManager.GetCumulatedUnits(), + fc.FeeManager.GetCumulatedUnits(), ) }, }, @@ -893,7 +894,7 @@ func TestTransferSubnetOwnershipTxFees(t *testing.T) { return cfg, chainTime }, expectedError: errFailedConsumedUnitsCumulation, - checksF: func(t *testing.T, fc *FeeCalculator) {}, + checksF: func(t *testing.T, fc *Calculator) {}, }, } @@ -901,8 +902,8 @@ func TestTransferSubnetOwnershipTxFees(t *testing.T) { t.Run(tt.description, func(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() - fc := &FeeCalculator{ - feeManager: fees.NewManager(cfg.DefaultUnitFees), + fc := &Calculator{ + FeeManager: fees.NewManager(cfg.DefaultUnitFees), Config: cfg, ChainTime: chainTime, Credentials: sTx.Creds, @@ -962,7 +963,7 @@ func TestAddPermissionlessValidatorTxFees(t *testing.T) { return cfg, chainTime }, expectedError: nil, - checksF: func(t *testing.T, fc *FeeCalculator) { + checksF: func(t *testing.T, fc *Calculator) { require.Equal(t, fc.Config.AddSubnetValidatorFee, fc.Fee) }, }, @@ -981,7 +982,7 @@ func TestAddPermissionlessValidatorTxFees(t *testing.T) { return cfg, chainTime }, expectedError: nil, - checksF: func(t *testing.T, fc *FeeCalculator) { + checksF: func(t *testing.T, fc *Calculator) { require.Equal(t, 3939*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ @@ -990,7 +991,7 @@ func TestAddPermissionlessValidatorTxFees(t *testing.T) { 266, 0, }, - fc.feeManager.GetCumulatedUnits(), + fc.FeeManager.GetCumulatedUnits(), ) }, }, @@ -1010,7 +1011,7 @@ func TestAddPermissionlessValidatorTxFees(t *testing.T) { return cfg, chainTime }, expectedError: errFailedConsumedUnitsCumulation, - checksF: func(t *testing.T, fc *FeeCalculator) {}, + checksF: func(t *testing.T, fc *Calculator) {}, }, } @@ -1018,8 +1019,8 @@ func TestAddPermissionlessValidatorTxFees(t *testing.T) { t.Run(tt.description, func(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() - fc := &FeeCalculator{ - feeManager: fees.NewManager(cfg.DefaultUnitFees), + fc := &Calculator{ + FeeManager: fees.NewManager(cfg.DefaultUnitFees), Config: cfg, ChainTime: chainTime, Credentials: sTx.Creds, @@ -1074,7 +1075,7 @@ func TestAddPermissionlessDelegatorTxFees(t *testing.T) { return cfg, chainTime }, expectedError: nil, - checksF: func(t *testing.T, fc *FeeCalculator) { + checksF: func(t *testing.T, fc *Calculator) { require.Equal(t, fc.Config.AddSubnetDelegatorFee, fc.Fee) }, }, @@ -1093,7 +1094,7 @@ func TestAddPermissionlessDelegatorTxFees(t *testing.T) { return cfg, chainTime }, expectedError: nil, - checksF: func(t *testing.T, fc *FeeCalculator) { + checksF: func(t *testing.T, fc *Calculator) { require.Equal(t, 3747*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ @@ -1102,7 +1103,7 @@ func TestAddPermissionlessDelegatorTxFees(t *testing.T) { 266, 0, }, - fc.feeManager.GetCumulatedUnits(), + fc.FeeManager.GetCumulatedUnits(), ) }, }, @@ -1122,7 +1123,7 @@ func TestAddPermissionlessDelegatorTxFees(t *testing.T) { return cfg, chainTime }, expectedError: errFailedConsumedUnitsCumulation, - checksF: func(t *testing.T, fc *FeeCalculator) {}, + checksF: func(t *testing.T, fc *Calculator) {}, }, } @@ -1130,8 +1131,8 @@ func TestAddPermissionlessDelegatorTxFees(t *testing.T) { t.Run(tt.description, func(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() - fc := &FeeCalculator{ - feeManager: fees.NewManager(cfg.DefaultUnitFees), + fc := &Calculator{ + FeeManager: fees.NewManager(cfg.DefaultUnitFees), Config: cfg, ChainTime: chainTime, Credentials: sTx.Creds, @@ -1169,7 +1170,7 @@ func TestBaseTxFees(t *testing.T) { return cfg, chainTime }, expectedError: nil, - checksF: func(t *testing.T, fc *FeeCalculator) { + checksF: func(t *testing.T, fc *Calculator) { require.Equal(t, fc.Config.TxFee, fc.Fee) }, }, @@ -1188,7 +1189,7 @@ func TestBaseTxFees(t *testing.T) { return cfg, chainTime }, expectedError: nil, - checksF: func(t *testing.T, fc *FeeCalculator) { + checksF: func(t *testing.T, fc *Calculator) { require.Equal(t, 3253*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ @@ -1197,7 +1198,7 @@ func TestBaseTxFees(t *testing.T) { 172, 0, }, - fc.feeManager.GetCumulatedUnits(), + fc.FeeManager.GetCumulatedUnits(), ) }, }, @@ -1217,7 +1218,7 @@ func TestBaseTxFees(t *testing.T) { return cfg, chainTime }, expectedError: errFailedConsumedUnitsCumulation, - checksF: func(t *testing.T, fc *FeeCalculator) {}, + checksF: func(t *testing.T, fc *Calculator) {}, }, } @@ -1225,8 +1226,8 @@ func TestBaseTxFees(t *testing.T) { t.Run(tt.description, func(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() - fc := &FeeCalculator{ - feeManager: fees.NewManager(cfg.DefaultUnitFees), + fc := &Calculator{ + FeeManager: fees.NewManager(cfg.DefaultUnitFees), Config: cfg, ChainTime: chainTime, Credentials: sTx.Creds, @@ -1278,7 +1279,7 @@ func TestImportTxFees(t *testing.T) { return cfg, chainTime }, expectedError: nil, - checksF: func(t *testing.T, fc *FeeCalculator) { + checksF: func(t *testing.T, fc *Calculator) { require.Equal(t, fc.Config.TxFee, fc.Fee) }, }, @@ -1297,7 +1298,7 @@ func TestImportTxFees(t *testing.T) { return cfg, chainTime }, expectedError: nil, - checksF: func(t *testing.T, fc *FeeCalculator) { + checksF: func(t *testing.T, fc *Calculator) { require.Equal(t, 5827*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ @@ -1306,7 +1307,7 @@ func TestImportTxFees(t *testing.T) { 262, 0, }, - fc.feeManager.GetCumulatedUnits(), + fc.FeeManager.GetCumulatedUnits(), ) }, }, @@ -1326,7 +1327,7 @@ func TestImportTxFees(t *testing.T) { return cfg, chainTime }, expectedError: errFailedConsumedUnitsCumulation, - checksF: func(t *testing.T, fc *FeeCalculator) {}, + checksF: func(t *testing.T, fc *Calculator) {}, }, } @@ -1334,8 +1335,8 @@ func TestImportTxFees(t *testing.T) { t.Run(tt.description, func(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() - fc := &FeeCalculator{ - feeManager: fees.NewManager(cfg.DefaultUnitFees), + fc := &Calculator{ + FeeManager: fees.NewManager(cfg.DefaultUnitFees), Config: cfg, ChainTime: chainTime, Credentials: sTx.Creds, @@ -1377,7 +1378,7 @@ func TestExportTxFees(t *testing.T) { return cfg, chainTime }, expectedError: nil, - checksF: func(t *testing.T, fc *FeeCalculator) { + checksF: func(t *testing.T, fc *Calculator) { require.Equal(t, fc.Config.TxFee, fc.Fee) }, }, @@ -1396,7 +1397,7 @@ func TestExportTxFees(t *testing.T) { return cfg, chainTime }, expectedError: nil, - checksF: func(t *testing.T, fc *FeeCalculator) { + checksF: func(t *testing.T, fc *Calculator) { require.Equal(t, 3663*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ @@ -1405,7 +1406,7 @@ func TestExportTxFees(t *testing.T) { 266, 0, }, - fc.feeManager.GetCumulatedUnits(), + fc.FeeManager.GetCumulatedUnits(), ) }, }, @@ -1425,7 +1426,7 @@ func TestExportTxFees(t *testing.T) { return cfg, chainTime }, expectedError: errFailedConsumedUnitsCumulation, - checksF: func(t *testing.T, fc *FeeCalculator) {}, + checksF: func(t *testing.T, fc *Calculator) {}, }, } @@ -1433,8 +1434,8 @@ func TestExportTxFees(t *testing.T) { t.Run(tt.description, func(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() - fc := &FeeCalculator{ - feeManager: fees.NewManager(cfg.DefaultUnitFees), + fc := &Calculator{ + FeeManager: fees.NewManager(cfg.DefaultUnitFees), Config: cfg, ChainTime: chainTime, Credentials: sTx.Creds, From 687dcf0ff320c210158d71d33f65d85a95cc6f8b Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 11 Jan 2024 17:44:01 +0100 Subject: [PATCH 026/190] EXTENDED CODEC SIZE TO PROCESS PARTIALLY FILLED TXS --- codec/reflectcodec/type_codec.go | 6 +-- vms/platformvm/txs/fees/calculator_test.go | 51 ++++++++++++++++++++++ 2 files changed, 54 insertions(+), 3 deletions(-) diff --git a/codec/reflectcodec/type_codec.go b/codec/reflectcodec/type_codec.go index 312927559280..628fe72fec43 100644 --- a/codec/reflectcodec/type_codec.go +++ b/codec/reflectcodec/type_codec.go @@ -90,7 +90,7 @@ func New(typer TypeCodec, tagNames []string, durangoTime time.Time, maxSliceLen func (c *genericCodec) Size(value interface{}) (int, error) { if value == nil { - return 0, errMarshalNil // can't marshal nil + return 0, nil // can't marshal nil } size, _, err := c.size(reflect.ValueOf(value), nil /*=typeStack*/) @@ -126,14 +126,14 @@ func (c *genericCodec) size( return wrappers.StringLen(value.String()), false, nil case reflect.Ptr: if value.IsNil() { - return 0, false, errMarshalNil + return 0, true, nil } return c.size(value.Elem(), typeStack) case reflect.Interface: if value.IsNil() { - return 0, false, errMarshalNil + return 0, true, nil } underlyingValue := value.Interface() diff --git a/vms/platformvm/txs/fees/calculator_test.go b/vms/platformvm/txs/fees/calculator_test.go index d4e2065b0285..de3b320ebc36 100644 --- a/vms/platformvm/txs/fees/calculator_test.go +++ b/vms/platformvm/txs/fees/calculator_test.go @@ -17,6 +17,7 @@ import ( "github.com/ava-labs/avalanchego/utils/units" "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/components/fees" + "github.com/ava-labs/avalanchego/vms/components/verify" "github.com/ava-labs/avalanchego/vms/platformvm/config" "github.com/ava-labs/avalanchego/vms/platformvm/reward" "github.com/ava-labs/avalanchego/vms/platformvm/signer" @@ -64,6 +65,56 @@ type feeTests struct { checksF func(*testing.T, *Calculator) } +func TestPartiallyFulledTransactionsSizes(t *testing.T) { + var uTx *txs.AddValidatorTx + uTxSize, err := txs.Codec.Size(txs.CodecVersion, uTx) + require.NoError(t, err) + require.Equal(t, uTxSize, 2) + + uTx = &txs.AddValidatorTx{} + uTxSize, err = txs.Codec.Size(txs.CodecVersion, uTx) + require.NoError(t, err) + require.Equal(t, uTxSize, 102) + + // array of nil elements has size 0. + creds := make([]verify.Verifiable, 10) + uTxSize, err = txs.Codec.Size(txs.CodecVersion, creds) + require.NoError(t, err) + require.Equal(t, uTxSize, 6) + + creds[0] = &secp256k1fx.Credential{ + Sigs: make([][secp256k1.SignatureLen]byte, 5), + } + uTxSize, err = txs.Codec.Size(txs.CodecVersion, creds) + require.NoError(t, err) + require.Equal(t, uTxSize, 339) + + var sTx *txs.Tx + uTxSize, err = txs.Codec.Size(txs.CodecVersion, sTx) + require.NoError(t, err) + require.Equal(t, uTxSize, 2) + + sTx = &txs.Tx{} + uTxSize, err = txs.Codec.Size(txs.CodecVersion, sTx) + require.NoError(t, err) + require.Equal(t, uTxSize, 6) + + sTx = &txs.Tx{ + Unsigned: uTx, + } + uTxSize, err = txs.Codec.Size(txs.CodecVersion, sTx) + require.NoError(t, err) + require.Equal(t, uTxSize, 110) + + sTx = &txs.Tx{ + Unsigned: uTx, + Creds: creds, + } + uTxSize, err = txs.Codec.Size(txs.CodecVersion, sTx) + require.NoError(t, err) + require.Equal(t, uTxSize, 443) +} + func TestAddValidatorTxFees(t *testing.T) { r := require.New(t) From f40fa5ebf514bc1b1f5c6a64140b86fe160ef5fe Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 11 Jan 2024 18:15:01 +0100 Subject: [PATCH 027/190] nit --- vms/platformvm/txs/builder/builder.go | 242 +++++++++++++++----------- 1 file changed, 140 insertions(+), 102 deletions(-) diff --git a/vms/platformvm/txs/builder/builder.go b/vms/platformvm/txs/builder/builder.go index 3427bf2b1015..8a005d41480c 100644 --- a/vms/platformvm/txs/builder/builder.go +++ b/vms/platformvm/txs/builder/builder.go @@ -229,6 +229,16 @@ func (b *builder) NewImportTx( keys []*secp256k1.PrivateKey, changeAddr ids.ShortID, ) (*txs.Tx, error) { + // 1. Build core transaction without utxos + utx := &txs.ImportTx{ + BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ + NetworkID: b.ctx.NetworkID, + BlockchainID: b.ctx.ChainID, + }}, + SourceChain: from, + } + + // 2. Finance the tx by building the utxos (inputs, outputs and stakes) kc := secp256k1fx.NewKeychain(keys...) atomicUTXOs, _, _, err := b.GetAtomicUTXOs(from, kc.Addresses(), ids.ShortEmpty, ids.Empty, MaxPageSize) @@ -303,17 +313,11 @@ func (b *builder) NewImportTx( avax.SortTransferableOutputs(outs, txs.Codec) // sort imported outputs - // Create the transaction - utx := &txs.ImportTx{ - BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ - NetworkID: b.ctx.NetworkID, - BlockchainID: b.ctx.ChainID, - Outs: outs, - Ins: ins, - }}, - SourceChain: from, - ImportedInputs: importedInputs, - } + utx.BaseTx.Ins = ins + utx.BaseTx.Outs = outs + utx.ImportedInputs = importedInputs + + // 3. Sign the tx tx, err := txs.NewSigned(utx, txs.Codec, signers) if err != nil { return nil, err @@ -329,22 +333,11 @@ func (b *builder) NewExportTx( keys []*secp256k1.PrivateKey, changeAddr ids.ShortID, ) (*txs.Tx, error) { - toBurn, err := math.Add64(amount, b.cfg.TxFee) - if err != nil { - return nil, fmt.Errorf("amount (%d) + tx fee(%d) overflows", amount, b.cfg.TxFee) - } - ins, outs, _, signers, err := b.Spend(b.state, keys, 0, toBurn, changeAddr) - if err != nil { - return nil, fmt.Errorf("couldn't generate tx inputs/outputs: %w", err) - } - - // Create the transaction + // 1. Build core transaction without utxos utx := &txs.ExportTx{ BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ NetworkID: b.ctx.NetworkID, BlockchainID: b.ctx.ChainID, - Ins: ins, - Outs: outs, // Non-exported outputs }}, DestinationChain: chainID, ExportedOutputs: []*avax.TransferableOutput{{ // Exported to X-Chain @@ -359,6 +352,21 @@ func (b *builder) NewExportTx( }, }}, } + + // 2. Finance the tx by building the utxos (inputs, outputs and stakes) + toBurn, err := math.Add64(amount, b.cfg.TxFee) + if err != nil { + return nil, fmt.Errorf("amount (%d) + tx fee(%d) overflows", amount, b.cfg.TxFee) + } + ins, outs, _, signers, err := b.Spend(b.state, keys, 0, toBurn, changeAddr) + if err != nil { + return nil, fmt.Errorf("couldn't generate tx inputs/outputs: %w", err) + } + + utx.BaseTx.Ins = ins + utx.BaseTx.Outs = outs + + // 3. Sign the tx tx, err := txs.NewSigned(utx, txs.Codec, signers) if err != nil { return nil, err @@ -375,29 +383,18 @@ func (b *builder) NewCreateChainTx( keys []*secp256k1.PrivateKey, changeAddr ids.ShortID, ) (*txs.Tx, error) { - timestamp := b.state.GetTimestamp() - createBlockchainTxFee := b.cfg.GetCreateBlockchainTxFee(timestamp) - ins, outs, _, signers, err := b.Spend(b.state, keys, 0, createBlockchainTxFee, changeAddr) - if err != nil { - return nil, fmt.Errorf("couldn't generate tx inputs/outputs: %w", err) - } - + // 1. Build core transaction without utxos subnetAuth, subnetSigners, err := b.Authorize(b.state, subnetID, keys) if err != nil { return nil, fmt.Errorf("couldn't authorize tx's subnet restrictions: %w", err) } - signers = append(signers, subnetSigners) - // Sort the provided fxIDs - utils.Sort(fxIDs) + utils.Sort(fxIDs) // sort the provided fxIDs - // Create the tx utx := &txs.CreateChainTx{ BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ NetworkID: b.ctx.NetworkID, BlockchainID: b.ctx.ChainID, - Ins: ins, - Outs: outs, }}, SubnetID: subnetID, ChainName: chainName, @@ -406,6 +403,20 @@ func (b *builder) NewCreateChainTx( GenesisData: genesisData, SubnetAuth: subnetAuth, } + + // 2. Finance the tx by building the utxos (inputs, outputs and stakes) + timestamp := b.state.GetTimestamp() + createBlockchainTxFee := b.cfg.GetCreateBlockchainTxFee(timestamp) + ins, outs, _, signers, err := b.Spend(b.state, keys, 0, createBlockchainTxFee, changeAddr) + if err != nil { + return nil, fmt.Errorf("couldn't generate tx inputs/outputs: %w", err) + } + + utx.BaseTx.Ins = ins + utx.BaseTx.Outs = outs + + // 3. Sign the tx + signers = append(signers, subnetSigners) tx, err := txs.NewSigned(utx, txs.Codec, signers) if err != nil { return nil, err @@ -419,29 +430,32 @@ func (b *builder) NewCreateSubnetTx( keys []*secp256k1.PrivateKey, changeAddr ids.ShortID, ) (*txs.Tx, error) { - timestamp := b.state.GetTimestamp() - createSubnetTxFee := b.cfg.GetCreateSubnetTxFee(timestamp) - ins, outs, _, signers, err := b.Spend(b.state, keys, 0, createSubnetTxFee, changeAddr) - if err != nil { - return nil, fmt.Errorf("couldn't generate tx inputs/outputs: %w", err) - } - - // Sort control addresses - utils.Sort(ownerAddrs) + // 1. Build core transaction without utxos + utils.Sort(ownerAddrs) // sort control addresses - // Create the tx utx := &txs.CreateSubnetTx{ BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ NetworkID: b.ctx.NetworkID, BlockchainID: b.ctx.ChainID, - Ins: ins, - Outs: outs, }}, Owner: &secp256k1fx.OutputOwners{ Threshold: threshold, Addrs: ownerAddrs, }, } + + // 2. Finance the tx by building the utxos (inputs, outputs and stakes) + timestamp := b.state.GetTimestamp() + createSubnetTxFee := b.cfg.GetCreateSubnetTxFee(timestamp) + ins, outs, _, signers, err := b.Spend(b.state, keys, 0, createSubnetTxFee, changeAddr) + if err != nil { + return nil, fmt.Errorf("couldn't generate tx inputs/outputs: %w", err) + } + + utx.BaseTx.Ins = ins + utx.BaseTx.Outs = outs + + // 3. Sign the tx tx, err := txs.NewSigned(utx, txs.Codec, signers) if err != nil { return nil, err @@ -459,17 +473,11 @@ func (b *builder) NewAddValidatorTx( keys []*secp256k1.PrivateKey, changeAddr ids.ShortID, ) (*txs.Tx, error) { - ins, unstakedOuts, stakedOuts, signers, err := b.Spend(b.state, keys, stakeAmount, b.cfg.AddPrimaryNetworkValidatorFee, changeAddr) - if err != nil { - return nil, fmt.Errorf("couldn't generate tx inputs/outputs: %w", err) - } - // Create the tx + // 1. Build core transaction without utxos utx := &txs.AddValidatorTx{ BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ NetworkID: b.ctx.NetworkID, BlockchainID: b.ctx.ChainID, - Ins: ins, - Outs: unstakedOuts, }}, Validator: txs.Validator{ NodeID: nodeID, @@ -477,7 +485,6 @@ func (b *builder) NewAddValidatorTx( End: endTime, Wght: stakeAmount, }, - StakeOuts: stakedOuts, RewardsOwner: &secp256k1fx.OutputOwners{ Locktime: 0, Threshold: 1, @@ -485,6 +492,18 @@ func (b *builder) NewAddValidatorTx( }, DelegationShares: shares, } + + // 2. Finance the tx by building the utxos (inputs, outputs and stakes) + ins, unstakedOuts, stakedOuts, signers, err := b.Spend(b.state, keys, stakeAmount, b.cfg.AddPrimaryNetworkValidatorFee, changeAddr) + if err != nil { + return nil, fmt.Errorf("couldn't generate tx inputs/outputs: %w", err) + } + + utx.BaseTx.Ins = ins + utx.BaseTx.Outs = unstakedOuts + utx.StakeOuts = stakedOuts + + // 3. Sign the tx tx, err := txs.NewSigned(utx, txs.Codec, signers) if err != nil { return nil, err @@ -501,17 +520,11 @@ func (b *builder) NewAddDelegatorTx( keys []*secp256k1.PrivateKey, changeAddr ids.ShortID, ) (*txs.Tx, error) { - ins, unlockedOuts, lockedOuts, signers, err := b.Spend(b.state, keys, stakeAmount, b.cfg.AddPrimaryNetworkDelegatorFee, changeAddr) - if err != nil { - return nil, fmt.Errorf("couldn't generate tx inputs/outputs: %w", err) - } - // Create the tx + // 1. Build core transaction without utxos utx := &txs.AddDelegatorTx{ BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ NetworkID: b.ctx.NetworkID, BlockchainID: b.ctx.ChainID, - Ins: ins, - Outs: unlockedOuts, }}, Validator: txs.Validator{ NodeID: nodeID, @@ -519,13 +532,24 @@ func (b *builder) NewAddDelegatorTx( End: endTime, Wght: stakeAmount, }, - StakeOuts: lockedOuts, DelegationRewardsOwner: &secp256k1fx.OutputOwners{ Locktime: 0, Threshold: 1, Addrs: []ids.ShortID{rewardAddress}, }, } + + // 2. Finance the tx by building the utxos (inputs, outputs and stakes) + ins, unstakedOuts, stakedOuts, signers, err := b.Spend(b.state, keys, stakeAmount, b.cfg.AddPrimaryNetworkDelegatorFee, changeAddr) + if err != nil { + return nil, fmt.Errorf("couldn't generate tx inputs/outputs: %w", err) + } + + utx.BaseTx.Ins = ins + utx.BaseTx.Outs = unstakedOuts + utx.StakeOuts = stakedOuts + + // 3. Sign the tx tx, err := txs.NewSigned(utx, txs.Codec, signers) if err != nil { return nil, err @@ -542,24 +566,15 @@ func (b *builder) NewAddSubnetValidatorTx( keys []*secp256k1.PrivateKey, changeAddr ids.ShortID, ) (*txs.Tx, error) { - ins, outs, _, signers, err := b.Spend(b.state, keys, 0, b.cfg.TxFee, changeAddr) - if err != nil { - return nil, fmt.Errorf("couldn't generate tx inputs/outputs: %w", err) - } - + // 1. Build core transaction without utxos subnetAuth, subnetSigners, err := b.Authorize(b.state, subnetID, keys) if err != nil { return nil, fmt.Errorf("couldn't authorize tx's subnet restrictions: %w", err) } - signers = append(signers, subnetSigners) - - // Create the tx utx := &txs.AddSubnetValidatorTx{ BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ NetworkID: b.ctx.NetworkID, BlockchainID: b.ctx.ChainID, - Ins: ins, - Outs: outs, }}, SubnetValidator: txs.SubnetValidator{ Validator: txs.Validator{ @@ -572,6 +587,18 @@ func (b *builder) NewAddSubnetValidatorTx( }, SubnetAuth: subnetAuth, } + + // 2. Finance the tx by building the utxos (inputs, outputs and stakes) + ins, outs, _, signers, err := b.Spend(b.state, keys, 0, b.cfg.TxFee, changeAddr) + if err != nil { + return nil, fmt.Errorf("couldn't generate tx inputs/outputs: %w", err) + } + + utx.BaseTx.Ins = ins + utx.BaseTx.Outs = outs + + // 3. Sign the tx + signers = append(signers, subnetSigners) tx, err := txs.NewSigned(utx, txs.Codec, signers) if err != nil { return nil, err @@ -585,29 +612,32 @@ func (b *builder) NewRemoveSubnetValidatorTx( keys []*secp256k1.PrivateKey, changeAddr ids.ShortID, ) (*txs.Tx, error) { - ins, outs, _, signers, err := b.Spend(b.state, keys, 0, b.cfg.TxFee, changeAddr) - if err != nil { - return nil, fmt.Errorf("couldn't generate tx inputs/outputs: %w", err) - } - + // 1. Build core transaction without utxos subnetAuth, subnetSigners, err := b.Authorize(b.state, subnetID, keys) if err != nil { return nil, fmt.Errorf("couldn't authorize tx's subnet restrictions: %w", err) } - signers = append(signers, subnetSigners) - - // Create the tx utx := &txs.RemoveSubnetValidatorTx{ BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ NetworkID: b.ctx.NetworkID, BlockchainID: b.ctx.ChainID, - Ins: ins, - Outs: outs, }}, Subnet: subnetID, NodeID: nodeID, SubnetAuth: subnetAuth, } + + // 2. Finance the tx by building the utxos (inputs, outputs and stakes) + ins, outs, _, signers, err := b.Spend(b.state, keys, 0, b.cfg.TxFee, changeAddr) + if err != nil { + return nil, fmt.Errorf("couldn't generate tx inputs/outputs: %w", err) + } + + utx.BaseTx.Ins = ins + utx.BaseTx.Outs = outs + + // 3. Sign the tx + signers = append(signers, subnetSigners) tx, err := txs.NewSigned(utx, txs.Codec, signers) if err != nil { return nil, err @@ -641,23 +671,15 @@ func (b *builder) NewTransferSubnetOwnershipTx( keys []*secp256k1.PrivateKey, changeAddr ids.ShortID, ) (*txs.Tx, error) { - ins, outs, _, signers, err := b.Spend(b.state, keys, 0, b.cfg.TxFee, changeAddr) - if err != nil { - return nil, fmt.Errorf("couldn't generate tx inputs/outputs: %w", err) - } - + // 1. Build core transaction without utxos subnetAuth, subnetSigners, err := b.Authorize(b.state, subnetID, keys) if err != nil { return nil, fmt.Errorf("couldn't authorize tx's subnet restrictions: %w", err) } - signers = append(signers, subnetSigners) - utx := &txs.TransferSubnetOwnershipTx{ BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ NetworkID: b.ctx.NetworkID, BlockchainID: b.ctx.ChainID, - Ins: ins, - Outs: outs, }}, Subnet: subnetID, SubnetAuth: subnetAuth, @@ -666,6 +688,18 @@ func (b *builder) NewTransferSubnetOwnershipTx( Addrs: ownerAddrs, }, } + + // 2. Finance the tx by building the utxos (inputs, outputs and stakes) + ins, outs, _, signers, err := b.Spend(b.state, keys, 0, b.cfg.TxFee, changeAddr) + if err != nil { + return nil, fmt.Errorf("couldn't generate tx inputs/outputs: %w", err) + } + + utx.BaseTx.Ins = ins + utx.BaseTx.Outs = outs + + // 3. Sign the tx + signers = append(signers, subnetSigners) tx, err := txs.NewSigned(utx, txs.Codec, signers) if err != nil { return nil, err @@ -679,6 +713,15 @@ func (b *builder) NewBaseTx( keys []*secp256k1.PrivateKey, changeAddr ids.ShortID, ) (*txs.Tx, error) { + // 1. Build core transaction without utxos + utx := &txs.BaseTx{ + BaseTx: avax.BaseTx{ + NetworkID: b.ctx.NetworkID, + BlockchainID: b.ctx.ChainID, + }, + } + + // 2. Finance the tx by building the utxos (inputs, outputs and stakes) toBurn, err := math.Add64(amount, b.cfg.TxFee) if err != nil { return nil, fmt.Errorf("amount (%d) + tx fee(%d) overflows", amount, b.cfg.TxFee) @@ -695,17 +738,12 @@ func (b *builder) NewBaseTx( OutputOwners: owner, }, }) - avax.SortTransferableOutputs(outs, txs.Codec) - utx := &txs.BaseTx{ - BaseTx: avax.BaseTx{ - NetworkID: b.ctx.NetworkID, - BlockchainID: b.ctx.ChainID, - Ins: ins, - Outs: outs, - }, - } + utx.BaseTx.Ins = ins + utx.BaseTx.Outs = outs + + // 3. Sign the tx tx, err := txs.NewSigned(utx, txs.Codec, signers) if err != nil { return nil, err From 2123e4de4ff1774034607e174ead8e349115266e Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Fri, 12 Jan 2024 10:30:34 +0100 Subject: [PATCH 028/190] wip: draft of tx financing with dynamic fees --- vms/platformvm/txs/builder/builder.go | 39 +++- vms/platformvm/utxo/handler.go | 268 ++++++++++++++++++++++++++ vms/platformvm/utxo/handler_test.go | 105 ++++++++++ 3 files changed, 409 insertions(+), 3 deletions(-) diff --git a/vms/platformvm/txs/builder/builder.go b/vms/platformvm/txs/builder/builder.go index 8a005d41480c..998a4a85795e 100644 --- a/vms/platformvm/txs/builder/builder.go +++ b/vms/platformvm/txs/builder/builder.go @@ -19,8 +19,11 @@ import ( "github.com/ava-labs/avalanchego/vms/platformvm/fx" "github.com/ava-labs/avalanchego/vms/platformvm/state" "github.com/ava-labs/avalanchego/vms/platformvm/txs" + "github.com/ava-labs/avalanchego/vms/platformvm/txs/fees" "github.com/ava-labs/avalanchego/vms/platformvm/utxo" "github.com/ava-labs/avalanchego/vms/secp256k1fx" + + commonfees "github.com/ava-labs/avalanchego/vms/components/fees" ) // Max number of items allowed in a page @@ -445,9 +448,39 @@ func (b *builder) NewCreateSubnetTx( } // 2. Finance the tx by building the utxos (inputs, outputs and stakes) - timestamp := b.state.GetTimestamp() - createSubnetTxFee := b.cfg.GetCreateSubnetTxFee(timestamp) - ins, outs, _, signers, err := b.Spend(b.state, keys, 0, createSubnetTxFee, changeAddr) + var ( + chainTime = b.state.GetTimestamp() + ins []*avax.TransferableInput + outs []*avax.TransferableOutput + signers [][]*secp256k1.PrivateKey + err error + ) + if b.cfg.IsEForkActivated(chainTime) { + feesMan := commonfees.NewManager(b.cfg.DefaultUnitFees) + feeCalc := &fees.Calculator{ + FeeManager: feesMan, + Config: b.cfg, + ChainTime: b.state.GetTimestamp(), + // Credentials: , + } + + // feesMan cumulates consumed units. Let's init it with utx filled so far + if err := feeCalc.CreateSubnetTx(utx); err != nil { + return nil, err + } + + ins, outs, _, signers, err = b.FinanceTx( + b.state, + keys, + 0, + utx, + feeCalc, + changeAddr, + ) + } else { + createSubnetTxFee := b.cfg.GetCreateSubnetTxFee(chainTime) + ins, outs, _, signers, err = b.Spend(b.state, keys, 0, createSubnetTxFee, changeAddr) + } if err != nil { return nil, fmt.Errorf("couldn't generate tx inputs/outputs: %w", err) } diff --git a/vms/platformvm/utxo/handler.go b/vms/platformvm/utxo/handler.go index f22a76fd0b8f..790f53904ae3 100644 --- a/vms/platformvm/utxo/handler.go +++ b/vms/platformvm/utxo/handler.go @@ -22,6 +22,7 @@ import ( "github.com/ava-labs/avalanchego/vms/platformvm/stakeable" "github.com/ava-labs/avalanchego/vms/platformvm/state" "github.com/ava-labs/avalanchego/vms/platformvm/txs" + "github.com/ava-labs/avalanchego/vms/platformvm/txs/fees" "github.com/ava-labs/avalanchego/vms/secp256k1fx" ) @@ -69,6 +70,21 @@ type Spender interface { error, ) + FinanceTx( + utxoReader avax.UTXOReader, + keys []*secp256k1.PrivateKey, + amount uint64, + uTx txs.UnsignedTx, + feeCalc *fees.Calculator, + changeAddr ids.ShortID, + ) ( + []*avax.TransferableInput, // inputs + []*avax.TransferableOutput, // returnedOutputs + []*avax.TransferableOutput, // stakedOutputs + [][]*secp256k1.PrivateKey, // signers + error, + ) + // Authorize an operation on behalf of the named subnet with the provided // keys. Authorize( @@ -390,6 +406,258 @@ func (h *handler) Spend( return ins, returnedOuts, stakedOuts, signers, nil } +func (h *handler) FinanceTx( + utxoReader avax.UTXOReader, + keys []*secp256k1.PrivateKey, + amount uint64, + uTx txs.UnsignedTx, + feeCalc *fees.Calculator, + changeAddr ids.ShortID, +) ( + []*avax.TransferableInput, // inputs + []*avax.TransferableOutput, // returnedOutputs + []*avax.TransferableOutput, // stakedOutputs + [][]*secp256k1.PrivateKey, // signers + error, +) { + addrs := set.NewSet[ids.ShortID](len(keys)) // The addresses controlled by [keys] + for _, key := range keys { + addrs.Add(key.PublicKey().Address()) + } + utxos, err := avax.GetAllUTXOs(utxoReader, addrs) // The UTXOs controlled by [keys] + if err != nil { + return nil, nil, nil, nil, fmt.Errorf("couldn't get UTXOs: %w", err) + } + + kc := secp256k1fx.NewKeychain(keys...) // Keychain consumes UTXOs and creates new ones + + // Minimum time this transaction will be issued at + now := uint64(h.clk.Time().Unix()) + + ins := []*avax.TransferableInput{} + returnedOuts := []*avax.TransferableOutput{} + stakedOuts := []*avax.TransferableOutput{} + signers := [][]*secp256k1.PrivateKey{} + + targetFee := feeCalc.Fee + + // Amount of AVAX that has been staked + amountStaked := uint64(0) + + // Consume locked UTXOs + for _, utxo := range utxos { + // If we have consumed more AVAX than we are trying to stake, then we + // have no need to consume more locked AVAX + if amountStaked >= amount { + break + } + + if assetID := utxo.AssetID(); assetID != h.ctx.AVAXAssetID { + continue // We only care about staking AVAX, so ignore other assets + } + + out, ok := utxo.Out.(*stakeable.LockOut) + if !ok { + // This output isn't locked, so it will be handled during the next + // iteration of the UTXO set + continue + } + if out.Locktime <= now { + // This output is no longer locked, so it will be handled during the + // next iteration of the UTXO set + continue + } + + inner, ok := out.TransferableOut.(*secp256k1fx.TransferOutput) + if !ok { + // We only know how to clone secp256k1 outputs for now + continue + } + + inIntf, inSigners, err := kc.Spend(out.TransferableOut, now) + if err != nil { + // We couldn't spend the output, so move on to the next one + continue + } + in, ok := inIntf.(avax.TransferableIn) + if !ok { // should never happen + h.ctx.Log.Warn("wrong input type", + zap.String("expectedType", "avax.TransferableIn"), + zap.String("actualType", fmt.Sprintf("%T", inIntf)), + ) + continue + } + + // The remaining value is initially the full value of the input + remainingValue := in.Amount() + + // Stake any value that should be staked + amountToStake := math.Min( + amount-amountStaked, // Amount we still need to stake + remainingValue, // Amount available to stake + ) + amountStaked += amountToStake + remainingValue -= amountToStake + + // Add the input to the consumed inputs + ins = append(ins, &avax.TransferableInput{ + UTXOID: utxo.UTXOID, + Asset: avax.Asset{ID: h.ctx.AVAXAssetID}, + In: &stakeable.LockIn{ + Locktime: out.Locktime, + TransferableIn: in, + }, + }) + + // Add the output to the staked outputs + stakedOuts = append(stakedOuts, &avax.TransferableOutput{ + Asset: avax.Asset{ID: h.ctx.AVAXAssetID}, + Out: &stakeable.LockOut{ + Locktime: out.Locktime, + TransferableOut: &secp256k1fx.TransferOutput{ + Amt: amountToStake, + OutputOwners: inner.OutputOwners, + }, + }, + }) + + if remainingValue > 0 { + // This input provided more value than was needed to be locked. + // Some of it must be returned + returnedOuts = append(returnedOuts, &avax.TransferableOutput{ + Asset: avax.Asset{ID: h.ctx.AVAXAssetID}, + Out: &stakeable.LockOut{ + Locktime: out.Locktime, + TransferableOut: &secp256k1fx.TransferOutput{ + Amt: remainingValue, + OutputOwners: inner.OutputOwners, + }, + }, + }) + } + + // Add the signers needed for this input to the set of signers + signers = append(signers, inSigners) + } + + // Amount of AVAX that has been burned + amountBurned := uint64(0) + + for _, utxo := range utxos { + // If we have consumed more AVAX than we are trying to stake, + // and we have burned more AVAX than we need to, + // then we have no need to consume more AVAX + if amountBurned >= targetFee && amountStaked >= amount { + break + } + + if assetID := utxo.AssetID(); assetID != h.ctx.AVAXAssetID { + continue // We only care about burning AVAX, so ignore other assets + } + + out := utxo.Out + inner, ok := out.(*stakeable.LockOut) + if ok { + if inner.Locktime > now { + // This output is currently locked, so this output can't be + // burned. Additionally, it may have already been consumed + // above. Regardless, we skip to the next UTXO + continue + } + out = inner.TransferableOut + } + + inIntf, inSigners, err := kc.Spend(out, now) + if err != nil { + // We couldn't spend this UTXO, so we skip to the next one + continue + } + in, ok := inIntf.(avax.TransferableIn) + if !ok { + // Because we only use the secp Fx right now, this should never + // happen + continue + } + + // The remaining value is initially the full value of the input + remainingValue := in.Amount() + + if err := uTx.Visit(feeCalc); err != nil { + return nil, nil, nil, nil, fmt.Errorf("couldn't get UTXOs: %w", err) + } + targetFee = feeCalc.Fee + + // Burn any value that should be burned + amountToBurn := math.Min( + targetFee-amountBurned, // Amount we still need to burn + remainingValue, // Amount available to burn + ) + amountBurned += amountToBurn + remainingValue -= amountToBurn + + // Stake any value that should be staked + amountToStake := math.Min( + amount-amountStaked, // Amount we still need to stake + remainingValue, // Amount available to stake + ) + amountStaked += amountToStake + remainingValue -= amountToStake + + // Add the input to the consumed inputs + ins = append(ins, &avax.TransferableInput{ + UTXOID: utxo.UTXOID, + Asset: avax.Asset{ID: h.ctx.AVAXAssetID}, + In: in, + }) + + if amountToStake > 0 { + // Some of this input was put for staking + stakedOuts = append(stakedOuts, &avax.TransferableOutput{ + Asset: avax.Asset{ID: h.ctx.AVAXAssetID}, + Out: &secp256k1fx.TransferOutput{ + Amt: amountToStake, + OutputOwners: secp256k1fx.OutputOwners{ + Locktime: 0, + Threshold: 1, + Addrs: []ids.ShortID{changeAddr}, + }, + }, + }) + } + + if remainingValue > 0 { + // This input had extra value, so some of it must be returned + returnedOuts = append(returnedOuts, &avax.TransferableOutput{ + Asset: avax.Asset{ID: h.ctx.AVAXAssetID}, + Out: &secp256k1fx.TransferOutput{ + Amt: remainingValue, + OutputOwners: secp256k1fx.OutputOwners{ + Locktime: 0, + Threshold: 1, + Addrs: []ids.ShortID{changeAddr}, + }, + }, + }) + } + + // Add the signers needed for this input to the set of signers + signers = append(signers, inSigners) + } + + if amountBurned < targetFee || amountStaked < amount { + return nil, nil, nil, nil, fmt.Errorf( + "%w (unlocked, locked) (%d, %d) but need (%d, %d)", + ErrInsufficientFunds, amountBurned, amountStaked, targetFee, amount, + ) + } + + avax.SortTransferableInputsWithSigners(ins, signers) // sort inputs and keys + avax.SortTransferableOutputs(returnedOuts, txs.Codec) // sort outputs + avax.SortTransferableOutputs(stakedOuts, txs.Codec) // sort outputs + + return ins, returnedOuts, stakedOuts, signers, nil +} + func (h *handler) Authorize( state state.Chain, subnetID ids.ID, diff --git a/vms/platformvm/utxo/handler_test.go b/vms/platformvm/utxo/handler_test.go index d0224ed4666a..62d9ab975dff 100644 --- a/vms/platformvm/utxo/handler_test.go +++ b/vms/platformvm/utxo/handler_test.go @@ -9,18 +9,24 @@ import ( "time" "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/snow/snowtest" "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" "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/config" "github.com/ava-labs/avalanchego/vms/platformvm/stakeable" + "github.com/ava-labs/avalanchego/vms/platformvm/state" "github.com/ava-labs/avalanchego/vms/platformvm/txs" + "github.com/ava-labs/avalanchego/vms/platformvm/txs/fees" "github.com/ava-labs/avalanchego/vms/secp256k1fx" safemath "github.com/ava-labs/avalanchego/utils/math" + commonfees "github.com/ava-labs/avalanchego/vms/components/fees" ) var _ txs.UnsignedTx = (*dummyUnsignedTx)(nil) @@ -33,6 +39,105 @@ func (*dummyUnsignedTx) Visit(txs.Visitor) error { return nil } +func TestVerifyFinanceTx(t *testing.T) { + fx := &secp256k1fx.Fx{} + + require.NoError(t, fx.InitializeVM(&secp256k1fx.TestVM{})) + require.NoError(t, fx.Bootstrapped()) + + ctx := snowtest.Context(t, snowtest.PChainID) + + h := &handler{ + ctx: ctx, + clk: &mockable.Clock{}, + fx: fx, + } + + cfg := &config.Config{ + FeeConfig: config.FeeConfig{ + DefaultUnitFees: commonfees.Dimensions{ + 1 * units.MicroAvax, + 2 * units.MicroAvax, + 3 * units.MicroAvax, + 4 * units.MicroAvax, + }, + DefaultBlockMaxConsumedUnits: commonfees.Dimensions{ + math.MaxUint64, + math.MaxUint64, + math.MaxUint64, + math.MaxUint64, + }, + }, + } + + tests := []struct { + description string + utxoReaderF func(ctrl *gomock.Controller) avax.UTXOReader + keys []*secp256k1.PrivateKey + amountToStake uint64 + uTxF func() txs.UnsignedTx + feeCalcF func() *fees.Calculator + changeAddr ids.ShortID + + expectedErr error + checksF func(*testing.T, *fees.Calculator, []*avax.TransferableInput, []*avax.TransferableOutput, []*avax.TransferableOutput) + }{ + { + description: "no inputs, no outputs, no fee", + utxoReaderF: func(ctrl *gomock.Controller) avax.UTXOReader { + s := state.NewMockState(ctrl) + s.EXPECT().UTXOIDs(gomock.Any(), gomock.Any(), gomock.Any()).Return([]ids.ID{}, nil).AnyTimes() + return s + }, + keys: secp256k1.TestKeys(), + amountToStake: 0, + uTxF: func() txs.UnsignedTx { + unsignedTx := dummyUnsignedTx{ + BaseTx: txs.BaseTx{}, + } + unsignedTx.SetBytes([]byte{0}) + return &unsignedTx + }, + feeCalcF: func() *fees.Calculator { + fm := commonfees.NewManager(cfg.DefaultUnitFees) + feesCalc := fees.Calculator{ + FeeManager: fm, + Config: cfg, + ChainTime: time.Time{}, + Credentials: []verify.Verifiable{}, + } + return &feesCalc + }, + expectedErr: nil, + checksF: func(t *testing.T, calc *fees.Calculator, ins []*avax.TransferableInput, outs, staked []*avax.TransferableOutput) { + require.Zero(t, calc.Fee) + require.Empty(t, ins) + require.Empty(t, outs) + require.Empty(t, staked) + }, + }, + } + + for _, test := range tests { + t.Run(test.description, func(t *testing.T) { + ctrl := gomock.NewController(t) + + feeCalc := test.feeCalcF() + + ins, outs, staked, _, err := h.FinanceTx( + test.utxoReaderF(ctrl), + test.keys, + test.amountToStake, + test.uTxF(), + feeCalc, + test.changeAddr, + ) + require.ErrorIs(t, err, test.expectedErr) + test.checksF(t, feeCalc, ins, outs, staked) + }) + } +} + func TestVerifySpendUTXOs(t *testing.T) { fx := &secp256k1fx.Fx{} From cf2c55cef42e7687c16d472c42e97e96ea9d5e02 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Fri, 12 Jan 2024 13:54:33 +0100 Subject: [PATCH 029/190] UT for codec size additivity --- codec/manager.go | 4 +- vms/platformvm/state/metadata_validator.go | 3 +- vms/platformvm/txs/fees/calculator_test.go | 78 ++++++++++++++++++++++ 3 files changed, 83 insertions(+), 2 deletions(-) diff --git a/codec/manager.go b/codec/manager.go index 6fb48aaad9f8..2afc011aa3fe 100644 --- a/codec/manager.go +++ b/codec/manager.go @@ -13,6 +13,8 @@ import ( ) const ( + CodecVersionSize = wrappers.ShortLen + // default max size, in bytes, of something being marshalled by Marshal() defaultMaxSize = 256 * units.KiB @@ -103,7 +105,7 @@ func (m *manager) Size(version uint16, value interface{}) (int, error) { res, err := c.Size(value) // Add [wrappers.ShortLen] for the codec version - return wrappers.ShortLen + res, err + return CodecVersionSize + res, err } // To marshal an interface, [value] must be a pointer to the interface. diff --git a/vms/platformvm/state/metadata_validator.go b/vms/platformvm/state/metadata_validator.go index 0c725368505b..74242150d37f 100644 --- a/vms/platformvm/state/metadata_validator.go +++ b/vms/platformvm/state/metadata_validator.go @@ -6,6 +6,7 @@ package state import ( "time" + "github.com/ava-labs/avalanchego/codec" "github.com/ava-labs/avalanchego/database" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils/constants" @@ -17,7 +18,7 @@ import ( // [preDelegateeRewardMetadata]. // // CodecVersionLen + UpDurationLen + LastUpdatedLen + PotentialRewardLen -const preDelegateeRewardSize = wrappers.ShortLen + 3*wrappers.LongLen +const preDelegateeRewardSize = codec.CodecVersionSize + 3*wrappers.LongLen var _ validatorState = (*metadata)(nil) diff --git a/vms/platformvm/txs/fees/calculator_test.go b/vms/platformvm/txs/fees/calculator_test.go index de3b320ebc36..0701d72d3fb9 100644 --- a/vms/platformvm/txs/fees/calculator_test.go +++ b/vms/platformvm/txs/fees/calculator_test.go @@ -4,11 +4,13 @@ package fees import ( + "math/rand" "testing" "time" "github.com/stretchr/testify/require" + "github.com/ava-labs/avalanchego/codec" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/snow" "github.com/ava-labs/avalanchego/snow/snowtest" @@ -115,6 +117,82 @@ func TestPartiallyFulledTransactionsSizes(t *testing.T) { require.Equal(t, uTxSize, 443) } +func TestUTXOsAreAdditiveInSize(t *testing.T) { + // Show that including utxos of size [S] into a tx of size [T] + // result in a tx of size [S+T-CodecVersion] + // This is key to calculate fees correctly while building a tx + + uTx := &txs.AddValidatorTx{ + BaseTx: txs.BaseTx{ + BaseTx: avax.BaseTx{ + NetworkID: rand.Uint32(), + BlockchainID: ids.GenerateTestID(), + Memo: []byte{'a', 'b', 'c'}, + Ins: make([]*avax.TransferableInput, 0), + Outs: make([]*avax.TransferableOutput, 0), + }, + }, + } + + uTxNakedSize := 105 + uTxSize, err := txs.Codec.Size(txs.CodecVersion, uTx) + require.NoError(t, err) + require.Equal(t, uTxNakedSize, uTxSize) + + // input to add + input := &avax.TransferableInput{ + UTXOID: avax.UTXOID{ + TxID: ids.ID{'t', 'x', 'I', 'D'}, + OutputIndex: 2, + }, + Asset: avax.Asset{ID: ids.GenerateTestID()}, + In: &secp256k1fx.TransferInput{ + Amt: uint64(5678), + Input: secp256k1fx.Input{SigIndices: []uint32{0}}, + }, + } + inSize, err := txs.Codec.Size(txs.CodecVersion, input) + require.NoError(t, err) + + // include input in uTx and check that sizes add + uTx.BaseTx.BaseTx.Ins = append(uTx.BaseTx.BaseTx.Ins, input) + uTxSize, err = txs.Codec.Size(txs.CodecVersion, uTx) + require.NoError(t, err) + require.Equal(t, uTxNakedSize+(inSize-codec.CodecVersionSize), uTxSize) + + // output to add + output := &avax.TransferableOutput{ + Asset: avax.Asset{ + ID: ids.GenerateTestID(), + }, + Out: &stakeable.LockOut{ + Locktime: 87654321, + TransferableOut: &secp256k1fx.TransferOutput{ + Amt: 1, + OutputOwners: secp256k1fx.OutputOwners{ + Locktime: 12345678, + Threshold: 0, + Addrs: []ids.ShortID{}, + }, + }, + }, + } + outSize, err := txs.Codec.Size(txs.CodecVersion, output) + require.NoError(t, err) + + // include output in uTx and check that sizes add + uTx.BaseTx.BaseTx.Outs = append(uTx.BaseTx.BaseTx.Outs, output) + uTxSize, err = txs.Codec.Size(txs.CodecVersion, uTx) + require.NoError(t, err) + require.Equal(t, uTxNakedSize+(inSize-codec.CodecVersionSize)+(outSize-codec.CodecVersionSize), uTxSize) + + // include output in uTx as stake and check that sizes add + uTx.StakeOuts = append(uTx.StakeOuts, output) + uTxSize, err = txs.Codec.Size(txs.CodecVersion, uTx) + require.NoError(t, err) + require.Equal(t, uTxNakedSize+(inSize-codec.CodecVersionSize)+(outSize-codec.CodecVersionSize)+(outSize-codec.CodecVersionSize), uTxSize) +} + func TestAddValidatorTxFees(t *testing.T) { r := require.New(t) From b14d514e93d086a50148a135e1ee98fc65d45f72 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Fri, 12 Jan 2024 15:04:23 +0100 Subject: [PATCH 030/190] exported inputs and outputs fee dimensions calculations --- vms/components/fees/manager.go | 12 ++ vms/platformvm/txs/fees/calculator.go | 174 ++++++++++++--------- vms/platformvm/txs/fees/calculator_test.go | 2 +- 3 files changed, 114 insertions(+), 74 deletions(-) diff --git a/vms/components/fees/manager.go b/vms/components/fees/manager.go index 4a93bed3c4b0..9270f9798fa7 100644 --- a/vms/components/fees/manager.go +++ b/vms/components/fees/manager.go @@ -21,6 +21,18 @@ type ( Dimensions [FeeDimensions]uint64 ) +func Add(lhs, rhs Dimensions) (Dimensions, error) { + var res Dimensions + for i := 0; i < FeeDimensions; i++ { + v, err := math.Add64(lhs[i], rhs[i]) + if err != nil { + return res, err + } + res[i] = v + } + return res, nil +} + type Manager struct { // Avax denominated unit fees for all fee dimensions unitFees Dimensions diff --git a/vms/platformvm/txs/fees/calculator.go b/vms/platformvm/txs/fees/calculator.go index 441e26eddafe..4f3831f61ef4 100644 --- a/vms/platformvm/txs/fees/calculator.go +++ b/vms/platformvm/txs/fees/calculator.go @@ -8,6 +8,7 @@ import ( "fmt" "time" + "github.com/ava-labs/avalanchego/codec" "github.com/ava-labs/avalanchego/utils/constants" "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/components/fees" @@ -46,13 +47,12 @@ func (fc *Calculator) AddValidatorTx(tx *txs.AddValidatorTx) error { copy(outs, tx.Outs) copy(outs[len(tx.Outs):], tx.StakeOuts) - consumedUnits, err := commonConsumedUnits(tx, fc.Credentials, outs, tx.Ins) + consumedUnits, err := fc.commonConsumedUnits(tx, outs, tx.Ins) if err != nil { return err } - fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.FeeManager, consumedUnits) - return err + return fc.processFees(consumedUnits) } func (fc *Calculator) AddSubnetValidatorTx(tx *txs.AddSubnetValidatorTx) error { @@ -61,13 +61,12 @@ func (fc *Calculator) AddSubnetValidatorTx(tx *txs.AddSubnetValidatorTx) error { return nil } - consumedUnits, err := commonConsumedUnits(tx, fc.Credentials, tx.Outs, tx.Ins) + consumedUnits, err := fc.commonConsumedUnits(tx, tx.Outs, tx.Ins) if err != nil { return err } - fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.FeeManager, consumedUnits) - return err + return fc.processFees(consumedUnits) } func (fc *Calculator) AddDelegatorTx(tx *txs.AddDelegatorTx) error { @@ -80,13 +79,12 @@ func (fc *Calculator) AddDelegatorTx(tx *txs.AddDelegatorTx) error { copy(outs, tx.Outs) copy(outs[len(tx.Outs):], tx.StakeOuts) - consumedUnits, err := commonConsumedUnits(tx, fc.Credentials, outs, tx.Ins) + consumedUnits, err := fc.commonConsumedUnits(tx, outs, tx.Ins) if err != nil { return err } - fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.FeeManager, consumedUnits) - return err + return fc.processFees(consumedUnits) } func (fc *Calculator) CreateChainTx(tx *txs.CreateChainTx) error { @@ -95,13 +93,12 @@ func (fc *Calculator) CreateChainTx(tx *txs.CreateChainTx) error { return nil } - consumedUnits, err := commonConsumedUnits(tx, fc.Credentials, tx.Outs, tx.Ins) + consumedUnits, err := fc.commonConsumedUnits(tx, tx.Outs, tx.Ins) if err != nil { return err } - fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.FeeManager, consumedUnits) - return err + return fc.processFees(consumedUnits) } func (fc *Calculator) CreateSubnetTx(tx *txs.CreateSubnetTx) error { @@ -110,13 +107,12 @@ func (fc *Calculator) CreateSubnetTx(tx *txs.CreateSubnetTx) error { return nil } - consumedUnits, err := commonConsumedUnits(tx, fc.Credentials, tx.Outs, tx.Ins) + consumedUnits, err := fc.commonConsumedUnits(tx, tx.Outs, tx.Ins) if err != nil { return err } - fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.FeeManager, consumedUnits) - return err + return fc.processFees(consumedUnits) } func (*Calculator) AdvanceTimeTx(*txs.AdvanceTimeTx) error { @@ -133,13 +129,12 @@ func (fc *Calculator) RemoveSubnetValidatorTx(tx *txs.RemoveSubnetValidatorTx) e return nil } - consumedUnits, err := commonConsumedUnits(tx, fc.Credentials, tx.Outs, tx.Ins) + consumedUnits, err := fc.commonConsumedUnits(tx, tx.Outs, tx.Ins) if err != nil { return err } - fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.FeeManager, consumedUnits) - return err + return fc.processFees(consumedUnits) } func (fc *Calculator) TransformSubnetTx(tx *txs.TransformSubnetTx) error { @@ -148,13 +143,12 @@ func (fc *Calculator) TransformSubnetTx(tx *txs.TransformSubnetTx) error { return nil } - consumedUnits, err := commonConsumedUnits(tx, fc.Credentials, tx.Outs, tx.Ins) + consumedUnits, err := fc.commonConsumedUnits(tx, tx.Outs, tx.Ins) if err != nil { return err } - fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.FeeManager, consumedUnits) - return err + return fc.processFees(consumedUnits) } func (fc *Calculator) TransferSubnetOwnershipTx(tx *txs.TransferSubnetOwnershipTx) error { @@ -163,13 +157,12 @@ func (fc *Calculator) TransferSubnetOwnershipTx(tx *txs.TransferSubnetOwnershipT return nil } - consumedUnits, err := commonConsumedUnits(tx, fc.Credentials, tx.Outs, tx.Ins) + consumedUnits, err := fc.commonConsumedUnits(tx, tx.Outs, tx.Ins) if err != nil { return err } - fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.FeeManager, consumedUnits) - return err + return fc.processFees(consumedUnits) } func (fc *Calculator) AddPermissionlessValidatorTx(tx *txs.AddPermissionlessValidatorTx) error { @@ -186,13 +179,12 @@ func (fc *Calculator) AddPermissionlessValidatorTx(tx *txs.AddPermissionlessVali copy(outs, tx.Outs) copy(outs[len(tx.Outs):], tx.StakeOuts) - consumedUnits, err := commonConsumedUnits(tx, fc.Credentials, outs, tx.Ins) + consumedUnits, err := fc.commonConsumedUnits(tx, outs, tx.Ins) if err != nil { return err } - fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.FeeManager, consumedUnits) - return err + return fc.processFees(consumedUnits) } func (fc *Calculator) AddPermissionlessDelegatorTx(tx *txs.AddPermissionlessDelegatorTx) error { @@ -209,13 +201,12 @@ func (fc *Calculator) AddPermissionlessDelegatorTx(tx *txs.AddPermissionlessDele copy(outs, tx.Outs) copy(outs[len(tx.Outs):], tx.StakeOuts) - consumedUnits, err := commonConsumedUnits(tx, fc.Credentials, outs, tx.Ins) + consumedUnits, err := fc.commonConsumedUnits(tx, outs, tx.Ins) if err != nil { return err } - fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.FeeManager, consumedUnits) - return err + return fc.processFees(consumedUnits) } func (fc *Calculator) BaseTx(tx *txs.BaseTx) error { @@ -224,13 +215,12 @@ func (fc *Calculator) BaseTx(tx *txs.BaseTx) error { return nil } - consumedUnits, err := commonConsumedUnits(tx, fc.Credentials, tx.Outs, tx.Ins) + consumedUnits, err := fc.commonConsumedUnits(tx, tx.Outs, tx.Ins) if err != nil { return err } - fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.FeeManager, consumedUnits) - return err + return fc.processFees(consumedUnits) } func (fc *Calculator) ImportTx(tx *txs.ImportTx) error { @@ -243,13 +233,12 @@ func (fc *Calculator) ImportTx(tx *txs.ImportTx) error { copy(ins, tx.Ins) copy(ins[len(tx.Ins):], tx.ImportedInputs) - consumedUnits, err := commonConsumedUnits(tx, fc.Credentials, tx.Outs, ins) + consumedUnits, err := fc.commonConsumedUnits(tx, tx.Outs, ins) if err != nil { return err } - fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.FeeManager, consumedUnits) - return err + return fc.processFees(consumedUnits) } func (fc *Calculator) ExportTx(tx *txs.ExportTx) error { @@ -262,75 +251,114 @@ func (fc *Calculator) ExportTx(tx *txs.ExportTx) error { copy(outs, tx.Outs) copy(outs[len(tx.Outs):], tx.ExportedOutputs) - consumedUnits, err := commonConsumedUnits(tx, fc.Credentials, outs, tx.Ins) + consumedUnits, err := fc.commonConsumedUnits(tx, outs, tx.Ins) if err != nil { return err } - fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.FeeManager, consumedUnits) - return err + return fc.processFees(consumedUnits) } -func commonConsumedUnits( - uTx txs.UnsignedTx, - credentials []verify.Verifiable, - allOuts []*avax.TransferableOutput, - allIns []*avax.TransferableInput, -) (fees.Dimensions, error) { - var consumedUnits fees.Dimensions +func GetInputsDimensions(in *avax.TransferableInput) (fees.Dimensions, error) { + return getInputsDimensions(true, []*avax.TransferableInput{in}) +} - uTxSize, err := txs.Codec.Size(txs.CodecVersion, uTx) - if err != nil { - return consumedUnits, fmt.Errorf("couldn't calculate UnsignedTx marshal length: %w", err) - } - credsSize, err := txs.Codec.Size(txs.CodecVersion, credentials) - if err != nil { - return consumedUnits, fmt.Errorf("failed retrieving size of credentials: %w", err) - } - consumedUnits[fees.Bandwidth] = uint64(uTxSize + credsSize) +func getInputsDimensions(evaluteBandwitdh bool, ins []*avax.TransferableInput) (fees.Dimensions, error) { + var consumedUnits fees.Dimensions - var ( - insCost uint64 - insSize uint64 - outsSize uint64 - ) - for _, in := range allIns { + for _, in := range ins { cost, err := in.In.Cost() if err != nil { return consumedUnits, fmt.Errorf("failed retrieving cost of input %s: %w", in.ID, err) } - insCost += cost inSize, err := txs.Codec.Size(txs.CodecVersion, in) if err != nil { return consumedUnits, fmt.Errorf("failed retrieving size of input %s: %w", in.ID, err) } - insSize += uint64(inSize) + uInSize := uint64(inSize) + + if evaluteBandwitdh { + consumedUnits[fees.Bandwidth] += uInSize - codec.CodecVersionSize + } + consumedUnits[fees.UTXORead] += cost + uInSize // inputs are read + consumedUnits[fees.UTXOWrite] += uInSize // inputs are deleted } + return consumedUnits, nil +} + +func GetOutputsDimensions(out *avax.TransferableOutput) (fees.Dimensions, error) { + return getOutputsDimensions(true, []*avax.TransferableOutput{out}) +} - for _, out := range allOuts { +func getOutputsDimensions(evaluteBandwitdh bool, outs []*avax.TransferableOutput) (fees.Dimensions, error) { + var consumedUnits fees.Dimensions + + for _, out := range outs { outSize, err := txs.Codec.Size(txs.CodecVersion, out) if err != nil { return consumedUnits, fmt.Errorf("failed retrieving size of output %s: %w", out.ID, err) } - outsSize += uint64(outSize) + uOutSize := uint64(outSize) + + if evaluteBandwitdh { + consumedUnits[fees.Bandwidth] += uOutSize - codec.CodecVersionSize + } + consumedUnits[fees.UTXOWrite] += uOutSize + } + + return consumedUnits, nil +} + +func (fc *Calculator) commonConsumedUnits( + uTx txs.UnsignedTx, + allOuts []*avax.TransferableOutput, + allIns []*avax.TransferableInput, +) (fees.Dimensions, error) { + var consumedUnits fees.Dimensions + + uTxSize, err := txs.Codec.Size(txs.CodecVersion, uTx) + if err != nil { + return consumedUnits, fmt.Errorf("couldn't calculate UnsignedTx marshal length: %w", err) + } + credsSize, err := txs.Codec.Size(txs.CodecVersion, fc.Credentials) + if err != nil { + return consumedUnits, fmt.Errorf("failed retrieving size of credentials: %w", err) + } + consumedUnits[fees.Bandwidth] = uint64(uTxSize + credsSize) + + inputDimensions, err := getInputsDimensions(false, allIns) + if err != nil { + return consumedUnits, fmt.Errorf("failed retrieving size of inputs: %w", err) + } + consumedUnits, err = fees.Add(consumedUnits, inputDimensions) + if err != nil { + return consumedUnits, fmt.Errorf("failed adding inputs: %w", err) + } + + outputDimensions, err := getOutputsDimensions(false, allOuts) + if err != nil { + return consumedUnits, fmt.Errorf("failed retrieving size of outputs: %w", err) + } + consumedUnits, err = fees.Add(consumedUnits, outputDimensions) + if err != nil { + return consumedUnits, fmt.Errorf("failed adding outputs: %w", err) } - consumedUnits[fees.UTXORead] = insCost + insSize // inputs are read - consumedUnits[fees.UTXOWrite] = insSize + outsSize // inputs are deleted, outputs are created return consumedUnits, nil } -func processFees(cfg *config.Config, chainTime time.Time, fc *fees.Manager, consumedUnits fees.Dimensions) (uint64, error) { - boundBreached, dimension := fc.CumulateUnits(consumedUnits, cfg.BlockMaxConsumedUnits(chainTime)) +func (fc *Calculator) processFees(consumedUnits fees.Dimensions) error { + boundBreached, dimension := fc.FeeManager.CumulateUnits(consumedUnits, fc.Config.BlockMaxConsumedUnits(fc.ChainTime)) if boundBreached { - return 0, fmt.Errorf("%w: breached dimension %d", errFailedConsumedUnitsCumulation, dimension) + return fmt.Errorf("%w: breached dimension %d", errFailedConsumedUnitsCumulation, dimension) } - fee, err := fc.CalculateFee(consumedUnits) + fee, err := fc.FeeManager.CalculateFee(consumedUnits) if err != nil { - return 0, fmt.Errorf("%w: %w", errFailedFeeCalculation, err) + return fmt.Errorf("%w: %w", errFailedFeeCalculation, err) } - return fee, nil + fc.Fee = fee + return nil } diff --git a/vms/platformvm/txs/fees/calculator_test.go b/vms/platformvm/txs/fees/calculator_test.go index 0701d72d3fb9..59ed5a5c4cd2 100644 --- a/vms/platformvm/txs/fees/calculator_test.go +++ b/vms/platformvm/txs/fees/calculator_test.go @@ -125,7 +125,7 @@ func TestUTXOsAreAdditiveInSize(t *testing.T) { uTx := &txs.AddValidatorTx{ BaseTx: txs.BaseTx{ BaseTx: avax.BaseTx{ - NetworkID: rand.Uint32(), + NetworkID: rand.Uint32(), //#nosec G404 BlockchainID: ids.GenerateTestID(), Memo: []byte{'a', 'b', 'c'}, Ins: make([]*avax.TransferableInput, 0), From 3d6f980b8432e8ec7bcbe9f4e85455b81510d643 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Fri, 12 Jan 2024 15:23:03 +0100 Subject: [PATCH 031/190] wip: keep on drafting tx financing with dynamic fees --- vms/platformvm/txs/builder/builder.go | 1 - vms/platformvm/txs/fees/calculator.go | 28 ++++----- vms/platformvm/utxo/handler.go | 39 ++++++++---- vms/platformvm/utxo/handler_test.go | 87 ++++++++++++++++++++++++--- 4 files changed, 121 insertions(+), 34 deletions(-) diff --git a/vms/platformvm/txs/builder/builder.go b/vms/platformvm/txs/builder/builder.go index 998a4a85795e..662382d2448f 100644 --- a/vms/platformvm/txs/builder/builder.go +++ b/vms/platformvm/txs/builder/builder.go @@ -473,7 +473,6 @@ func (b *builder) NewCreateSubnetTx( b.state, keys, 0, - utx, feeCalc, changeAddr, ) diff --git a/vms/platformvm/txs/fees/calculator.go b/vms/platformvm/txs/fees/calculator.go index 4f3831f61ef4..4484c9c50040 100644 --- a/vms/platformvm/txs/fees/calculator.go +++ b/vms/platformvm/txs/fees/calculator.go @@ -52,7 +52,7 @@ func (fc *Calculator) AddValidatorTx(tx *txs.AddValidatorTx) error { return err } - return fc.processFees(consumedUnits) + return fc.ProcessFees(consumedUnits) } func (fc *Calculator) AddSubnetValidatorTx(tx *txs.AddSubnetValidatorTx) error { @@ -66,7 +66,7 @@ func (fc *Calculator) AddSubnetValidatorTx(tx *txs.AddSubnetValidatorTx) error { return err } - return fc.processFees(consumedUnits) + return fc.ProcessFees(consumedUnits) } func (fc *Calculator) AddDelegatorTx(tx *txs.AddDelegatorTx) error { @@ -84,7 +84,7 @@ func (fc *Calculator) AddDelegatorTx(tx *txs.AddDelegatorTx) error { return err } - return fc.processFees(consumedUnits) + return fc.ProcessFees(consumedUnits) } func (fc *Calculator) CreateChainTx(tx *txs.CreateChainTx) error { @@ -98,7 +98,7 @@ func (fc *Calculator) CreateChainTx(tx *txs.CreateChainTx) error { return err } - return fc.processFees(consumedUnits) + return fc.ProcessFees(consumedUnits) } func (fc *Calculator) CreateSubnetTx(tx *txs.CreateSubnetTx) error { @@ -112,7 +112,7 @@ func (fc *Calculator) CreateSubnetTx(tx *txs.CreateSubnetTx) error { return err } - return fc.processFees(consumedUnits) + return fc.ProcessFees(consumedUnits) } func (*Calculator) AdvanceTimeTx(*txs.AdvanceTimeTx) error { @@ -134,7 +134,7 @@ func (fc *Calculator) RemoveSubnetValidatorTx(tx *txs.RemoveSubnetValidatorTx) e return err } - return fc.processFees(consumedUnits) + return fc.ProcessFees(consumedUnits) } func (fc *Calculator) TransformSubnetTx(tx *txs.TransformSubnetTx) error { @@ -148,7 +148,7 @@ func (fc *Calculator) TransformSubnetTx(tx *txs.TransformSubnetTx) error { return err } - return fc.processFees(consumedUnits) + return fc.ProcessFees(consumedUnits) } func (fc *Calculator) TransferSubnetOwnershipTx(tx *txs.TransferSubnetOwnershipTx) error { @@ -162,7 +162,7 @@ func (fc *Calculator) TransferSubnetOwnershipTx(tx *txs.TransferSubnetOwnershipT return err } - return fc.processFees(consumedUnits) + return fc.ProcessFees(consumedUnits) } func (fc *Calculator) AddPermissionlessValidatorTx(tx *txs.AddPermissionlessValidatorTx) error { @@ -184,7 +184,7 @@ func (fc *Calculator) AddPermissionlessValidatorTx(tx *txs.AddPermissionlessVali return err } - return fc.processFees(consumedUnits) + return fc.ProcessFees(consumedUnits) } func (fc *Calculator) AddPermissionlessDelegatorTx(tx *txs.AddPermissionlessDelegatorTx) error { @@ -206,7 +206,7 @@ func (fc *Calculator) AddPermissionlessDelegatorTx(tx *txs.AddPermissionlessDele return err } - return fc.processFees(consumedUnits) + return fc.ProcessFees(consumedUnits) } func (fc *Calculator) BaseTx(tx *txs.BaseTx) error { @@ -220,7 +220,7 @@ func (fc *Calculator) BaseTx(tx *txs.BaseTx) error { return err } - return fc.processFees(consumedUnits) + return fc.ProcessFees(consumedUnits) } func (fc *Calculator) ImportTx(tx *txs.ImportTx) error { @@ -238,7 +238,7 @@ func (fc *Calculator) ImportTx(tx *txs.ImportTx) error { return err } - return fc.processFees(consumedUnits) + return fc.ProcessFees(consumedUnits) } func (fc *Calculator) ExportTx(tx *txs.ExportTx) error { @@ -256,7 +256,7 @@ func (fc *Calculator) ExportTx(tx *txs.ExportTx) error { return err } - return fc.processFees(consumedUnits) + return fc.ProcessFees(consumedUnits) } func GetInputsDimensions(in *avax.TransferableInput) (fees.Dimensions, error) { @@ -348,7 +348,7 @@ func (fc *Calculator) commonConsumedUnits( return consumedUnits, nil } -func (fc *Calculator) processFees(consumedUnits fees.Dimensions) error { +func (fc *Calculator) ProcessFees(consumedUnits fees.Dimensions) error { boundBreached, dimension := fc.FeeManager.CumulateUnits(consumedUnits, fc.Config.BlockMaxConsumedUnits(fc.ChainTime)) if boundBreached { return fmt.Errorf("%w: breached dimension %d", errFailedConsumedUnitsCumulation, dimension) diff --git a/vms/platformvm/utxo/handler.go b/vms/platformvm/utxo/handler.go index 790f53904ae3..577b434f5c87 100644 --- a/vms/platformvm/utxo/handler.go +++ b/vms/platformvm/utxo/handler.go @@ -74,7 +74,6 @@ type Spender interface { utxoReader avax.UTXOReader, keys []*secp256k1.PrivateKey, amount uint64, - uTx txs.UnsignedTx, feeCalc *fees.Calculator, changeAddr ids.ShortID, ) ( @@ -410,7 +409,6 @@ func (h *handler) FinanceTx( utxoReader avax.UTXOReader, keys []*secp256k1.PrivateKey, amount uint64, - uTx txs.UnsignedTx, feeCalc *fees.Calculator, changeAddr ids.ShortID, ) ( @@ -578,12 +576,22 @@ func (h *handler) FinanceTx( // happen continue } + avaxIn := &avax.TransferableInput{ + UTXOID: utxo.UTXOID, + Asset: avax.Asset{ID: h.ctx.AVAXAssetID}, + In: in, + } // The remaining value is initially the full value of the input remainingValue := in.Amount() - if err := uTx.Visit(feeCalc); err != nil { - return nil, nil, nil, nil, fmt.Errorf("couldn't get UTXOs: %w", err) + // update fees to target given the extra input added + insDimensions, err := fees.GetInputsDimensions(avaxIn) + if err != nil { + return nil, nil, nil, nil, fmt.Errorf("failed calculating input size: %w", err) + } + if err := feeCalc.ProcessFees(insDimensions); err != nil { + return nil, nil, nil, nil, fmt.Errorf("account for input fees: %w", err) } targetFee = feeCalc.Fee @@ -604,15 +612,12 @@ func (h *handler) FinanceTx( remainingValue -= amountToStake // Add the input to the consumed inputs - ins = append(ins, &avax.TransferableInput{ - UTXOID: utxo.UTXOID, - Asset: avax.Asset{ID: h.ctx.AVAXAssetID}, - In: in, - }) + ins = append(ins, avaxIn) if amountToStake > 0 { // Some of this input was put for staking - stakedOuts = append(stakedOuts, &avax.TransferableOutput{ + + stakedOut := &avax.TransferableOutput{ Asset: avax.Asset{ID: h.ctx.AVAXAssetID}, Out: &secp256k1fx.TransferOutput{ Amt: amountToStake, @@ -622,7 +627,19 @@ func (h *handler) FinanceTx( Addrs: []ids.ShortID{changeAddr}, }, }, - }) + } + + // update fees to target given the extra input added + outDimensions, err := fees.GetOutputsDimensions(stakedOut) + if err != nil { + return nil, nil, nil, nil, fmt.Errorf("failed calculating output size: %w", err) + } + if err := feeCalc.ProcessFees(outDimensions); err != nil { + return nil, nil, nil, nil, fmt.Errorf("account for output fees: %w", err) + } + targetFee = feeCalc.Fee + + stakedOuts = append(stakedOuts, stakedOut) } if remainingValue > 0 { diff --git a/vms/platformvm/utxo/handler_test.go b/vms/platformvm/utxo/handler_test.go index 62d9ab975dff..ec84ce0f7d79 100644 --- a/vms/platformvm/utxo/handler_test.go +++ b/vms/platformvm/utxo/handler_test.go @@ -5,6 +5,7 @@ package utxo import ( "math" + "math/rand" "testing" "time" @@ -41,11 +42,11 @@ func (*dummyUnsignedTx) Visit(txs.Visitor) error { func TestVerifyFinanceTx(t *testing.T) { fx := &secp256k1fx.Fx{} - require.NoError(t, fx.InitializeVM(&secp256k1fx.TestVM{})) require.NoError(t, fx.Bootstrapped()) ctx := snowtest.Context(t, snowtest.PChainID) + keys := secp256k1.TestKeys() h := &handler{ ctx: ctx, @@ -70,18 +71,85 @@ func TestVerifyFinanceTx(t *testing.T) { }, } + bigUnlockedUTXO := &avax.UTXO{ + UTXOID: avax.UTXOID{ + TxID: ids.GenerateTestID(), + OutputIndex: rand.Uint32(), // #nosec G404 + }, + Asset: avax.Asset{ID: ctx.AVAXAssetID}, + Out: &secp256k1fx.TransferOutput{ + Amt: 100 * units.Avax, + OutputOwners: secp256k1fx.OutputOwners{ + Locktime: 0, + Addrs: []ids.ShortID{keys[0].PublicKey().Address()}, + Threshold: 1, + }, + }, + } + bigUnlockedUTXOID := bigUnlockedUTXO.InputID() + tests := []struct { description string utxoReaderF func(ctrl *gomock.Controller) avax.UTXOReader - keys []*secp256k1.PrivateKey amountToStake uint64 - uTxF func() txs.UnsignedTx + uTxF func(t *testing.T) txs.UnsignedTx feeCalcF func() *fees.Calculator changeAddr ids.ShortID expectedErr error checksF func(*testing.T, *fees.Calculator, []*avax.TransferableInput, []*avax.TransferableOutput, []*avax.TransferableOutput) }{ + { + description: "simple tx no stake outputs", + utxoReaderF: func(ctrl *gomock.Controller) avax.UTXOReader { + s := state.NewMockState(ctrl) + s.EXPECT().UTXOIDs(gomock.Any(), gomock.Any(), gomock.Any()).Return([]ids.ID{bigUnlockedUTXOID}, nil).AnyTimes() + s.EXPECT().GetUTXO(bigUnlockedUTXOID).Return(bigUnlockedUTXO, nil).AnyTimes() + return s + }, + + amountToStake: 0, + uTxF: func(t *testing.T) txs.UnsignedTx { + uTx := &txs.CreateChainTx{ + BaseTx: txs.BaseTx{ + BaseTx: avax.BaseTx{ + NetworkID: ctx.NetworkID, + BlockchainID: ctx.ChainID, + Ins: make([]*avax.TransferableInput, 0), + Outs: make([]*avax.TransferableOutput, 0), + Memo: []byte{'a', 'b', 'c'}, + }, + }, + SubnetID: ids.GenerateTestID(), + ChainName: "testChain", + VMID: ids.GenerateTestID(), + SubnetAuth: &secp256k1fx.Input{}, + } + + bytes, err := txs.Codec.Marshal(txs.CodecVersion, uTx) + require.NoError(t, err) + + uTx.SetBytes(bytes) + return uTx + }, + feeCalcF: func() *fees.Calculator { + fm := commonfees.NewManager(cfg.DefaultUnitFees) + feesCalc := fees.Calculator{ + FeeManager: fm, + Config: cfg, + ChainTime: time.Time{}, + Credentials: []verify.Verifiable{}, + } + return &feesCalc + }, + expectedErr: nil, + checksF: func(t *testing.T, calc *fees.Calculator, ins []*avax.TransferableInput, outs, staked []*avax.TransferableOutput) { + require.Equal(t, 2538*units.MicroAvax, calc.Fee) + // require.Empty(t, ins) + // require.Empty(t, outs) + require.Empty(t, staked) + }, + }, { description: "no inputs, no outputs, no fee", utxoReaderF: func(ctrl *gomock.Controller) avax.UTXOReader { @@ -89,9 +157,8 @@ func TestVerifyFinanceTx(t *testing.T) { s.EXPECT().UTXOIDs(gomock.Any(), gomock.Any(), gomock.Any()).Return([]ids.ID{}, nil).AnyTimes() return s }, - keys: secp256k1.TestKeys(), amountToStake: 0, - uTxF: func() txs.UnsignedTx { + uTxF: func(t *testing.T) txs.UnsignedTx { unsignedTx := dummyUnsignedTx{ BaseTx: txs.BaseTx{}, } @@ -120,19 +187,23 @@ func TestVerifyFinanceTx(t *testing.T) { for _, test := range tests { t.Run(test.description, func(t *testing.T) { + r := require.New(t) ctrl := gomock.NewController(t) + uTx := test.uTxF(t) feeCalc := test.feeCalcF() + // init fee calc with the uTx data + r.NoError(uTx.Visit(feeCalc)) + ins, outs, staked, _, err := h.FinanceTx( test.utxoReaderF(ctrl), - test.keys, + keys, test.amountToStake, - test.uTxF(), feeCalc, test.changeAddr, ) - require.ErrorIs(t, err, test.expectedErr) + r.ErrorIs(err, test.expectedErr) test.checksF(t, feeCalc, ins, outs, staked) }) } From f472b39b0e6051fa9629c96838a34c347cd0a55c Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Fri, 12 Jan 2024 17:42:04 +0100 Subject: [PATCH 032/190] wip: keep on drafting tx financing with dynamic fees --- vms/platformvm/utxo/handler.go | 37 ++++++++++++++++++++++------- vms/platformvm/utxo/handler_test.go | 7 +++--- 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/vms/platformvm/utxo/handler.go b/vms/platformvm/utxo/handler.go index 577b434f5c87..4e882ec9bc9b 100644 --- a/vms/platformvm/utxo/handler.go +++ b/vms/platformvm/utxo/handler.go @@ -576,7 +576,7 @@ func (h *handler) FinanceTx( // happen continue } - avaxIn := &avax.TransferableInput{ + input := &avax.TransferableInput{ UTXOID: utxo.UTXOID, Asset: avax.Asset{ID: h.ctx.AVAXAssetID}, In: in, @@ -586,14 +586,14 @@ func (h *handler) FinanceTx( remainingValue := in.Amount() // update fees to target given the extra input added - insDimensions, err := fees.GetInputsDimensions(avaxIn) + insDimensions, err := fees.GetInputsDimensions(input) if err != nil { return nil, nil, nil, nil, fmt.Errorf("failed calculating input size: %w", err) } if err := feeCalc.ProcessFees(insDimensions); err != nil { return nil, nil, nil, nil, fmt.Errorf("account for input fees: %w", err) } - targetFee = feeCalc.Fee + targetFee += feeCalc.Fee // Burn any value that should be burned amountToBurn := math.Min( @@ -612,7 +612,7 @@ func (h *handler) FinanceTx( remainingValue -= amountToStake // Add the input to the consumed inputs - ins = append(ins, avaxIn) + ins = append(ins, input) if amountToStake > 0 { // Some of this input was put for staking @@ -637,24 +637,43 @@ func (h *handler) FinanceTx( if err := feeCalc.ProcessFees(outDimensions); err != nil { return nil, nil, nil, nil, fmt.Errorf("account for output fees: %w", err) } - targetFee = feeCalc.Fee + targetFee += feeCalc.Fee stakedOuts = append(stakedOuts, stakedOut) } if remainingValue > 0 { - // This input had extra value, so some of it must be returned - returnedOuts = append(returnedOuts, &avax.TransferableOutput{ + changeOut := &avax.TransferableOutput{ Asset: avax.Asset{ID: h.ctx.AVAXAssetID}, Out: &secp256k1fx.TransferOutput{ - Amt: remainingValue, + // Amt: remainingValue, // SET IT AFTER CONSIDERING IT'S OWN FEE OutputOwners: secp256k1fx.OutputOwners{ Locktime: 0, Threshold: 1, Addrs: []ids.ShortID{changeAddr}, }, }, - }) + } + + // update fees to target given the extra input added + outDimensions, err := fees.GetOutputsDimensions(changeOut) + if err != nil { + return nil, nil, nil, nil, fmt.Errorf("failed calculating output size: %w", err) + } + if err := feeCalc.ProcessFees(outDimensions); err != nil { + return nil, nil, nil, nil, fmt.Errorf("account for output fees: %w", err) + } + targetFee += feeCalc.Fee + + if remainingValue > feeCalc.Fee { + amountBurned += feeCalc.Fee + changeOut.Out.(*secp256k1fx.TransferOutput).Amt = remainingValue - feeCalc.Fee + // This input had extra value, so some of it must be returned + returnedOuts = append(returnedOuts, changeOut) + } + + // This UTXO has not enough value to cover for its own taxes. + // Let's fully consume it and move to the next UTXO to pay for it } // Add the signers needed for this input to the set of signers diff --git a/vms/platformvm/utxo/handler_test.go b/vms/platformvm/utxo/handler_test.go index ec84ce0f7d79..16362c8362f1 100644 --- a/vms/platformvm/utxo/handler_test.go +++ b/vms/platformvm/utxo/handler_test.go @@ -144,9 +144,10 @@ func TestVerifyFinanceTx(t *testing.T) { }, expectedErr: nil, checksF: func(t *testing.T, calc *fees.Calculator, ins []*avax.TransferableInput, outs, staked []*avax.TransferableOutput) { - require.Equal(t, 2538*units.MicroAvax, calc.Fee) - // require.Empty(t, ins) - // require.Empty(t, outs) + expectedFee := 3014 * units.MicroAvax + require.Len(t, ins, 1) + require.Len(t, outs, 1) + require.Equal(t, expectedFee, ins[0].In.Amount()-outs[0].Out.Amount()) require.Empty(t, staked) }, }, From 8b8c1fa520acd633bb218f8076d0d21dc2ecc782 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 15 Jan 2024 12:16:17 +0100 Subject: [PATCH 033/190] some more UTs --- vms/platformvm/utxo/handler.go | 12 ++- vms/platformvm/utxo/handler_test.go | 136 +++++++++++++++++++++++----- 2 files changed, 122 insertions(+), 26 deletions(-) diff --git a/vms/platformvm/utxo/handler.go b/vms/platformvm/utxo/handler.go index 4e882ec9bc9b..67c3378cd219 100644 --- a/vms/platformvm/utxo/handler.go +++ b/vms/platformvm/utxo/handler.go @@ -646,7 +646,7 @@ func (h *handler) FinanceTx( changeOut := &avax.TransferableOutput{ Asset: avax.Asset{ID: h.ctx.AVAXAssetID}, Out: &secp256k1fx.TransferOutput{ - // Amt: remainingValue, // SET IT AFTER CONSIDERING IT'S OWN FEE + // Amt: remainingValue, // SET IT AFTER CONSIDERING ITS OWN FEES OutputOwners: secp256k1fx.OutputOwners{ Locktime: 0, Threshold: 1, @@ -663,17 +663,19 @@ func (h *handler) FinanceTx( if err := feeCalc.ProcessFees(outDimensions); err != nil { return nil, nil, nil, nil, fmt.Errorf("account for output fees: %w", err) } - targetFee += feeCalc.Fee if remainingValue > feeCalc.Fee { + targetFee += feeCalc.Fee amountBurned += feeCalc.Fee - changeOut.Out.(*secp256k1fx.TransferOutput).Amt = remainingValue - feeCalc.Fee + remainingValue -= feeCalc.Fee + + changeOut.Out.(*secp256k1fx.TransferOutput).Amt = remainingValue // This input had extra value, so some of it must be returned returnedOuts = append(returnedOuts, changeOut) } - // This UTXO has not enough value to cover for its own taxes. - // Let's fully consume it and move to the next UTXO to pay for it + // If this UTXO has not enough value to cover for its own taxes, + // we fully consume it (no output) and move to the next UTXO to pay for it. } // Add the signers needed for this input to the set of signers diff --git a/vms/platformvm/utxo/handler_test.go b/vms/platformvm/utxo/handler_test.go index 16362c8362f1..c0b84022d080 100644 --- a/vms/platformvm/utxo/handler_test.go +++ b/vms/platformvm/utxo/handler_test.go @@ -5,7 +5,6 @@ package utxo import ( "math" - "math/rand" "testing" "time" @@ -71,26 +70,56 @@ func TestVerifyFinanceTx(t *testing.T) { }, } - bigUnlockedUTXO := &avax.UTXO{ - UTXOID: avax.UTXOID{ - TxID: ids.GenerateTestID(), - OutputIndex: rand.Uint32(), // #nosec G404 - }, - Asset: avax.Asset{ID: ctx.AVAXAssetID}, - Out: &secp256k1fx.TransferOutput{ - Amt: 100 * units.Avax, - OutputOwners: secp256k1fx.OutputOwners{ - Locktime: 0, - Addrs: []ids.ShortID{keys[0].PublicKey().Address()}, - Threshold: 1, - }, - }, - } - bigUnlockedUTXOID := bigUnlockedUTXO.InputID() + var ( + bigUtxoTxID = ids.GenerateTestID() + bigUtxoKey = keys[0] + bigUtxoAddr = bigUtxoKey.PublicKey().Address() + bigUtxoAmount = 5 * units.MilliAvax + bigUtxo = &avax.UTXO{ + UTXOID: avax.UTXOID{ + TxID: bigUtxoTxID, + OutputIndex: 0, + }, + Asset: avax.Asset{ID: ctx.AVAXAssetID}, + Out: &secp256k1fx.TransferOutput{ + Amt: bigUtxoAmount, + OutputOwners: secp256k1fx.OutputOwners{ + Locktime: 0, + Addrs: []ids.ShortID{bigUtxoAddr}, + Threshold: 1, + }, + }, + } + bigUtxoID = bigUtxo.InputID() + + smallUtxoTxID = ids.GenerateTestID() + smallUtxoKey = keys[1] + smallUtxoAddr = smallUtxoKey.PublicKey().Address() + smallUtxoAmount = 2 * units.MilliAvax + smallUtxo = &avax.UTXO{ + UTXOID: avax.UTXOID{ + TxID: smallUtxoTxID, + OutputIndex: 0, + }, + Asset: avax.Asset{ID: ctx.AVAXAssetID}, + Out: &secp256k1fx.TransferOutput{ + Amt: smallUtxoAmount, + OutputOwners: secp256k1fx.OutputOwners{ + Locktime: 0, + Addrs: []ids.ShortID{smallUtxoAddr}, + Threshold: 1, + }, + }, + } + smallUtxoID = smallUtxo.InputID() + ) + + require.True(t, smallUtxoID.Compare(bigUtxoID) < 0) tests := []struct { description string utxoReaderF func(ctrl *gomock.Controller) avax.UTXOReader + keysF func() []*secp256k1.PrivateKey amountToStake uint64 uTxF func(t *testing.T) txs.UnsignedTx feeCalcF func() *fees.Calculator @@ -100,13 +129,16 @@ func TestVerifyFinanceTx(t *testing.T) { checksF func(*testing.T, *fees.Calculator, []*avax.TransferableInput, []*avax.TransferableOutput, []*avax.TransferableOutput) }{ { - description: "simple tx no stake outputs", + description: "Tx, no stake outputs, single UTXO", utxoReaderF: func(ctrl *gomock.Controller) avax.UTXOReader { s := state.NewMockState(ctrl) - s.EXPECT().UTXOIDs(gomock.Any(), gomock.Any(), gomock.Any()).Return([]ids.ID{bigUnlockedUTXOID}, nil).AnyTimes() - s.EXPECT().GetUTXO(bigUnlockedUTXOID).Return(bigUnlockedUTXO, nil).AnyTimes() + s.EXPECT().UTXOIDs(bigUtxoAddr.Bytes(), gomock.Any(), gomock.Any()).Return([]ids.ID{bigUtxoID}, nil).AnyTimes() + s.EXPECT().GetUTXO(bigUtxoID).Return(bigUtxo, nil).AnyTimes() return s }, + keysF: func() []*secp256k1.PrivateKey { + return []*secp256k1.PrivateKey{bigUtxoKey} + }, amountToStake: 0, uTxF: func(t *testing.T) txs.UnsignedTx { @@ -151,6 +183,65 @@ func TestVerifyFinanceTx(t *testing.T) { require.Empty(t, staked) }, }, + { + description: "Tx, no stake outputs, multiple UTXOs", + utxoReaderF: func(ctrl *gomock.Controller) avax.UTXOReader { + s := state.NewMockState(ctrl) + s.EXPECT().UTXOIDs(smallUtxoAddr.Bytes(), gomock.Any(), gomock.Any()).Return([]ids.ID{smallUtxoID}, nil).AnyTimes() + s.EXPECT().GetUTXO(smallUtxoID).Return(smallUtxo, nil).AnyTimes() + + s.EXPECT().UTXOIDs(bigUtxoAddr.Bytes(), gomock.Any(), gomock.Any()).Return([]ids.ID{bigUtxoID}, nil).AnyTimes() + s.EXPECT().GetUTXO(bigUtxoID).Return(bigUtxo, nil).AnyTimes() + + return s + }, + keysF: func() []*secp256k1.PrivateKey { + return []*secp256k1.PrivateKey{smallUtxoKey, bigUtxoKey} + }, + + amountToStake: 0, + uTxF: func(t *testing.T) txs.UnsignedTx { + uTx := &txs.CreateChainTx{ + BaseTx: txs.BaseTx{ + BaseTx: avax.BaseTx{ + NetworkID: ctx.NetworkID, + BlockchainID: ctx.ChainID, + Ins: make([]*avax.TransferableInput, 0), + Outs: make([]*avax.TransferableOutput, 0), + Memo: []byte{'a', 'b', 'c'}, + }, + }, + SubnetID: ids.GenerateTestID(), + ChainName: "testChain", + VMID: ids.GenerateTestID(), + SubnetAuth: &secp256k1fx.Input{}, + } + + bytes, err := txs.Codec.Marshal(txs.CodecVersion, uTx) + require.NoError(t, err) + + uTx.SetBytes(bytes) + return uTx + }, + feeCalcF: func() *fees.Calculator { + fm := commonfees.NewManager(cfg.DefaultUnitFees) + feesCalc := fees.Calculator{ + FeeManager: fm, + Config: cfg, + ChainTime: time.Time{}, + Credentials: []verify.Verifiable{}, + } + return &feesCalc + }, + expectedErr: nil, + checksF: func(t *testing.T, calc *fees.Calculator, ins []*avax.TransferableInput, outs, staked []*avax.TransferableOutput) { + expectedFee := 5552 * units.MicroAvax + require.Len(t, ins, 2) + require.Len(t, outs, 1) + require.Equal(t, expectedFee, ins[0].In.Amount()+ins[1].In.Amount()-outs[0].Out.Amount()) + require.Empty(t, staked) + }, + }, { description: "no inputs, no outputs, no fee", utxoReaderF: func(ctrl *gomock.Controller) avax.UTXOReader { @@ -158,6 +249,9 @@ func TestVerifyFinanceTx(t *testing.T) { s.EXPECT().UTXOIDs(gomock.Any(), gomock.Any(), gomock.Any()).Return([]ids.ID{}, nil).AnyTimes() return s }, + keysF: func() []*secp256k1.PrivateKey { + return []*secp256k1.PrivateKey{} + }, amountToStake: 0, uTxF: func(t *testing.T) txs.UnsignedTx { unsignedTx := dummyUnsignedTx{ @@ -199,7 +293,7 @@ func TestVerifyFinanceTx(t *testing.T) { ins, outs, staked, _, err := h.FinanceTx( test.utxoReaderF(ctrl), - keys, + test.keysF(), test.amountToStake, feeCalc, test.changeAddr, From 2ff80c8ef708e518b2cc90ba5a60417cc44e5b3d Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 15 Jan 2024 14:00:34 +0100 Subject: [PATCH 034/190] added UTs for stake amounts --- vms/platformvm/utxo/handler.go | 8 +- vms/platformvm/utxo/handler_test.go | 142 +++++++++++++++++++++++++++- 2 files changed, 147 insertions(+), 3 deletions(-) diff --git a/vms/platformvm/utxo/handler.go b/vms/platformvm/utxo/handler.go index 67c3378cd219..ac39dceb5f4a 100644 --- a/vms/platformvm/utxo/handler.go +++ b/vms/platformvm/utxo/handler.go @@ -616,7 +616,6 @@ func (h *handler) FinanceTx( if amountToStake > 0 { // Some of this input was put for staking - stakedOut := &avax.TransferableOutput{ Asset: avax.Asset{ID: h.ctx.AVAXAssetID}, Out: &secp256k1fx.TransferOutput{ @@ -639,6 +638,13 @@ func (h *handler) FinanceTx( } targetFee += feeCalc.Fee + amountToBurn := math.Min( + targetFee-amountBurned, // Amount we still need to burn + remainingValue, // Amount available to burn + ) + amountBurned += amountToBurn + remainingValue -= amountToBurn + stakedOuts = append(stakedOuts, stakedOut) } diff --git a/vms/platformvm/utxo/handler_test.go b/vms/platformvm/utxo/handler_test.go index c0b84022d080..15aa1c0c1a2e 100644 --- a/vms/platformvm/utxo/handler_test.go +++ b/vms/platformvm/utxo/handler_test.go @@ -19,6 +19,7 @@ import ( "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/components/verify" "github.com/ava-labs/avalanchego/vms/platformvm/config" + "github.com/ava-labs/avalanchego/vms/platformvm/reward" "github.com/ava-labs/avalanchego/vms/platformvm/stakeable" "github.com/ava-labs/avalanchego/vms/platformvm/state" "github.com/ava-labs/avalanchego/vms/platformvm/txs" @@ -114,11 +115,16 @@ func TestVerifyFinanceTx(t *testing.T) { smallUtxoID = smallUtxo.InputID() ) + // this UTXOs ordering ensures that smallUtxo will be picked first, + // even if bigUtxo would be enough finance the whole tx require.True(t, smallUtxoID.Compare(bigUtxoID) < 0) tests := []struct { - description string - utxoReaderF func(ctrl *gomock.Controller) avax.UTXOReader + description string + utxoReaderF func(ctrl *gomock.Controller) avax.UTXOReader + + // keysF simplifies the utxoReade mock setup. We just specify here + // the only keys referenced by the test scenario keysF func() []*secp256k1.PrivateKey amountToStake uint64 uTxF func(t *testing.T) txs.UnsignedTx @@ -128,6 +134,138 @@ func TestVerifyFinanceTx(t *testing.T) { expectedErr error checksF func(*testing.T, *fees.Calculator, []*avax.TransferableInput, []*avax.TransferableOutput, []*avax.TransferableOutput) }{ + { + description: "Tx, stake outputs,, multiple UTXOs", + utxoReaderF: func(ctrl *gomock.Controller) avax.UTXOReader { + s := state.NewMockState(ctrl) + s.EXPECT().UTXOIDs(smallUtxoAddr.Bytes(), gomock.Any(), gomock.Any()).Return([]ids.ID{smallUtxoID}, nil).AnyTimes() + s.EXPECT().GetUTXO(smallUtxoID).Return(smallUtxo, nil).AnyTimes() + + s.EXPECT().UTXOIDs(bigUtxoAddr.Bytes(), gomock.Any(), gomock.Any()).Return([]ids.ID{bigUtxoID}, nil).AnyTimes() + s.EXPECT().GetUTXO(bigUtxoID).Return(bigUtxo, nil).AnyTimes() + + return s + }, + keysF: func() []*secp256k1.PrivateKey { + return []*secp256k1.PrivateKey{smallUtxoKey, bigUtxoKey} + }, + + amountToStake: units.MilliAvax, + uTxF: func(t *testing.T) txs.UnsignedTx { + uTx := &txs.AddValidatorTx{ + BaseTx: txs.BaseTx{ + BaseTx: avax.BaseTx{ + NetworkID: ctx.NetworkID, + BlockchainID: ctx.ChainID, + Ins: make([]*avax.TransferableInput, 0), + Outs: make([]*avax.TransferableOutput, 0), + Memo: []byte{'a', 'b', 'c'}, + }, + }, + Validator: txs.Validator{ + NodeID: ids.GenerateTestNodeID(), + Start: 0, + End: uint64(time.Now().Unix()), + Wght: units.MilliAvax, + }, + StakeOuts: make([]*avax.TransferableOutput, 0), + RewardsOwner: &secp256k1fx.OutputOwners{ + Locktime: 0, + Threshold: 1, + Addrs: []ids.ShortID{ids.GenerateTestShortID()}, + }, + DelegationShares: reward.PercentDenominator, + } + + bytes, err := txs.Codec.Marshal(txs.CodecVersion, uTx) + require.NoError(t, err) + + uTx.SetBytes(bytes) + return uTx + }, + feeCalcF: func() *fees.Calculator { + fm := commonfees.NewManager(cfg.DefaultUnitFees) + feesCalc := fees.Calculator{ + FeeManager: fm, + Config: cfg, + ChainTime: time.Time{}, + Credentials: []verify.Verifiable{}, + } + return &feesCalc + }, + expectedErr: nil, + checksF: func(t *testing.T, calc *fees.Calculator, ins []*avax.TransferableInput, outs, staked []*avax.TransferableOutput) { + expectedFee := 5879 * units.MicroAvax + require.Len(t, ins, 2) + require.Len(t, staked, 1) + require.Len(t, outs, 1) + require.Equal(t, expectedFee, ins[0].In.Amount()+ins[1].In.Amount()-staked[0].Out.Amount()-outs[0].Out.Amount()) + }, + }, + { + description: "Tx, stake outputs, single UTXO", + utxoReaderF: func(ctrl *gomock.Controller) avax.UTXOReader { + s := state.NewMockState(ctrl) + s.EXPECT().UTXOIDs(bigUtxoAddr.Bytes(), gomock.Any(), gomock.Any()).Return([]ids.ID{bigUtxoID}, nil).AnyTimes() + s.EXPECT().GetUTXO(bigUtxoID).Return(bigUtxo, nil).AnyTimes() + return s + }, + keysF: func() []*secp256k1.PrivateKey { + return []*secp256k1.PrivateKey{bigUtxoKey} + }, + + amountToStake: units.MilliAvax, + uTxF: func(t *testing.T) txs.UnsignedTx { + uTx := &txs.AddValidatorTx{ + BaseTx: txs.BaseTx{ + BaseTx: avax.BaseTx{ + NetworkID: ctx.NetworkID, + BlockchainID: ctx.ChainID, + Ins: make([]*avax.TransferableInput, 0), + Outs: make([]*avax.TransferableOutput, 0), + Memo: []byte{'a', 'b', 'c'}, + }, + }, + Validator: txs.Validator{ + NodeID: ids.GenerateTestNodeID(), + Start: 0, + End: uint64(time.Now().Unix()), + Wght: units.MilliAvax, + }, + StakeOuts: make([]*avax.TransferableOutput, 0), + RewardsOwner: &secp256k1fx.OutputOwners{ + Locktime: 0, + Threshold: 1, + Addrs: []ids.ShortID{ids.GenerateTestShortID()}, + }, + DelegationShares: reward.PercentDenominator, + } + + bytes, err := txs.Codec.Marshal(txs.CodecVersion, uTx) + require.NoError(t, err) + + uTx.SetBytes(bytes) + return uTx + }, + feeCalcF: func() *fees.Calculator { + fm := commonfees.NewManager(cfg.DefaultUnitFees) + feesCalc := fees.Calculator{ + FeeManager: fm, + Config: cfg, + ChainTime: time.Time{}, + Credentials: []verify.Verifiable{}, + } + return &feesCalc + }, + expectedErr: nil, + checksF: func(t *testing.T, calc *fees.Calculator, ins []*avax.TransferableInput, outs, staked []*avax.TransferableOutput) { + expectedFee := 3341 * units.MicroAvax + require.Len(t, ins, 1) + require.Len(t, staked, 1) + require.Len(t, outs, 1) + require.Equal(t, expectedFee, ins[0].In.Amount()-staked[0].Out.Amount()-outs[0].Out.Amount()) + }, + }, { description: "Tx, no stake outputs, single UTXO", utxoReaderF: func(ctrl *gomock.Controller) avax.UTXOReader { From 1c151c0480addfcaa19b872ea7a46b6b7350de6a Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 15 Jan 2024 14:23:02 +0100 Subject: [PATCH 035/190] nit: simplified UTs --- vms/platformvm/utxo/handler_test.go | 63 +++++------------------------ 1 file changed, 9 insertions(+), 54 deletions(-) diff --git a/vms/platformvm/utxo/handler_test.go b/vms/platformvm/utxo/handler_test.go index 15aa1c0c1a2e..cb788f727ab3 100644 --- a/vms/platformvm/utxo/handler_test.go +++ b/vms/platformvm/utxo/handler_test.go @@ -128,8 +128,6 @@ func TestVerifyFinanceTx(t *testing.T) { keysF func() []*secp256k1.PrivateKey amountToStake uint64 uTxF func(t *testing.T) txs.UnsignedTx - feeCalcF func() *fees.Calculator - changeAddr ids.ShortID expectedErr error checksF func(*testing.T, *fees.Calculator, []*avax.TransferableInput, []*avax.TransferableOutput, []*avax.TransferableOutput) @@ -183,16 +181,6 @@ func TestVerifyFinanceTx(t *testing.T) { uTx.SetBytes(bytes) return uTx }, - feeCalcF: func() *fees.Calculator { - fm := commonfees.NewManager(cfg.DefaultUnitFees) - feesCalc := fees.Calculator{ - FeeManager: fm, - Config: cfg, - ChainTime: time.Time{}, - Credentials: []verify.Verifiable{}, - } - return &feesCalc - }, expectedErr: nil, checksF: func(t *testing.T, calc *fees.Calculator, ins []*avax.TransferableInput, outs, staked []*avax.TransferableOutput) { expectedFee := 5879 * units.MicroAvax @@ -247,16 +235,6 @@ func TestVerifyFinanceTx(t *testing.T) { uTx.SetBytes(bytes) return uTx }, - feeCalcF: func() *fees.Calculator { - fm := commonfees.NewManager(cfg.DefaultUnitFees) - feesCalc := fees.Calculator{ - FeeManager: fm, - Config: cfg, - ChainTime: time.Time{}, - Credentials: []verify.Verifiable{}, - } - return &feesCalc - }, expectedErr: nil, checksF: func(t *testing.T, calc *fees.Calculator, ins []*avax.TransferableInput, outs, staked []*avax.TransferableOutput) { expectedFee := 3341 * units.MicroAvax @@ -302,16 +280,6 @@ func TestVerifyFinanceTx(t *testing.T) { uTx.SetBytes(bytes) return uTx }, - feeCalcF: func() *fees.Calculator { - fm := commonfees.NewManager(cfg.DefaultUnitFees) - feesCalc := fees.Calculator{ - FeeManager: fm, - Config: cfg, - ChainTime: time.Time{}, - Credentials: []verify.Verifiable{}, - } - return &feesCalc - }, expectedErr: nil, checksF: func(t *testing.T, calc *fees.Calculator, ins []*avax.TransferableInput, outs, staked []*avax.TransferableOutput) { expectedFee := 3014 * units.MicroAvax @@ -361,16 +329,6 @@ func TestVerifyFinanceTx(t *testing.T) { uTx.SetBytes(bytes) return uTx }, - feeCalcF: func() *fees.Calculator { - fm := commonfees.NewManager(cfg.DefaultUnitFees) - feesCalc := fees.Calculator{ - FeeManager: fm, - Config: cfg, - ChainTime: time.Time{}, - Credentials: []verify.Verifiable{}, - } - return &feesCalc - }, expectedErr: nil, checksF: func(t *testing.T, calc *fees.Calculator, ins []*avax.TransferableInput, outs, staked []*avax.TransferableOutput) { expectedFee := 5552 * units.MicroAvax @@ -398,16 +356,6 @@ func TestVerifyFinanceTx(t *testing.T) { unsignedTx.SetBytes([]byte{0}) return &unsignedTx }, - feeCalcF: func() *fees.Calculator { - fm := commonfees.NewManager(cfg.DefaultUnitFees) - feesCalc := fees.Calculator{ - FeeManager: fm, - Config: cfg, - ChainTime: time.Time{}, - Credentials: []verify.Verifiable{}, - } - return &feesCalc - }, expectedErr: nil, checksF: func(t *testing.T, calc *fees.Calculator, ins []*avax.TransferableInput, outs, staked []*avax.TransferableOutput) { require.Zero(t, calc.Fee) @@ -424,7 +372,14 @@ func TestVerifyFinanceTx(t *testing.T) { ctrl := gomock.NewController(t) uTx := test.uTxF(t) - feeCalc := test.feeCalcF() + + fm := commonfees.NewManager(cfg.DefaultUnitFees) + feeCalc := &fees.Calculator{ + FeeManager: fm, + Config: cfg, + ChainTime: time.Time{}, + Credentials: []verify.Verifiable{}, + } // init fee calc with the uTx data r.NoError(uTx.Visit(feeCalc)) @@ -434,7 +389,7 @@ func TestVerifyFinanceTx(t *testing.T) { test.keysF(), test.amountToStake, feeCalc, - test.changeAddr, + ids.GenerateTestShortID(), ) r.ErrorIs(err, test.expectedErr) test.checksF(t, feeCalc, ins, outs, staked) From c1b8f7a7b4d177366094a5e5bfddd60e2aed2143 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 15 Jan 2024 14:36:46 +0100 Subject: [PATCH 036/190] extended UTs checks --- vms/platformvm/utxo/handler_test.go | 108 +++++++++++++++++++++------- 1 file changed, 81 insertions(+), 27 deletions(-) diff --git a/vms/platformvm/utxo/handler_test.go b/vms/platformvm/utxo/handler_test.go index cb788f727ab3..32f234bd1ad2 100644 --- a/vms/platformvm/utxo/handler_test.go +++ b/vms/platformvm/utxo/handler_test.go @@ -130,7 +130,7 @@ func TestVerifyFinanceTx(t *testing.T) { uTxF func(t *testing.T) txs.UnsignedTx expectedErr error - checksF func(*testing.T, *fees.Calculator, []*avax.TransferableInput, []*avax.TransferableOutput, []*avax.TransferableOutput) + checksF func(*testing.T, txs.UnsignedTx, *fees.Calculator, []*avax.TransferableInput, []*avax.TransferableOutput, []*avax.TransferableOutput) }{ { description: "Tx, stake outputs,, multiple UTXOs", @@ -182,12 +182,25 @@ func TestVerifyFinanceTx(t *testing.T) { return uTx }, expectedErr: nil, - checksF: func(t *testing.T, calc *fees.Calculator, ins []*avax.TransferableInput, outs, staked []*avax.TransferableOutput) { + checksF: func(t *testing.T, uTx txs.UnsignedTx, calc *fees.Calculator, ins []*avax.TransferableInput, outs, staked []*avax.TransferableOutput) { + r := require.New(t) expectedFee := 5879 * units.MicroAvax - require.Len(t, ins, 2) - require.Len(t, staked, 1) - require.Len(t, outs, 1) - require.Equal(t, expectedFee, ins[0].In.Amount()+ins[1].In.Amount()-staked[0].Out.Amount()-outs[0].Out.Amount()) + + // complete uTx with the utxos + addVal, ok := uTx.(*txs.AddValidatorTx) + r.True(ok) + + addVal.Ins = ins + addVal.Outs = outs + addVal.StakeOuts = staked + + r.NoError(uTx.Visit(calc)) + r.Equal(expectedFee, calc.Fee) + + r.Len(ins, 2) + r.Len(staked, 1) + r.Len(outs, 1) + r.Equal(expectedFee, ins[0].In.Amount()+ins[1].In.Amount()-staked[0].Out.Amount()-outs[0].Out.Amount()) }, }, { @@ -236,12 +249,25 @@ func TestVerifyFinanceTx(t *testing.T) { return uTx }, expectedErr: nil, - checksF: func(t *testing.T, calc *fees.Calculator, ins []*avax.TransferableInput, outs, staked []*avax.TransferableOutput) { + checksF: func(t *testing.T, uTx txs.UnsignedTx, calc *fees.Calculator, ins []*avax.TransferableInput, outs, staked []*avax.TransferableOutput) { + r := require.New(t) expectedFee := 3341 * units.MicroAvax - require.Len(t, ins, 1) - require.Len(t, staked, 1) - require.Len(t, outs, 1) - require.Equal(t, expectedFee, ins[0].In.Amount()-staked[0].Out.Amount()-outs[0].Out.Amount()) + + // complete uTx with the utxos + addVal, ok := uTx.(*txs.AddValidatorTx) + r.True(ok) + + addVal.Ins = ins + addVal.Outs = outs + addVal.StakeOuts = staked + + r.NoError(uTx.Visit(calc)) + r.Equal(expectedFee, calc.Fee) + + r.Len(ins, 1) + r.Len(staked, 1) + r.Len(outs, 1) + r.Equal(expectedFee, ins[0].In.Amount()-staked[0].Out.Amount()-outs[0].Out.Amount()) }, }, { @@ -281,12 +307,24 @@ func TestVerifyFinanceTx(t *testing.T) { return uTx }, expectedErr: nil, - checksF: func(t *testing.T, calc *fees.Calculator, ins []*avax.TransferableInput, outs, staked []*avax.TransferableOutput) { + checksF: func(t *testing.T, uTx txs.UnsignedTx, calc *fees.Calculator, ins []*avax.TransferableInput, outs, staked []*avax.TransferableOutput) { + r := require.New(t) expectedFee := 3014 * units.MicroAvax - require.Len(t, ins, 1) - require.Len(t, outs, 1) - require.Equal(t, expectedFee, ins[0].In.Amount()-outs[0].Out.Amount()) - require.Empty(t, staked) + + // complete uTx with the utxos + addVal, ok := uTx.(*txs.CreateChainTx) + r.True(ok) + + addVal.Ins = ins + addVal.Outs = outs + + r.NoError(uTx.Visit(calc)) + r.Equal(expectedFee, calc.Fee) + + r.Len(ins, 1) + r.Len(outs, 1) + r.Equal(expectedFee, ins[0].In.Amount()-outs[0].Out.Amount()) + r.Empty(staked) }, }, { @@ -330,12 +368,24 @@ func TestVerifyFinanceTx(t *testing.T) { return uTx }, expectedErr: nil, - checksF: func(t *testing.T, calc *fees.Calculator, ins []*avax.TransferableInput, outs, staked []*avax.TransferableOutput) { + checksF: func(t *testing.T, uTx txs.UnsignedTx, calc *fees.Calculator, ins []*avax.TransferableInput, outs, staked []*avax.TransferableOutput) { + r := require.New(t) expectedFee := 5552 * units.MicroAvax - require.Len(t, ins, 2) - require.Len(t, outs, 1) - require.Equal(t, expectedFee, ins[0].In.Amount()+ins[1].In.Amount()-outs[0].Out.Amount()) - require.Empty(t, staked) + + // complete uTx with the utxos + addVal, ok := uTx.(*txs.CreateChainTx) + r.True(ok) + + addVal.Ins = ins + addVal.Outs = outs + + r.NoError(uTx.Visit(calc)) + r.Equal(expectedFee, calc.Fee) + + r.Len(ins, 2) + r.Len(outs, 1) + r.Equal(expectedFee, ins[0].In.Amount()+ins[1].In.Amount()-outs[0].Out.Amount()) + r.Empty(staked) }, }, { @@ -357,11 +407,15 @@ func TestVerifyFinanceTx(t *testing.T) { return &unsignedTx }, expectedErr: nil, - checksF: func(t *testing.T, calc *fees.Calculator, ins []*avax.TransferableInput, outs, staked []*avax.TransferableOutput) { - require.Zero(t, calc.Fee) - require.Empty(t, ins) - require.Empty(t, outs) - require.Empty(t, staked) + checksF: func(t *testing.T, uTx txs.UnsignedTx, calc *fees.Calculator, ins []*avax.TransferableInput, outs, staked []*avax.TransferableOutput) { + r := require.New(t) + + r.NoError(uTx.Visit(calc)) + r.Zero(calc.Fee) + + r.Empty(ins) + r.Empty(outs) + r.Empty(staked) }, }, } @@ -392,7 +446,7 @@ func TestVerifyFinanceTx(t *testing.T) { ids.GenerateTestShortID(), ) r.ErrorIs(err, test.expectedErr) - test.checksF(t, feeCalc, ins, outs, staked) + test.checksF(t, uTx, feeCalc, ins, outs, staked) }) } } From 67fa06ead8e09b77eb79baa9014eae545929b627 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 15 Jan 2024 14:59:37 +0100 Subject: [PATCH 037/190] nit --- vms/platformvm/utxo/handler.go | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/vms/platformvm/utxo/handler.go b/vms/platformvm/utxo/handler.go index ac39dceb5f4a..01885d229bc8 100644 --- a/vms/platformvm/utxo/handler.go +++ b/vms/platformvm/utxo/handler.go @@ -485,6 +485,14 @@ func (h *handler) FinanceTx( ) continue } + input := &avax.TransferableInput{ + UTXOID: utxo.UTXOID, + Asset: avax.Asset{ID: h.ctx.AVAXAssetID}, + In: &stakeable.LockIn{ + Locktime: out.Locktime, + TransferableIn: in, + }, + } // The remaining value is initially the full value of the input remainingValue := in.Amount() @@ -498,17 +506,9 @@ func (h *handler) FinanceTx( remainingValue -= amountToStake // Add the input to the consumed inputs - ins = append(ins, &avax.TransferableInput{ - UTXOID: utxo.UTXOID, - Asset: avax.Asset{ID: h.ctx.AVAXAssetID}, - In: &stakeable.LockIn{ - Locktime: out.Locktime, - TransferableIn: in, - }, - }) + ins = append(ins, input) - // Add the output to the staked outputs - stakedOuts = append(stakedOuts, &avax.TransferableOutput{ + stakedOut := &avax.TransferableOutput{ Asset: avax.Asset{ID: h.ctx.AVAXAssetID}, Out: &stakeable.LockOut{ Locktime: out.Locktime, @@ -517,12 +517,15 @@ func (h *handler) FinanceTx( OutputOwners: inner.OutputOwners, }, }, - }) + } + + // Add the output to the staked outputs + stakedOuts = append(stakedOuts, stakedOut) if remainingValue > 0 { // This input provided more value than was needed to be locked. // Some of it must be returned - returnedOuts = append(returnedOuts, &avax.TransferableOutput{ + changeOut := &avax.TransferableOutput{ Asset: avax.Asset{ID: h.ctx.AVAXAssetID}, Out: &stakeable.LockOut{ Locktime: out.Locktime, @@ -531,7 +534,8 @@ func (h *handler) FinanceTx( OutputOwners: inner.OutputOwners, }, }, - }) + } + returnedOuts = append(returnedOuts, changeOut) } // Add the signers needed for this input to the set of signers From ac1d066fc16c416f28f71d42d856f355972ae496 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 15 Jan 2024 15:16:43 +0100 Subject: [PATCH 038/190] added UTs with locked UTXOs --- vms/platformvm/utxo/handler.go | 31 ++++++++ vms/platformvm/utxo/handler_test.go | 106 ++++++++++++++++++++++++++-- 2 files changed, 132 insertions(+), 5 deletions(-) diff --git a/vms/platformvm/utxo/handler.go b/vms/platformvm/utxo/handler.go index 01885d229bc8..88b4ab9e3ce9 100644 --- a/vms/platformvm/utxo/handler.go +++ b/vms/platformvm/utxo/handler.go @@ -497,6 +497,16 @@ func (h *handler) FinanceTx( // The remaining value is initially the full value of the input remainingValue := in.Amount() + // update fees to target given the extra input added + insDimensions, err := fees.GetInputsDimensions(input) + if err != nil { + return nil, nil, nil, nil, fmt.Errorf("failed calculating input size: %w", err) + } + if err := feeCalc.ProcessFees(insDimensions); err != nil { + return nil, nil, nil, nil, fmt.Errorf("account for input fees: %w", err) + } + targetFee += feeCalc.Fee + // Stake any value that should be staked amountToStake := math.Min( amount-amountStaked, // Amount we still need to stake @@ -519,6 +529,16 @@ func (h *handler) FinanceTx( }, } + // update fees to target given the staked output added + outDimensions, err := fees.GetOutputsDimensions(stakedOut) + if err != nil { + return nil, nil, nil, nil, fmt.Errorf("failed calculating stakedOut size: %w", err) + } + if err := feeCalc.ProcessFees(outDimensions); err != nil { + return nil, nil, nil, nil, fmt.Errorf("account for stakedOut fees: %w", err) + } + targetFee += feeCalc.Fee + // Add the output to the staked outputs stakedOuts = append(stakedOuts, stakedOut) @@ -535,6 +555,17 @@ func (h *handler) FinanceTx( }, }, } + + // update fees to target given the change output added + outDimensions, err := fees.GetOutputsDimensions(changeOut) + if err != nil { + return nil, nil, nil, nil, fmt.Errorf("failed calculating changeOut size: %w", err) + } + if err := feeCalc.ProcessFees(outDimensions); err != nil { + return nil, nil, nil, nil, fmt.Errorf("account for stakedOut fees: %w", err) + } + targetFee += feeCalc.Fee + returnedOuts = append(returnedOuts, changeOut) } diff --git a/vms/platformvm/utxo/handler_test.go b/vms/platformvm/utxo/handler_test.go index 32f234bd1ad2..89fceea39edb 100644 --- a/vms/platformvm/utxo/handler_test.go +++ b/vms/platformvm/utxo/handler_test.go @@ -72,10 +72,12 @@ func TestVerifyFinanceTx(t *testing.T) { } var ( + amountToStake = units.MilliAvax + bigUtxoTxID = ids.GenerateTestID() - bigUtxoKey = keys[0] + bigUtxoKey = keys[1] bigUtxoAddr = bigUtxoKey.PublicKey().Address() - bigUtxoAmount = 5 * units.MilliAvax + bigUtxoAmount = 6 * units.MilliAvax bigUtxo = &avax.UTXO{ UTXOID: avax.UTXOID{ TxID: bigUtxoTxID, @@ -94,7 +96,7 @@ func TestVerifyFinanceTx(t *testing.T) { bigUtxoID = bigUtxo.InputID() smallUtxoTxID = ids.GenerateTestID() - smallUtxoKey = keys[1] + smallUtxoKey = keys[2] smallUtxoAddr = smallUtxoKey.PublicKey().Address() smallUtxoAmount = 2 * units.MilliAvax smallUtxo = &avax.UTXO{ @@ -113,6 +115,31 @@ func TestVerifyFinanceTx(t *testing.T) { }, } smallUtxoID = smallUtxo.InputID() + + lockedUtxoTxID = ids.GenerateTestID() + lockedUtxoKey = keys[0] + lockedUtxoAddr = lockedUtxoKey.PublicKey().Address() + lockedUtxoAmount = amountToStake + + lockedUtxo = &avax.UTXO{ + UTXOID: avax.UTXOID{ + TxID: lockedUtxoTxID, + OutputIndex: 0, + }, + Asset: avax.Asset{ID: ctx.AVAXAssetID}, + Out: &stakeable.LockOut{ + Locktime: uint64(time.Now().Add(time.Hour).Unix()), + TransferableOut: &secp256k1fx.TransferOutput{ + Amt: lockedUtxoAmount, + OutputOwners: secp256k1fx.OutputOwners{ + Locktime: 0, + Addrs: []ids.ShortID{lockedUtxoAddr}, + Threshold: 1, + }, + }, + }, + } + lockedUtxoID = lockedUtxo.InputID() ) // this UTXOs ordering ensures that smallUtxo will be picked first, @@ -132,6 +159,75 @@ func TestVerifyFinanceTx(t *testing.T) { expectedErr error checksF func(*testing.T, txs.UnsignedTx, *fees.Calculator, []*avax.TransferableInput, []*avax.TransferableOutput, []*avax.TransferableOutput) }{ + { + description: "Tx, stake outputs, single locked and unlocked UTXOs", + utxoReaderF: func(ctrl *gomock.Controller) avax.UTXOReader { + s := state.NewMockState(ctrl) + s.EXPECT().UTXOIDs(lockedUtxoAddr.Bytes(), gomock.Any(), gomock.Any()).Return([]ids.ID{lockedUtxoID}, nil).AnyTimes() + s.EXPECT().GetUTXO(lockedUtxoID).Return(lockedUtxo, nil).AnyTimes() + s.EXPECT().UTXOIDs(bigUtxoAddr.Bytes(), gomock.Any(), gomock.Any()).Return([]ids.ID{bigUtxoID}, nil).AnyTimes() + s.EXPECT().GetUTXO(bigUtxoID).Return(bigUtxo, nil).AnyTimes() + return s + }, + keysF: func() []*secp256k1.PrivateKey { + return []*secp256k1.PrivateKey{lockedUtxoKey, bigUtxoKey} + }, + + amountToStake: units.MilliAvax, + uTxF: func(t *testing.T) txs.UnsignedTx { + uTx := &txs.AddValidatorTx{ + BaseTx: txs.BaseTx{ + BaseTx: avax.BaseTx{ + NetworkID: ctx.NetworkID, + BlockchainID: ctx.ChainID, + Ins: make([]*avax.TransferableInput, 0), + Outs: make([]*avax.TransferableOutput, 0), + Memo: []byte{'a', 'b', 'c'}, + }, + }, + Validator: txs.Validator{ + NodeID: ids.GenerateTestNodeID(), + Start: 0, + End: uint64(time.Now().Unix()), + Wght: amountToStake, + }, + StakeOuts: make([]*avax.TransferableOutput, 0), + RewardsOwner: &secp256k1fx.OutputOwners{ + Locktime: 0, + Threshold: 1, + Addrs: []ids.ShortID{ids.GenerateTestShortID()}, + }, + DelegationShares: reward.PercentDenominator, + } + + bytes, err := txs.Codec.Marshal(txs.CodecVersion, uTx) + require.NoError(t, err) + + uTx.SetBytes(bytes) + return uTx + }, + expectedErr: nil, + checksF: func(t *testing.T, uTx txs.UnsignedTx, calc *fees.Calculator, ins []*avax.TransferableInput, outs, staked []*avax.TransferableOutput) { + r := require.New(t) + expectedFee := 5999 * units.MicroAvax + + // complete uTx with the utxos + addVal, ok := uTx.(*txs.AddValidatorTx) + r.True(ok) + + addVal.Ins = ins + addVal.Outs = outs + addVal.StakeOuts = staked + + r.NoError(uTx.Visit(calc)) + r.Equal(expectedFee, calc.Fee) + + r.Len(ins, 2) + r.Len(staked, 1) + r.Len(outs, 1) + r.Equal(expectedFee, ins[1].In.Amount()-outs[0].Out.Amount()) + }, + }, { description: "Tx, stake outputs,, multiple UTXOs", utxoReaderF: func(ctrl *gomock.Controller) avax.UTXOReader { @@ -164,7 +260,7 @@ func TestVerifyFinanceTx(t *testing.T) { NodeID: ids.GenerateTestNodeID(), Start: 0, End: uint64(time.Now().Unix()), - Wght: units.MilliAvax, + Wght: amountToStake, }, StakeOuts: make([]*avax.TransferableOutput, 0), RewardsOwner: &secp256k1fx.OutputOwners{ @@ -231,7 +327,7 @@ func TestVerifyFinanceTx(t *testing.T) { NodeID: ids.GenerateTestNodeID(), Start: 0, End: uint64(time.Now().Unix()), - Wght: units.MilliAvax, + Wght: amountToStake, }, StakeOuts: make([]*avax.TransferableOutput, 0), RewardsOwner: &secp256k1fx.OutputOwners{ From 7f9bc12bc6ac8f28195125013fc814eb53e209c8 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 15 Jan 2024 15:23:08 +0100 Subject: [PATCH 039/190] nit --- vms/platformvm/utxo/handler_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vms/platformvm/utxo/handler_test.go b/vms/platformvm/utxo/handler_test.go index 89fceea39edb..785b4bc83d6a 100644 --- a/vms/platformvm/utxo/handler_test.go +++ b/vms/platformvm/utxo/handler_test.go @@ -75,7 +75,7 @@ func TestVerifyFinanceTx(t *testing.T) { amountToStake = units.MilliAvax bigUtxoTxID = ids.GenerateTestID() - bigUtxoKey = keys[1] + bigUtxoKey = keys[0] bigUtxoAddr = bigUtxoKey.PublicKey().Address() bigUtxoAmount = 6 * units.MilliAvax bigUtxo = &avax.UTXO{ @@ -96,7 +96,7 @@ func TestVerifyFinanceTx(t *testing.T) { bigUtxoID = bigUtxo.InputID() smallUtxoTxID = ids.GenerateTestID() - smallUtxoKey = keys[2] + smallUtxoKey = keys[1] smallUtxoAddr = smallUtxoKey.PublicKey().Address() smallUtxoAmount = 2 * units.MilliAvax smallUtxo = &avax.UTXO{ @@ -117,7 +117,7 @@ func TestVerifyFinanceTx(t *testing.T) { smallUtxoID = smallUtxo.InputID() lockedUtxoTxID = ids.GenerateTestID() - lockedUtxoKey = keys[0] + lockedUtxoKey = keys[2] lockedUtxoAddr = lockedUtxoKey.PublicKey().Address() lockedUtxoAmount = amountToStake From dc8566890816ff43309b9395b9c638f431a8e47f Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 15 Jan 2024 16:08:41 +0100 Subject: [PATCH 040/190] nits --- vms/platformvm/utxo/handler_test.go | 125 ++++++++++++++++++++++++++-- 1 file changed, 117 insertions(+), 8 deletions(-) diff --git a/vms/platformvm/utxo/handler_test.go b/vms/platformvm/utxo/handler_test.go index 785b4bc83d6a..2027c6cee7c0 100644 --- a/vms/platformvm/utxo/handler_test.go +++ b/vms/platformvm/utxo/handler_test.go @@ -74,10 +74,10 @@ func TestVerifyFinanceTx(t *testing.T) { var ( amountToStake = units.MilliAvax - bigUtxoTxID = ids.GenerateTestID() + bigUtxoTxID = ids.ID{0x0, 0x1} bigUtxoKey = keys[0] bigUtxoAddr = bigUtxoKey.PublicKey().Address() - bigUtxoAmount = 6 * units.MilliAvax + bigUtxoAmount = 10 * units.MilliAvax bigUtxo = &avax.UTXO{ UTXOID: avax.UTXOID{ TxID: bigUtxoTxID, @@ -95,7 +95,7 @@ func TestVerifyFinanceTx(t *testing.T) { } bigUtxoID = bigUtxo.InputID() - smallUtxoTxID = ids.GenerateTestID() + smallUtxoTxID = ids.ID{0x0, 0x2} smallUtxoKey = keys[1] smallUtxoAddr = smallUtxoKey.PublicKey().Address() smallUtxoAmount = 2 * units.MilliAvax @@ -116,7 +116,7 @@ func TestVerifyFinanceTx(t *testing.T) { } smallUtxoID = smallUtxo.InputID() - lockedUtxoTxID = ids.GenerateTestID() + lockedUtxoTxID = ids.ID{'c'} lockedUtxoKey = keys[2] lockedUtxoAddr = lockedUtxoKey.PublicKey().Address() lockedUtxoAmount = amountToStake @@ -140,6 +140,31 @@ func TestVerifyFinanceTx(t *testing.T) { }, } lockedUtxoID = lockedUtxo.InputID() + + bigLockedUtxoTxID = ids.ID{'d'} + bigLockedUtxoKey = keys[2] + bigLockedUtxoAddr = bigLockedUtxoKey.PublicKey().Address() + bigLockedUtxoAmount = amountToStake * 10 + + bigLockedUtxo = &avax.UTXO{ + UTXOID: avax.UTXOID{ + TxID: bigLockedUtxoTxID, + OutputIndex: 0, + }, + Asset: avax.Asset{ID: ctx.AVAXAssetID}, + Out: &stakeable.LockOut{ + Locktime: uint64(time.Now().Add(time.Hour).Unix()), + TransferableOut: &secp256k1fx.TransferOutput{ + Amt: bigLockedUtxoAmount, + OutputOwners: secp256k1fx.OutputOwners{ + Locktime: 0, + Addrs: []ids.ShortID{bigLockedUtxoAddr}, + Threshold: 1, + }, + }, + }, + } + bigLockedUtxoID = bigLockedUtxo.InputID() ) // this UTXOs ordering ensures that smallUtxo will be picked first, @@ -159,6 +184,83 @@ func TestVerifyFinanceTx(t *testing.T) { expectedErr error checksF func(*testing.T, txs.UnsignedTx, *fees.Calculator, []*avax.TransferableInput, []*avax.TransferableOutput, []*avax.TransferableOutput) }{ + { + description: "Tx, stake outputs, single locked UTXO and multiple UTXOs", + utxoReaderF: func(ctrl *gomock.Controller) avax.UTXOReader { + s := state.NewMockState(ctrl) + s.EXPECT().UTXOIDs(smallUtxoAddr.Bytes(), gomock.Any(), gomock.Any()).Return([]ids.ID{smallUtxoID}, nil).AnyTimes() + s.EXPECT().GetUTXO(smallUtxoID).Return(smallUtxo, nil).AnyTimes() + + s.EXPECT().UTXOIDs(bigUtxoAddr.Bytes(), gomock.Any(), gomock.Any()).Return([]ids.ID{bigUtxoID}, nil).AnyTimes() + s.EXPECT().GetUTXO(bigUtxoID).Return(bigUtxo, nil).AnyTimes() + + s.EXPECT().UTXOIDs(bigLockedUtxoAddr.Bytes(), gomock.Any(), gomock.Any()).Return([]ids.ID{bigLockedUtxoID}, nil).AnyTimes() + s.EXPECT().GetUTXO(bigLockedUtxoID).Return(bigLockedUtxo, nil).AnyTimes() + + return s + }, + keysF: func() []*secp256k1.PrivateKey { + return []*secp256k1.PrivateKey{smallUtxoKey, bigUtxoKey, bigLockedUtxoKey} + }, + + amountToStake: units.MilliAvax, + uTxF: func(t *testing.T) txs.UnsignedTx { + uTx := &txs.AddValidatorTx{ + BaseTx: txs.BaseTx{ + BaseTx: avax.BaseTx{ + NetworkID: ctx.NetworkID, + BlockchainID: ctx.ChainID, + Ins: make([]*avax.TransferableInput, 0), + Outs: make([]*avax.TransferableOutput, 0), + Memo: []byte{'a', 'b', 'c'}, + }, + }, + Validator: txs.Validator{ + NodeID: ids.GenerateTestNodeID(), + Start: 0, + End: uint64(time.Now().Unix()), + Wght: amountToStake, + }, + StakeOuts: make([]*avax.TransferableOutput, 0), + RewardsOwner: &secp256k1fx.OutputOwners{ + Locktime: 0, + Threshold: 1, + Addrs: []ids.ShortID{ids.GenerateTestShortID()}, + }, + DelegationShares: reward.PercentDenominator, + } + + bytes, err := txs.Codec.Marshal(txs.CodecVersion, uTx) + require.NoError(t, err) + + uTx.SetBytes(bytes) + return uTx + }, + expectedErr: nil, + checksF: func(t *testing.T, uTx txs.UnsignedTx, calc *fees.Calculator, ins []*avax.TransferableInput, outs, staked []*avax.TransferableOutput) { + r := require.New(t) + expectedFee := 8911 * units.MicroAvax + + // complete uTx with the utxos + addVal, ok := uTx.(*txs.AddValidatorTx) + r.True(ok) + + addVal.Ins = ins + addVal.Outs = outs + addVal.StakeOuts = staked + + r.NoError(uTx.Visit(calc)) + r.Equal(expectedFee, calc.Fee) + + r.Len(ins, 3) + r.Len(staked, 1) + r.Len(outs, 2) + + r.Equal(amountToStake, staked[0].Out.Amount()) + r.Equal(amountToStake, ins[0].In.Amount()-outs[1].Out.Amount()) + r.Equal(expectedFee, ins[1].In.Amount()+ins[2].In.Amount()-outs[0].Out.Amount()) + }, + }, { description: "Tx, stake outputs, single locked and unlocked UTXOs", utxoReaderF: func(ctrl *gomock.Controller) avax.UTXOReader { @@ -225,11 +327,14 @@ func TestVerifyFinanceTx(t *testing.T) { r.Len(ins, 2) r.Len(staked, 1) r.Len(outs, 1) - r.Equal(expectedFee, ins[1].In.Amount()-outs[0].Out.Amount()) + + r.Equal(amountToStake, staked[0].Out.Amount()) + r.Equal(amountToStake, ins[1].In.Amount()) + r.Equal(expectedFee, ins[0].In.Amount()-outs[0].Out.Amount()) }, }, { - description: "Tx, stake outputs,, multiple UTXOs", + description: "Tx, stake outputs, multiple UTXOs", utxoReaderF: func(ctrl *gomock.Controller) avax.UTXOReader { s := state.NewMockState(ctrl) s.EXPECT().UTXOIDs(smallUtxoAddr.Bytes(), gomock.Any(), gomock.Any()).Return([]ids.ID{smallUtxoID}, nil).AnyTimes() @@ -296,7 +401,9 @@ func TestVerifyFinanceTx(t *testing.T) { r.Len(ins, 2) r.Len(staked, 1) r.Len(outs, 1) - r.Equal(expectedFee, ins[0].In.Amount()+ins[1].In.Amount()-staked[0].Out.Amount()-outs[0].Out.Amount()) + + r.Equal(amountToStake, staked[0].Out.Amount()) + r.Equal(expectedFee, ins[0].In.Amount()+ins[1].In.Amount()-amountToStake-outs[0].Out.Amount()) }, }, { @@ -363,7 +470,9 @@ func TestVerifyFinanceTx(t *testing.T) { r.Len(ins, 1) r.Len(staked, 1) r.Len(outs, 1) - r.Equal(expectedFee, ins[0].In.Amount()-staked[0].Out.Amount()-outs[0].Out.Amount()) + + r.Equal(amountToStake, staked[0].Out.Amount()) + r.Equal(expectedFee, ins[0].In.Amount()-amountToStake-outs[0].Out.Amount()) }, }, { From 5a684d319fdcad3696b6ff5ece9578e480329f59 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 15 Jan 2024 18:15:51 +0100 Subject: [PATCH 041/190] wip: extended financing of txs with dynamic fees --- vms/platformvm/txs/builder/builder.go | 284 ++++++++++++++++++++++++-- vms/platformvm/txs/tx.go | 16 +- 2 files changed, 276 insertions(+), 24 deletions(-) diff --git a/vms/platformvm/txs/builder/builder.go b/vms/platformvm/txs/builder/builder.go index 662382d2448f..1217c48f8db3 100644 --- a/vms/platformvm/txs/builder/builder.go +++ b/vms/platformvm/txs/builder/builder.go @@ -357,11 +357,42 @@ func (b *builder) NewExportTx( } // 2. Finance the tx by building the utxos (inputs, outputs and stakes) - toBurn, err := math.Add64(amount, b.cfg.TxFee) - if err != nil { - return nil, fmt.Errorf("amount (%d) + tx fee(%d) overflows", amount, b.cfg.TxFee) + var ( + chainTime = b.state.GetTimestamp() + ins []*avax.TransferableInput + outs []*avax.TransferableOutput + signers [][]*secp256k1.PrivateKey + err error + ) + if b.cfg.IsEForkActivated(chainTime) { + feesMan := commonfees.NewManager(b.cfg.DefaultUnitFees) + feeCalc := &fees.Calculator{ + FeeManager: feesMan, + Config: b.cfg, + ChainTime: b.state.GetTimestamp(), + Credentials: txs.EmptyCredentials(signers), + } + + // feesMan cumulates consumed units. Let's init it with utx filled so far + if err = feeCalc.ExportTx(utx); err != nil { + return nil, err + } + + ins, outs, _, signers, err = b.FinanceTx( + b.state, + keys, + 0, + feeCalc, + changeAddr, + ) + } else { + var toBurn uint64 + toBurn, err = math.Add64(amount, b.cfg.TxFee) + if err != nil { + return nil, fmt.Errorf("amount (%d) + tx fee(%d) overflows", amount, b.cfg.TxFee) + } + ins, outs, _, signers, err = b.Spend(b.state, keys, 0, toBurn, changeAddr) } - ins, outs, _, signers, err := b.Spend(b.state, keys, 0, toBurn, changeAddr) if err != nil { return nil, fmt.Errorf("couldn't generate tx inputs/outputs: %w", err) } @@ -408,9 +439,38 @@ func (b *builder) NewCreateChainTx( } // 2. Finance the tx by building the utxos (inputs, outputs and stakes) - timestamp := b.state.GetTimestamp() - createBlockchainTxFee := b.cfg.GetCreateBlockchainTxFee(timestamp) - ins, outs, _, signers, err := b.Spend(b.state, keys, 0, createBlockchainTxFee, changeAddr) + var ( + chainTime = b.state.GetTimestamp() + ins []*avax.TransferableInput + outs []*avax.TransferableOutput + signers [][]*secp256k1.PrivateKey + ) + if b.cfg.IsEForkActivated(chainTime) { + feesMan := commonfees.NewManager(b.cfg.DefaultUnitFees) + feeCalc := &fees.Calculator{ + FeeManager: feesMan, + Config: b.cfg, + ChainTime: b.state.GetTimestamp(), + Credentials: txs.EmptyCredentials(signers), + } + + // feesMan cumulates consumed units. Let's init it with utx filled so far + if err = feeCalc.CreateChainTx(utx); err != nil { + return nil, err + } + + ins, outs, _, signers, err = b.FinanceTx( + b.state, + keys, + 0, + feeCalc, + changeAddr, + ) + } else { + timestamp := b.state.GetTimestamp() + createBlockchainTxFee := b.cfg.GetCreateBlockchainTxFee(timestamp) + ins, outs, _, signers, err = b.Spend(b.state, keys, 0, createBlockchainTxFee, changeAddr) + } if err != nil { return nil, fmt.Errorf("couldn't generate tx inputs/outputs: %w", err) } @@ -458,10 +518,10 @@ func (b *builder) NewCreateSubnetTx( if b.cfg.IsEForkActivated(chainTime) { feesMan := commonfees.NewManager(b.cfg.DefaultUnitFees) feeCalc := &fees.Calculator{ - FeeManager: feesMan, - Config: b.cfg, - ChainTime: b.state.GetTimestamp(), - // Credentials: , + FeeManager: feesMan, + Config: b.cfg, + ChainTime: b.state.GetTimestamp(), + Credentials: txs.EmptyCredentials(signers), } // feesMan cumulates consumed units. Let's init it with utx filled so far @@ -526,13 +586,44 @@ func (b *builder) NewAddValidatorTx( } // 2. Finance the tx by building the utxos (inputs, outputs and stakes) - ins, unstakedOuts, stakedOuts, signers, err := b.Spend(b.state, keys, stakeAmount, b.cfg.AddPrimaryNetworkValidatorFee, changeAddr) + var ( + chainTime = b.state.GetTimestamp() + ins []*avax.TransferableInput + outs []*avax.TransferableOutput + stakedOuts []*avax.TransferableOutput + signers [][]*secp256k1.PrivateKey + err error + ) + if b.cfg.IsEForkActivated(chainTime) { + feesMan := commonfees.NewManager(b.cfg.DefaultUnitFees) + feeCalc := &fees.Calculator{ + FeeManager: feesMan, + Config: b.cfg, + ChainTime: b.state.GetTimestamp(), + Credentials: txs.EmptyCredentials(signers), + } + + // feesMan cumulates consumed units. Let's init it with utx filled so far + if err = feeCalc.AddValidatorTx(utx); err != nil { + return nil, err + } + + ins, outs, _, signers, err = b.FinanceTx( + b.state, + keys, + 0, + feeCalc, + changeAddr, + ) + } else { + ins, outs, stakedOuts, signers, err = b.Spend(b.state, keys, stakeAmount, b.cfg.AddPrimaryNetworkValidatorFee, changeAddr) + } if err != nil { return nil, fmt.Errorf("couldn't generate tx inputs/outputs: %w", err) } utx.BaseTx.Ins = ins - utx.BaseTx.Outs = unstakedOuts + utx.BaseTx.Outs = outs utx.StakeOuts = stakedOuts // 3. Sign the tx @@ -572,13 +663,44 @@ func (b *builder) NewAddDelegatorTx( } // 2. Finance the tx by building the utxos (inputs, outputs and stakes) - ins, unstakedOuts, stakedOuts, signers, err := b.Spend(b.state, keys, stakeAmount, b.cfg.AddPrimaryNetworkDelegatorFee, changeAddr) + var ( + chainTime = b.state.GetTimestamp() + ins []*avax.TransferableInput + outs []*avax.TransferableOutput + stakedOuts []*avax.TransferableOutput + signers [][]*secp256k1.PrivateKey + err error + ) + if b.cfg.IsEForkActivated(chainTime) { + feesMan := commonfees.NewManager(b.cfg.DefaultUnitFees) + feeCalc := &fees.Calculator{ + FeeManager: feesMan, + Config: b.cfg, + ChainTime: b.state.GetTimestamp(), + Credentials: txs.EmptyCredentials(signers), + } + + // feesMan cumulates consumed units. Let's init it with utx filled so far + if err = feeCalc.AddDelegatorTx(utx); err != nil { + return nil, err + } + + ins, outs, _, signers, err = b.FinanceTx( + b.state, + keys, + 0, + feeCalc, + changeAddr, + ) + } else { + ins, outs, stakedOuts, signers, err = b.Spend(b.state, keys, stakeAmount, b.cfg.AddPrimaryNetworkDelegatorFee, changeAddr) + } if err != nil { return nil, fmt.Errorf("couldn't generate tx inputs/outputs: %w", err) } utx.BaseTx.Ins = ins - utx.BaseTx.Outs = unstakedOuts + utx.BaseTx.Outs = outs utx.StakeOuts = stakedOuts // 3. Sign the tx @@ -621,7 +743,36 @@ func (b *builder) NewAddSubnetValidatorTx( } // 2. Finance the tx by building the utxos (inputs, outputs and stakes) - ins, outs, _, signers, err := b.Spend(b.state, keys, 0, b.cfg.TxFee, changeAddr) + var ( + chainTime = b.state.GetTimestamp() + ins []*avax.TransferableInput + outs []*avax.TransferableOutput + signers [][]*secp256k1.PrivateKey + ) + if b.cfg.IsEForkActivated(chainTime) { + feesMan := commonfees.NewManager(b.cfg.DefaultUnitFees) + feeCalc := &fees.Calculator{ + FeeManager: feesMan, + Config: b.cfg, + ChainTime: b.state.GetTimestamp(), + Credentials: txs.EmptyCredentials(signers), + } + + // feesMan cumulates consumed units. Let's init it with utx filled so far + if err = feeCalc.AddSubnetValidatorTx(utx); err != nil { + return nil, err + } + + ins, outs, _, signers, err = b.FinanceTx( + b.state, + keys, + 0, + feeCalc, + changeAddr, + ) + } else { + ins, outs, _, signers, err = b.Spend(b.state, keys, 0, b.cfg.TxFee, changeAddr) + } if err != nil { return nil, fmt.Errorf("couldn't generate tx inputs/outputs: %w", err) } @@ -660,7 +811,36 @@ func (b *builder) NewRemoveSubnetValidatorTx( } // 2. Finance the tx by building the utxos (inputs, outputs and stakes) - ins, outs, _, signers, err := b.Spend(b.state, keys, 0, b.cfg.TxFee, changeAddr) + var ( + chainTime = b.state.GetTimestamp() + ins []*avax.TransferableInput + outs []*avax.TransferableOutput + signers [][]*secp256k1.PrivateKey + ) + if b.cfg.IsEForkActivated(chainTime) { + feesMan := commonfees.NewManager(b.cfg.DefaultUnitFees) + feeCalc := &fees.Calculator{ + FeeManager: feesMan, + Config: b.cfg, + ChainTime: b.state.GetTimestamp(), + Credentials: txs.EmptyCredentials(signers), + } + + // feesMan cumulates consumed units. Let's init it with utx filled so far + if err = feeCalc.RemoveSubnetValidatorTx(utx); err != nil { + return nil, err + } + + ins, outs, _, signers, err = b.FinanceTx( + b.state, + keys, + 0, + feeCalc, + changeAddr, + ) + } else { + ins, outs, _, signers, err = b.Spend(b.state, keys, 0, b.cfg.TxFee, changeAddr) + } if err != nil { return nil, fmt.Errorf("couldn't generate tx inputs/outputs: %w", err) } @@ -722,7 +902,36 @@ func (b *builder) NewTransferSubnetOwnershipTx( } // 2. Finance the tx by building the utxos (inputs, outputs and stakes) - ins, outs, _, signers, err := b.Spend(b.state, keys, 0, b.cfg.TxFee, changeAddr) + var ( + chainTime = b.state.GetTimestamp() + ins []*avax.TransferableInput + outs []*avax.TransferableOutput + signers [][]*secp256k1.PrivateKey + ) + if b.cfg.IsEForkActivated(chainTime) { + feesMan := commonfees.NewManager(b.cfg.DefaultUnitFees) + feeCalc := &fees.Calculator{ + FeeManager: feesMan, + Config: b.cfg, + ChainTime: b.state.GetTimestamp(), + Credentials: txs.EmptyCredentials(signers), + } + + // feesMan cumulates consumed units. Let's init it with utx filled so far + if err = feeCalc.TransferSubnetOwnershipTx(utx); err != nil { + return nil, err + } + + ins, outs, _, signers, err = b.FinanceTx( + b.state, + keys, + 0, + feeCalc, + changeAddr, + ) + } else { + ins, outs, _, signers, err = b.Spend(b.state, keys, 0, b.cfg.TxFee, changeAddr) + } if err != nil { return nil, fmt.Errorf("couldn't generate tx inputs/outputs: %w", err) } @@ -754,11 +963,42 @@ func (b *builder) NewBaseTx( } // 2. Finance the tx by building the utxos (inputs, outputs and stakes) - toBurn, err := math.Add64(amount, b.cfg.TxFee) - if err != nil { - return nil, fmt.Errorf("amount (%d) + tx fee(%d) overflows", amount, b.cfg.TxFee) + var ( + chainTime = b.state.GetTimestamp() + ins []*avax.TransferableInput + outs []*avax.TransferableOutput + signers [][]*secp256k1.PrivateKey + err error + ) + if b.cfg.IsEForkActivated(chainTime) { + feesMan := commonfees.NewManager(b.cfg.DefaultUnitFees) + feeCalc := &fees.Calculator{ + FeeManager: feesMan, + Config: b.cfg, + ChainTime: b.state.GetTimestamp(), + Credentials: txs.EmptyCredentials(signers), + } + + // feesMan cumulates consumed units. Let's init it with utx filled so far + if err = feeCalc.BaseTx(utx); err != nil { + return nil, err + } + + ins, outs, _, signers, err = b.FinanceTx( + b.state, + keys, + 0, + feeCalc, + changeAddr, + ) + } else { + var toBurn uint64 + toBurn, err = math.Add64(amount, b.cfg.TxFee) + if err != nil { + return nil, fmt.Errorf("amount (%d) + tx fee(%d) overflows", amount, b.cfg.TxFee) + } + ins, outs, _, signers, err = b.Spend(b.state, keys, 0, toBurn, changeAddr) } - ins, outs, _, signers, err := b.Spend(b.state, keys, 0, toBurn, changeAddr) if err != nil { return nil, fmt.Errorf("couldn't generate tx inputs/outputs: %w", err) } diff --git a/vms/platformvm/txs/tx.go b/vms/platformvm/txs/tx.go index 9874f66e0468..c33f67c8cba3 100644 --- a/vms/platformvm/txs/tx.go +++ b/vms/platformvm/txs/tx.go @@ -138,8 +138,10 @@ func (tx *Tx) Sign(c codec.Manager, signers [][]*secp256k1.PrivateKey) error { } // Attach credentials + tx.Creds = EmptyCredentials(signers) + hash := hashing.ComputeHash256(unsignedBytes) - for _, keys := range signers { + for i, keys := range signers { cred := &secp256k1fx.Credential{ Sigs: make([][secp256k1.SignatureLen]byte, len(keys)), } @@ -150,7 +152,7 @@ func (tx *Tx) Sign(c codec.Manager, signers [][]*secp256k1.PrivateKey) error { } copy(cred.Sigs[i][:], sig) } - tx.Creds = append(tx.Creds, cred) // Attach credential + tx.Creds[i] = cred // Attach credential } signedBytes, err := c.Marshal(CodecVersion, tx) @@ -160,3 +162,13 @@ func (tx *Tx) Sign(c codec.Manager, signers [][]*secp256k1.PrivateKey) error { tx.SetBytes(unsignedBytes, signedBytes) return nil } + +func EmptyCredentials(signers [][]*secp256k1.PrivateKey) []verify.Verifiable { + creds := make([]verify.Verifiable, 0, len(signers)) + for i := 0; i < len(signers); i++ { + creds = append(creds, &secp256k1fx.Credential{ + Sigs: make([][secp256k1.SignatureLen]byte, len(signers)), + }) + } + return creds +} From a05df573e62591cc0328e296cbf96f94db28a77f Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Tue, 16 Jan 2024 15:59:33 +0100 Subject: [PATCH 042/190] wip: drafted ImportTx builder --- vms/components/fees/manager.go | 23 +++- vms/platformvm/txs/builder/builder.go | 152 +++++++++++++++++++++----- vms/platformvm/txs/fees/calculator.go | 42 ++++--- vms/platformvm/utxo/handler.go | 12 +- 4 files changed, 183 insertions(+), 46 deletions(-) diff --git a/vms/components/fees/manager.go b/vms/components/fees/manager.go index 9270f9798fa7..cfcf2beab493 100644 --- a/vms/components/fees/manager.go +++ b/vms/components/fees/manager.go @@ -3,7 +3,11 @@ package fees -import "github.com/ava-labs/avalanchego/utils/math" +import ( + "fmt" + + "github.com/ava-labs/avalanchego/utils/math" +) // Fees are not dynamic yet. We'll add mechanism for fee updating iterativelly @@ -48,6 +52,7 @@ func NewManager(unitFees Dimensions) *Manager { } } +// CalculateFee must be a stateless method func (m *Manager) CalculateFee(units Dimensions) (uint64, error) { fee := uint64(0) @@ -90,6 +95,22 @@ func (m *Manager) CumulateUnits(units, bounds Dimensions) (bool, Dimension) { return false, 0 } +// Sometimes, e.g. while building a tx, we'd like freedom to speculatively add units +// and to remove them later on. [RemoveUnits] grants this freedom +func (m *Manager) RemoveUnits(unitsToRm Dimensions) error { + var revertedUnits Dimensions + for i := Dimension(0); i < FeeDimensions; i++ { + prev, err := math.Sub(m.cumulatedUnits[i], unitsToRm[i]) + if err != nil { + return fmt.Errorf("%w: dimension %d", err, i) + } + revertedUnits[i] = prev + } + + m.cumulatedUnits = revertedUnits + return nil +} + func (m *Manager) GetCumulatedUnits() Dimensions { return m.cumulatedUnits } diff --git a/vms/platformvm/txs/builder/builder.go b/vms/platformvm/txs/builder/builder.go index 1217c48f8db3..d4edff49b72a 100644 --- a/vms/platformvm/txs/builder/builder.go +++ b/vms/platformvm/txs/builder/builder.go @@ -249,11 +249,14 @@ func (b *builder) NewImportTx( return nil, fmt.Errorf("problem retrieving atomic UTXOs: %w", err) } - importedInputs := []*avax.TransferableInput{} - signers := [][]*secp256k1.PrivateKey{} + var ( + importedInputs = []*avax.TransferableInput{} + signers = [][]*secp256k1.PrivateKey{} + outs = []*avax.TransferableOutput{} - importedAmounts := make(map[ids.ID]uint64) - now := b.clk.Unix() + importedAmounts = make(map[ids.ID]uint64) + now = b.clk.Unix() + ) for _, utxo := range atomicUTXOs { inputIntf, utxoSigners, err := kc.Spend(utxo.Out, now) if err != nil { @@ -275,32 +278,21 @@ func (b *builder) NewImportTx( }) signers = append(signers, utxoSigners) } - avax.SortTransferableInputsWithSigners(importedInputs, signers) - if len(importedAmounts) == 0 { return nil, ErrNoFunds // No imported UTXOs were spendable } - importedAVAX := importedAmounts[b.ctx.AVAXAssetID] - - ins := []*avax.TransferableInput{} - outs := []*avax.TransferableOutput{} - switch { - case importedAVAX < b.cfg.TxFee: // imported amount goes toward paying tx fee - var baseSigners [][]*secp256k1.PrivateKey - ins, outs, _, baseSigners, err = b.Spend(b.state, keys, 0, b.cfg.TxFee-importedAVAX, changeAddr) - if err != nil { - return nil, fmt.Errorf("couldn't generate tx inputs/outputs: %w", err) - } - signers = append(baseSigners, signers...) - delete(importedAmounts, b.ctx.AVAXAssetID) - case importedAVAX == b.cfg.TxFee: - delete(importedAmounts, b.ctx.AVAXAssetID) - default: - importedAmounts[b.ctx.AVAXAssetID] -= b.cfg.TxFee - } + // Sort and add imported txs to utx. Imported txs must not be + // changed here in after + avax.SortTransferableInputsWithSigners(importedInputs, signers) + utx.ImportedInputs = importedInputs + // add non avax-denominated outputs. Avax-denominated utxos + // are used to pay fees whose amount is calculated later on for assetID, amount := range importedAmounts { + if assetID == b.ctx.AVAXAssetID { + continue + } outs = append(outs, &avax.TransferableOutput{ Asset: avax.Asset{ID: assetID}, Out: &secp256k1fx.TransferOutput{ @@ -312,13 +304,123 @@ func (b *builder) NewImportTx( }, }, }) + delete(importedAmounts, assetID) + } + + var ( + ins []*avax.TransferableInput + + importedAVAX = importedAmounts[b.ctx.AVAXAssetID] // the only entry left in importedAmounts + chainTime = b.state.GetTimestamp() + ) + if b.cfg.IsEForkActivated(chainTime) { + // while outs are not ordered we add them to get current fees. We'll fix ordering later on + utx.BaseTx.Outs = outs + feesMan := commonfees.NewManager(b.cfg.DefaultUnitFees) + feeCalc := &fees.Calculator{ + FeeManager: feesMan, + Config: b.cfg, + ChainTime: b.state.GetTimestamp(), + Credentials: txs.EmptyCredentials(signers), + } + + // feesMan cumulates consumed units. Let's init it with utx filled so far + if err = feeCalc.ImportTx(utx); err != nil { + return nil, err + } + + if feeCalc.Fee >= importedAVAX { + // all imported avax will be burned to pay taxes. + // Fees are scaled back accordingly. + feeCalc.Fee -= importedAVAX + } else { + // imported inputs may be enough to pay taxes by themselves + changeOut := &avax.TransferableOutput{ + Asset: avax.Asset{ID: b.ctx.AVAXAssetID}, + Out: &secp256k1fx.TransferOutput{ + // Amt: importedAVAX, // SET IT AFTER CONSIDERING ITS OWN FEES + OutputOwners: secp256k1fx.OutputOwners{ + Locktime: 0, + Threshold: 1, + Addrs: []ids.ShortID{to}, + }, + }, + } + + // update fees to target given the extra input added + outDimensions, err := fees.GetOutputsDimensions(changeOut) + if err != nil { + return nil, fmt.Errorf("failed calculating output size: %w", err) + } + if err := feeCalc.AddFeesFor(outDimensions); err != nil { + return nil, fmt.Errorf("account for output fees: %w", err) + } + + if feeCalc.Fee >= importedAVAX { + // imported avax are not enough to pay fees + // Drop the changeOut and finance the tx + if err := feeCalc.RemoveFeesFor(outDimensions); err != nil { + return nil, fmt.Errorf("failed reverting change output: %w", err) + } + feeCalc.Fee -= importedAVAX + + var ( + financeOut []*avax.TransferableOutput + financeSigner [][]*secp256k1.PrivateKey + ) + ins, financeOut, _, financeSigner, err = b.FinanceTx( + b.state, + keys, + 0, + feeCalc, + changeAddr, + ) + if err != nil { + return nil, fmt.Errorf("couldn't generate tx inputs/outputs: %w", err) + } + outs = append(financeOut, outs...) + signers = append(financeSigner, signers...) + } else { + changeOut.Out.(*secp256k1fx.TransferOutput).Amt = importedAVAX - feeCalc.Fee + outs = append(outs, changeOut) + } + } + } else { + switch { + case importedAVAX < b.cfg.TxFee: // imported amount goes toward paying tx fee + var ( + baseOuts []*avax.TransferableOutput + baseSigners [][]*secp256k1.PrivateKey + ) + ins, baseOuts, _, baseSigners, err = b.Spend(b.state, keys, 0, b.cfg.TxFee-importedAVAX, changeAddr) + if err != nil { + return nil, fmt.Errorf("couldn't generate tx inputs/outputs: %w", err) + } + outs = append(baseOuts, outs...) + signers = append(baseSigners, signers...) + delete(importedAmounts, b.ctx.AVAXAssetID) + case importedAVAX == b.cfg.TxFee: + delete(importedAmounts, b.ctx.AVAXAssetID) + default: + importedAVAX -= b.cfg.TxFee + outs = append(outs, &avax.TransferableOutput{ + Asset: avax.Asset{ID: b.ctx.AVAXAssetID}, + Out: &secp256k1fx.TransferOutput{ + Amt: importedAVAX, + OutputOwners: secp256k1fx.OutputOwners{ + Locktime: 0, + Threshold: 1, + Addrs: []ids.ShortID{to}, + }, + }, + }) + } } avax.SortTransferableOutputs(outs, txs.Codec) // sort imported outputs utx.BaseTx.Ins = ins utx.BaseTx.Outs = outs - utx.ImportedInputs = importedInputs // 3. Sign the tx tx, err := txs.NewSigned(utx, txs.Codec, signers) diff --git a/vms/platformvm/txs/fees/calculator.go b/vms/platformvm/txs/fees/calculator.go index 4484c9c50040..55036d216818 100644 --- a/vms/platformvm/txs/fees/calculator.go +++ b/vms/platformvm/txs/fees/calculator.go @@ -52,7 +52,7 @@ func (fc *Calculator) AddValidatorTx(tx *txs.AddValidatorTx) error { return err } - return fc.ProcessFees(consumedUnits) + return fc.AddFeesFor(consumedUnits) } func (fc *Calculator) AddSubnetValidatorTx(tx *txs.AddSubnetValidatorTx) error { @@ -66,7 +66,7 @@ func (fc *Calculator) AddSubnetValidatorTx(tx *txs.AddSubnetValidatorTx) error { return err } - return fc.ProcessFees(consumedUnits) + return fc.AddFeesFor(consumedUnits) } func (fc *Calculator) AddDelegatorTx(tx *txs.AddDelegatorTx) error { @@ -84,7 +84,7 @@ func (fc *Calculator) AddDelegatorTx(tx *txs.AddDelegatorTx) error { return err } - return fc.ProcessFees(consumedUnits) + return fc.AddFeesFor(consumedUnits) } func (fc *Calculator) CreateChainTx(tx *txs.CreateChainTx) error { @@ -98,7 +98,7 @@ func (fc *Calculator) CreateChainTx(tx *txs.CreateChainTx) error { return err } - return fc.ProcessFees(consumedUnits) + return fc.AddFeesFor(consumedUnits) } func (fc *Calculator) CreateSubnetTx(tx *txs.CreateSubnetTx) error { @@ -112,7 +112,7 @@ func (fc *Calculator) CreateSubnetTx(tx *txs.CreateSubnetTx) error { return err } - return fc.ProcessFees(consumedUnits) + return fc.AddFeesFor(consumedUnits) } func (*Calculator) AdvanceTimeTx(*txs.AdvanceTimeTx) error { @@ -134,7 +134,7 @@ func (fc *Calculator) RemoveSubnetValidatorTx(tx *txs.RemoveSubnetValidatorTx) e return err } - return fc.ProcessFees(consumedUnits) + return fc.AddFeesFor(consumedUnits) } func (fc *Calculator) TransformSubnetTx(tx *txs.TransformSubnetTx) error { @@ -148,7 +148,7 @@ func (fc *Calculator) TransformSubnetTx(tx *txs.TransformSubnetTx) error { return err } - return fc.ProcessFees(consumedUnits) + return fc.AddFeesFor(consumedUnits) } func (fc *Calculator) TransferSubnetOwnershipTx(tx *txs.TransferSubnetOwnershipTx) error { @@ -162,7 +162,7 @@ func (fc *Calculator) TransferSubnetOwnershipTx(tx *txs.TransferSubnetOwnershipT return err } - return fc.ProcessFees(consumedUnits) + return fc.AddFeesFor(consumedUnits) } func (fc *Calculator) AddPermissionlessValidatorTx(tx *txs.AddPermissionlessValidatorTx) error { @@ -184,7 +184,7 @@ func (fc *Calculator) AddPermissionlessValidatorTx(tx *txs.AddPermissionlessVali return err } - return fc.ProcessFees(consumedUnits) + return fc.AddFeesFor(consumedUnits) } func (fc *Calculator) AddPermissionlessDelegatorTx(tx *txs.AddPermissionlessDelegatorTx) error { @@ -206,7 +206,7 @@ func (fc *Calculator) AddPermissionlessDelegatorTx(tx *txs.AddPermissionlessDele return err } - return fc.ProcessFees(consumedUnits) + return fc.AddFeesFor(consumedUnits) } func (fc *Calculator) BaseTx(tx *txs.BaseTx) error { @@ -220,7 +220,7 @@ func (fc *Calculator) BaseTx(tx *txs.BaseTx) error { return err } - return fc.ProcessFees(consumedUnits) + return fc.AddFeesFor(consumedUnits) } func (fc *Calculator) ImportTx(tx *txs.ImportTx) error { @@ -238,7 +238,7 @@ func (fc *Calculator) ImportTx(tx *txs.ImportTx) error { return err } - return fc.ProcessFees(consumedUnits) + return fc.AddFeesFor(consumedUnits) } func (fc *Calculator) ExportTx(tx *txs.ExportTx) error { @@ -256,7 +256,7 @@ func (fc *Calculator) ExportTx(tx *txs.ExportTx) error { return err } - return fc.ProcessFees(consumedUnits) + return fc.AddFeesFor(consumedUnits) } func GetInputsDimensions(in *avax.TransferableInput) (fees.Dimensions, error) { @@ -348,7 +348,7 @@ func (fc *Calculator) commonConsumedUnits( return consumedUnits, nil } -func (fc *Calculator) ProcessFees(consumedUnits fees.Dimensions) error { +func (fc *Calculator) AddFeesFor(consumedUnits fees.Dimensions) error { boundBreached, dimension := fc.FeeManager.CumulateUnits(consumedUnits, fc.Config.BlockMaxConsumedUnits(fc.ChainTime)) if boundBreached { return fmt.Errorf("%w: breached dimension %d", errFailedConsumedUnitsCumulation, dimension) @@ -362,3 +362,17 @@ func (fc *Calculator) ProcessFees(consumedUnits fees.Dimensions) error { fc.Fee = fee return nil } + +func (fc *Calculator) RemoveFeesFor(unitsToRm fees.Dimensions) error { + if err := fc.FeeManager.RemoveUnits(unitsToRm); err != nil { + return fmt.Errorf("failed removing units: %w", err) + } + + fee, err := fc.FeeManager.CalculateFee(unitsToRm) + if err != nil { + return fmt.Errorf("%w: %w", errFailedFeeCalculation, err) + } + + fc.Fee -= fee + return nil +} diff --git a/vms/platformvm/utxo/handler.go b/vms/platformvm/utxo/handler.go index 88b4ab9e3ce9..111e3e51c6ca 100644 --- a/vms/platformvm/utxo/handler.go +++ b/vms/platformvm/utxo/handler.go @@ -502,7 +502,7 @@ func (h *handler) FinanceTx( if err != nil { return nil, nil, nil, nil, fmt.Errorf("failed calculating input size: %w", err) } - if err := feeCalc.ProcessFees(insDimensions); err != nil { + if err := feeCalc.AddFeesFor(insDimensions); err != nil { return nil, nil, nil, nil, fmt.Errorf("account for input fees: %w", err) } targetFee += feeCalc.Fee @@ -534,7 +534,7 @@ func (h *handler) FinanceTx( if err != nil { return nil, nil, nil, nil, fmt.Errorf("failed calculating stakedOut size: %w", err) } - if err := feeCalc.ProcessFees(outDimensions); err != nil { + if err := feeCalc.AddFeesFor(outDimensions); err != nil { return nil, nil, nil, nil, fmt.Errorf("account for stakedOut fees: %w", err) } targetFee += feeCalc.Fee @@ -561,7 +561,7 @@ func (h *handler) FinanceTx( if err != nil { return nil, nil, nil, nil, fmt.Errorf("failed calculating changeOut size: %w", err) } - if err := feeCalc.ProcessFees(outDimensions); err != nil { + if err := feeCalc.AddFeesFor(outDimensions); err != nil { return nil, nil, nil, nil, fmt.Errorf("account for stakedOut fees: %w", err) } targetFee += feeCalc.Fee @@ -625,7 +625,7 @@ func (h *handler) FinanceTx( if err != nil { return nil, nil, nil, nil, fmt.Errorf("failed calculating input size: %w", err) } - if err := feeCalc.ProcessFees(insDimensions); err != nil { + if err := feeCalc.AddFeesFor(insDimensions); err != nil { return nil, nil, nil, nil, fmt.Errorf("account for input fees: %w", err) } targetFee += feeCalc.Fee @@ -668,7 +668,7 @@ func (h *handler) FinanceTx( if err != nil { return nil, nil, nil, nil, fmt.Errorf("failed calculating output size: %w", err) } - if err := feeCalc.ProcessFees(outDimensions); err != nil { + if err := feeCalc.AddFeesFor(outDimensions); err != nil { return nil, nil, nil, nil, fmt.Errorf("account for output fees: %w", err) } targetFee += feeCalc.Fee @@ -701,7 +701,7 @@ func (h *handler) FinanceTx( if err != nil { return nil, nil, nil, nil, fmt.Errorf("failed calculating output size: %w", err) } - if err := feeCalc.ProcessFees(outDimensions); err != nil { + if err := feeCalc.AddFeesFor(outDimensions); err != nil { return nil, nil, nil, nil, fmt.Errorf("account for output fees: %w", err) } From a4bdc700aae28e4cfc050c3493fce654a6e5eaed Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Tue, 16 Jan 2024 16:19:14 +0100 Subject: [PATCH 043/190] added UTs --- vms/platformvm/txs/fees/calculator_test.go | 28 ++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/vms/platformvm/txs/fees/calculator_test.go b/vms/platformvm/txs/fees/calculator_test.go index 59ed5a5c4cd2..c8cd85af0e05 100644 --- a/vms/platformvm/txs/fees/calculator_test.go +++ b/vms/platformvm/txs/fees/calculator_test.go @@ -117,6 +117,34 @@ func TestPartiallyFulledTransactionsSizes(t *testing.T) { require.Equal(t, uTxSize, 443) } +func TestAddAndRemoveFees(t *testing.T) { + r := require.New(t) + + cfg := &config.Config{ + FeeConfig: feeTestsDefaultCfg, + } + + fc := &Calculator{ + FeeManager: fees.NewManager(cfg.DefaultUnitFees), + Config: cfg, + } + + units := fees.Dimensions{ + 1, + 2, + 3, + 4, + } + + r.NoError(fc.AddFeesFor(units)) + r.Equal(units, fc.FeeManager.GetCumulatedUnits()) + r.NotZero(fc.Fee) + + r.NoError(fc.RemoveFeesFor(units)) + r.Zero(fc.FeeManager.GetCumulatedUnits()) + r.Zero(fc.Fee) +} + func TestUTXOsAreAdditiveInSize(t *testing.T) { // Show that including utxos of size [S] into a tx of size [T] // result in a tx of size [S+T-CodecVersion] From a1967547f5c25f9ff2c334f6df6a02c0849cf23a Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Tue, 16 Jan 2024 16:34:49 +0100 Subject: [PATCH 044/190] repackaged avm fee calculator --- vms/avm/txs/executor/fee_calculator.go | 169 -------------- vms/avm/txs/executor/syntactic_verifier.go | 66 +++--- vms/avm/txs/fees/calculator.go | 212 ++++++++++++++++++ .../calculator_test.go} | 134 +++++------ 4 files changed, 313 insertions(+), 268 deletions(-) delete mode 100644 vms/avm/txs/executor/fee_calculator.go create mode 100644 vms/avm/txs/fees/calculator.go rename vms/avm/txs/{executor/fee_calculator_test.go => fees/calculator_test.go} (84%) diff --git a/vms/avm/txs/executor/fee_calculator.go b/vms/avm/txs/executor/fee_calculator.go deleted file mode 100644 index 3702be1287a3..000000000000 --- a/vms/avm/txs/executor/fee_calculator.go +++ /dev/null @@ -1,169 +0,0 @@ -// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. -// See the file LICENSE for licensing terms. - -package executor - -import ( - "errors" - "fmt" - "time" - - "github.com/ava-labs/avalanchego/codec" - "github.com/ava-labs/avalanchego/vms/avm/config" - "github.com/ava-labs/avalanchego/vms/avm/txs" - "github.com/ava-labs/avalanchego/vms/components/avax" - "github.com/ava-labs/avalanchego/vms/components/fees" -) - -var ( - _ txs.Visitor = (*FeeCalculator)(nil) - - errFailedFeeCalculation = errors.New("failed fee calculation") - errFailedConsumedUnitsCumulation = errors.New("failed cumulating consumed units") -) - -type FeeCalculator struct { - // setup, to be filled before visitor methods are called - feeManager *fees.Manager - Codec codec.Manager - Config *config.Config - ChainTime time.Time - - // inputs, to be filled before visitor methods are called - Tx *txs.Tx - - // outputs of visitor execution - Fee uint64 -} - -func (fc *FeeCalculator) BaseTx(tx *txs.BaseTx) error { - if !fc.Config.IsEForkActivated(fc.ChainTime) { - fc.Fee = fc.Config.TxFee - return nil - } - - consumedUnits, err := commonConsumedUnits(fc.Codec, fc.Tx, tx.Outs, tx.Ins) - if err != nil { - return err - } - - fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) - return err -} - -func (fc *FeeCalculator) CreateAssetTx(tx *txs.CreateAssetTx) error { - if !fc.Config.IsEForkActivated(fc.ChainTime) { - fc.Fee = fc.Config.CreateAssetTxFee - return nil - } - - consumedUnits, err := commonConsumedUnits(fc.Codec, fc.Tx, tx.Outs, tx.Ins) - if err != nil { - return err - } - - fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) - return err -} - -func (fc *FeeCalculator) OperationTx(tx *txs.OperationTx) error { - if !fc.Config.IsEForkActivated(fc.ChainTime) { - fc.Fee = fc.Config.TxFee - return nil - } - - consumedUnits, err := commonConsumedUnits(fc.Codec, fc.Tx, tx.Outs, tx.Ins) - if err != nil { - return err - } - - fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) - return err -} - -func (fc *FeeCalculator) ImportTx(tx *txs.ImportTx) error { - if !fc.Config.IsEForkActivated(fc.ChainTime) { - fc.Fee = fc.Config.TxFee - return nil - } - - consumedUnits, err := commonConsumedUnits(fc.Codec, fc.Tx, tx.Outs, tx.Ins) - if err != nil { - return err - } - - fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) - return err -} - -func (fc *FeeCalculator) ExportTx(tx *txs.ExportTx) error { - if !fc.Config.IsEForkActivated(fc.ChainTime) { - fc.Fee = fc.Config.TxFee - return nil - } - - consumedUnits, err := commonConsumedUnits(fc.Codec, fc.Tx, tx.Outs, tx.Ins) - if err != nil { - return err - } - - fc.Fee, err = processFees(fc.Config, fc.ChainTime, fc.feeManager, consumedUnits) - return err -} - -func commonConsumedUnits( - codec codec.Manager, - sTx *txs.Tx, - allOuts []*avax.TransferableOutput, - allIns []*avax.TransferableInput, -) (fees.Dimensions, error) { - var consumedUnits fees.Dimensions - consumedUnits[fees.Bandwidth] = uint64(len(sTx.Bytes())) - - // TODO ABENEGIA: consider handling imports/exports differently - var ( - insCost uint64 - insSize uint64 - outsSize uint64 - ) - - for _, in := range allIns { - cost, err := in.In.Cost() - if err != nil { - return consumedUnits, fmt.Errorf("failed retrieving cost of input %s: %w", in.ID, err) - } - insCost += cost - - inSize, err := codec.Size(txs.CodecVersion, in) - if err != nil { - return consumedUnits, fmt.Errorf("failed retrieving size of input %s: %w", in.ID, err) - } - insSize += uint64(inSize) - } - - for _, out := range allOuts { - outSize, err := codec.Size(txs.CodecVersion, out) - if err != nil { - return consumedUnits, fmt.Errorf("failed retrieving size of output %s: %w", out.ID, err) - } - outsSize += uint64(outSize) - } - - consumedUnits[fees.UTXORead] = insCost + insSize // inputs are read - consumedUnits[fees.UTXOWrite] = insSize + outsSize // inputs are deleted, outputs are created - return consumedUnits, nil -} - -func processFees(cfg *config.Config, chainTime time.Time, fc *fees.Manager, consumedUnits fees.Dimensions) (uint64, error) { - boundBreached, dimension := fc.CumulateUnits(consumedUnits, cfg.BlockMaxConsumedUnits(chainTime)) - if boundBreached { - return 0, fmt.Errorf("%w: breached dimension %d", errFailedConsumedUnitsCumulation, dimension) - } - - fee, err := fc.CalculateFee(consumedUnits) - if err != nil { - return 0, fmt.Errorf("%w: %w", errFailedFeeCalculation, err) - } - - return fee, nil -} diff --git a/vms/avm/txs/executor/syntactic_verifier.go b/vms/avm/txs/executor/syntactic_verifier.go index 7543eed8d249..5032b75cb3dd 100644 --- a/vms/avm/txs/executor/syntactic_verifier.go +++ b/vms/avm/txs/executor/syntactic_verifier.go @@ -14,8 +14,10 @@ import ( "github.com/ava-labs/avalanchego/utils" "github.com/ava-labs/avalanchego/utils/set" "github.com/ava-labs/avalanchego/vms/avm/txs" + "github.com/ava-labs/avalanchego/vms/avm/txs/fees" "github.com/ava-labs/avalanchego/vms/components/avax" - "github.com/ava-labs/avalanchego/vms/components/fees" + + commonFees "github.com/ava-labs/avalanchego/vms/components/fees" ) const ( @@ -49,7 +51,7 @@ var ( type SyntacticVerifier struct { *Backend - BlkFeeManager *fees.Manager + BlkFeeManager *commonFees.Manager BlkTimestamp time.Time Tx *txs.Tx } @@ -59,12 +61,12 @@ func (v *SyntacticVerifier) BaseTx(tx *txs.BaseTx) error { return err } - feeCalculator := FeeCalculator{ - feeManager: v.BlkFeeManager, - Codec: v.Codec, - Config: v.Config, - ChainTime: v.BlkTimestamp, - Tx: v.Tx, + feeCalculator := fees.Calculator{ + FeeManager: v.BlkFeeManager, + Codec: v.Codec, + Config: v.Config, + ChainTime: v.BlkTimestamp, + Credentials: v.Tx.Creds, } if err := tx.Visit(&feeCalculator); err != nil { return err @@ -133,12 +135,12 @@ func (v *SyntacticVerifier) CreateAssetTx(tx *txs.CreateAssetTx) error { return err } - feeCalculator := FeeCalculator{ - feeManager: v.BlkFeeManager, - Codec: v.Codec, - Config: v.Config, - ChainTime: v.BlkTimestamp, - Tx: v.Tx, + feeCalculator := fees.Calculator{ + FeeManager: v.BlkFeeManager, + Codec: v.Codec, + Config: v.Config, + ChainTime: v.BlkTimestamp, + Credentials: v.Tx.Creds, } if err := tx.Visit(&feeCalculator); err != nil { return err @@ -192,12 +194,12 @@ func (v *SyntacticVerifier) OperationTx(tx *txs.OperationTx) error { return err } - feeCalculator := FeeCalculator{ - feeManager: v.BlkFeeManager, - Codec: v.Codec, - Config: v.Config, - ChainTime: v.BlkTimestamp, - Tx: v.Tx, + feeCalculator := fees.Calculator{ + FeeManager: v.BlkFeeManager, + Codec: v.Codec, + Config: v.Config, + ChainTime: v.BlkTimestamp, + Credentials: v.Tx.Creds, } if err := tx.Visit(&feeCalculator); err != nil { return err @@ -263,12 +265,12 @@ func (v *SyntacticVerifier) ImportTx(tx *txs.ImportTx) error { return err } - feeCalculator := FeeCalculator{ - feeManager: v.BlkFeeManager, - Codec: v.Codec, - Config: v.Config, - ChainTime: v.BlkTimestamp, - Tx: v.Tx, + feeCalculator := fees.Calculator{ + FeeManager: v.BlkFeeManager, + Codec: v.Codec, + Config: v.Config, + ChainTime: v.BlkTimestamp, + Credentials: v.Tx.Creds, } if err := tx.Visit(&feeCalculator); err != nil { return err @@ -316,12 +318,12 @@ func (v *SyntacticVerifier) ExportTx(tx *txs.ExportTx) error { return err } - feeCalculator := FeeCalculator{ - feeManager: v.BlkFeeManager, - Codec: v.Codec, - Config: v.Config, - ChainTime: v.BlkTimestamp, - Tx: v.Tx, + feeCalculator := fees.Calculator{ + FeeManager: v.BlkFeeManager, + Codec: v.Codec, + Config: v.Config, + ChainTime: v.BlkTimestamp, + Credentials: v.Tx.Creds, } if err := tx.Visit(&feeCalculator); err != nil { return err diff --git a/vms/avm/txs/fees/calculator.go b/vms/avm/txs/fees/calculator.go new file mode 100644 index 000000000000..58d72f780c92 --- /dev/null +++ b/vms/avm/txs/fees/calculator.go @@ -0,0 +1,212 @@ +// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package fees + +import ( + "errors" + "fmt" + "time" + + "github.com/ava-labs/avalanchego/codec" + "github.com/ava-labs/avalanchego/vms/avm/config" + "github.com/ava-labs/avalanchego/vms/avm/fxs" + "github.com/ava-labs/avalanchego/vms/avm/txs" + "github.com/ava-labs/avalanchego/vms/components/avax" + "github.com/ava-labs/avalanchego/vms/components/fees" +) + +var ( + _ txs.Visitor = (*Calculator)(nil) + + errFailedFeeCalculation = errors.New("failed fee calculation") + errFailedConsumedUnitsCumulation = errors.New("failed cumulating consumed units") +) + +type Calculator struct { + // setup, to be filled before visitor methods are called + FeeManager *fees.Manager + Codec codec.Manager + Config *config.Config + ChainTime time.Time + + // inputs, to be filled before visitor methods are called + Credentials []*fxs.FxCredential + + // outputs of visitor execution + Fee uint64 +} + +func (fc *Calculator) BaseTx(tx *txs.BaseTx) error { + if !fc.Config.IsEForkActivated(fc.ChainTime) { + fc.Fee = fc.Config.TxFee + return nil + } + + consumedUnits, err := fc.commonConsumedUnits(tx, tx.Outs, tx.Ins) + if err != nil { + return err + } + + return fc.AddFeesFor(consumedUnits) +} + +func (fc *Calculator) CreateAssetTx(tx *txs.CreateAssetTx) error { + if !fc.Config.IsEForkActivated(fc.ChainTime) { + fc.Fee = fc.Config.CreateAssetTxFee + return nil + } + + consumedUnits, err := fc.commonConsumedUnits(tx, tx.Outs, tx.Ins) + if err != nil { + return err + } + + return fc.AddFeesFor(consumedUnits) +} + +func (fc *Calculator) OperationTx(tx *txs.OperationTx) error { + if !fc.Config.IsEForkActivated(fc.ChainTime) { + fc.Fee = fc.Config.TxFee + return nil + } + + consumedUnits, err := fc.commonConsumedUnits(tx, tx.Outs, tx.Ins) + if err != nil { + return err + } + + return fc.AddFeesFor(consumedUnits) +} + +func (fc *Calculator) ImportTx(tx *txs.ImportTx) error { + if !fc.Config.IsEForkActivated(fc.ChainTime) { + fc.Fee = fc.Config.TxFee + return nil + } + + ins := make([]*avax.TransferableInput, len(tx.Ins)+len(tx.ImportedIns)) + copy(ins, tx.Ins) + copy(ins[len(tx.Ins):], tx.ImportedIns) + + consumedUnits, err := fc.commonConsumedUnits(tx, tx.Outs, ins) + if err != nil { + return err + } + + return fc.AddFeesFor(consumedUnits) +} + +func (fc *Calculator) ExportTx(tx *txs.ExportTx) error { + if !fc.Config.IsEForkActivated(fc.ChainTime) { + fc.Fee = fc.Config.TxFee + return nil + } + + outs := make([]*avax.TransferableOutput, len(tx.Outs)+len(tx.ExportedOuts)) + copy(outs, tx.Outs) + copy(outs[len(tx.Outs):], tx.ExportedOuts) + + consumedUnits, err := fc.commonConsumedUnits(tx, outs, tx.Ins) + if err != nil { + return err + } + + return fc.AddFeesFor(consumedUnits) +} + +func getInputsDimensions(evaluteBandwitdh bool, c codec.Manager, ins []*avax.TransferableInput) (fees.Dimensions, error) { + var consumedUnits fees.Dimensions + + for _, in := range ins { + cost, err := in.In.Cost() + if err != nil { + return consumedUnits, fmt.Errorf("failed retrieving cost of input %s: %w", in.ID, err) + } + + inSize, err := c.Size(txs.CodecVersion, in) + if err != nil { + return consumedUnits, fmt.Errorf("failed retrieving size of input %s: %w", in.ID, err) + } + uInSize := uint64(inSize) + + if evaluteBandwitdh { + consumedUnits[fees.Bandwidth] += uInSize - codec.CodecVersionSize + } + consumedUnits[fees.UTXORead] += cost + uInSize // inputs are read + consumedUnits[fees.UTXOWrite] += uInSize // inputs are deleted + } + return consumedUnits, nil +} + +func getOutputsDimensions(evaluteBandwitdh bool, c codec.Manager, outs []*avax.TransferableOutput) (fees.Dimensions, error) { + var consumedUnits fees.Dimensions + + for _, out := range outs { + outSize, err := c.Size(txs.CodecVersion, out) + if err != nil { + return consumedUnits, fmt.Errorf("failed retrieving size of output %s: %w", out.ID, err) + } + uOutSize := uint64(outSize) + + if evaluteBandwitdh { + consumedUnits[fees.Bandwidth] += uOutSize - codec.CodecVersionSize + } + consumedUnits[fees.UTXOWrite] += uOutSize + } + + return consumedUnits, nil +} + +func (fc *Calculator) commonConsumedUnits( + uTx txs.UnsignedTx, + allOuts []*avax.TransferableOutput, + allIns []*avax.TransferableInput, +) (fees.Dimensions, error) { + var consumedUnits fees.Dimensions + + uTxSize, err := fc.Codec.Size(txs.CodecVersion, uTx) + if err != nil { + return consumedUnits, fmt.Errorf("couldn't calculate UnsignedTx marshal length: %w", err) + } + credsSize, err := fc.Codec.Size(txs.CodecVersion, fc.Credentials) + if err != nil { + return consumedUnits, fmt.Errorf("failed retrieving size of credentials: %w", err) + } + consumedUnits[fees.Bandwidth] = uint64(uTxSize + credsSize) + + inputDimensions, err := getInputsDimensions(false, fc.Codec, allIns) + if err != nil { + return consumedUnits, fmt.Errorf("failed retrieving size of inputs: %w", err) + } + consumedUnits, err = fees.Add(consumedUnits, inputDimensions) + if err != nil { + return consumedUnits, fmt.Errorf("failed adding inputs: %w", err) + } + + outputDimensions, err := getOutputsDimensions(false, fc.Codec, allOuts) + if err != nil { + return consumedUnits, fmt.Errorf("failed retrieving size of outputs: %w", err) + } + consumedUnits, err = fees.Add(consumedUnits, outputDimensions) + if err != nil { + return consumedUnits, fmt.Errorf("failed adding outputs: %w", err) + } + + return consumedUnits, nil +} + +func (fc *Calculator) AddFeesFor(consumedUnits fees.Dimensions) error { + boundBreached, dimension := fc.FeeManager.CumulateUnits(consumedUnits, fc.Config.BlockMaxConsumedUnits(fc.ChainTime)) + if boundBreached { + return fmt.Errorf("%w: breached dimension %d", errFailedConsumedUnitsCumulation, dimension) + } + + fee, err := fc.FeeManager.CalculateFee(consumedUnits) + if err != nil { + return fmt.Errorf("%w: %w", errFailedFeeCalculation, err) + } + + fc.Fee = fee + return nil +} diff --git a/vms/avm/txs/executor/fee_calculator_test.go b/vms/avm/txs/fees/calculator_test.go similarity index 84% rename from vms/avm/txs/executor/fee_calculator_test.go rename to vms/avm/txs/fees/calculator_test.go index 1a7cc6ccec91..dab958369cc9 100644 --- a/vms/avm/txs/executor/fee_calculator_test.go +++ b/vms/avm/txs/fees/calculator_test.go @@ -1,7 +1,7 @@ // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. // See the file LICENSE for licensing terms. -package executor +package fees import ( "reflect" @@ -57,7 +57,7 @@ type feeTests struct { description string cfgAndChainTimeF func() (*config.Config, time.Time) expectedError error - checksF func(*testing.T, *FeeCalculator) + checksF func(*testing.T, *Calculator) } func TestBaseTxFees(t *testing.T) { @@ -88,7 +88,7 @@ func TestBaseTxFees(t *testing.T) { return &cfg, chainTime }, expectedError: nil, - checksF: func(t *testing.T, fc *FeeCalculator) { + checksF: func(t *testing.T, fc *Calculator) { require.Equal(t, fc.Config.TxFee, fc.Fee) }, }, @@ -105,16 +105,16 @@ func TestBaseTxFees(t *testing.T) { return &cfg, chainTime }, expectedError: nil, - checksF: func(t *testing.T, fc *FeeCalculator) { - require.Equal(t, 2922*units.MicroAvax, fc.Fee) + checksF: func(t *testing.T, fc *Calculator) { + require.Equal(t, 2920*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ - uint64(len(sTx.Bytes())), + 224, 1090, 172, 0, }, - fc.feeManager.GetCumulatedUnits(), + fc.FeeManager.GetCumulatedUnits(), ) }, }, @@ -132,7 +132,7 @@ func TestBaseTxFees(t *testing.T) { return &cfg, chainTime }, expectedError: errFailedConsumedUnitsCumulation, - checksF: func(t *testing.T, fc *FeeCalculator) {}, + checksF: func(t *testing.T, fc *Calculator) {}, }, } @@ -140,12 +140,12 @@ func TestBaseTxFees(t *testing.T) { t.Run(tt.description, func(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() - fc := &FeeCalculator{ - feeManager: fees.NewManager(cfg.DefaultUnitFees), - Codec: codec, - Config: cfg, - ChainTime: chainTime, - Tx: sTx, + fc := &Calculator{ + FeeManager: fees.NewManager(cfg.DefaultUnitFees), + Codec: codec, + Config: cfg, + ChainTime: chainTime, + Credentials: sTx.Creds, } err := uTx.Visit(fc) r.ErrorIs(err, tt.expectedError) @@ -174,7 +174,7 @@ func TestCreateAssetTxFees(t *testing.T) { &secp256k1fx.MintOutput{ OutputOwners: secp256k1fx.OutputOwners{ Threshold: 1, - Addrs: []ids.ShortID{keys[0].PublicKey().Address()}, + Addrs: []ids.ShortID{feeTestKeys[0].PublicKey().Address()}, }, }, }, @@ -200,7 +200,7 @@ func TestCreateAssetTxFees(t *testing.T) { return &cfg, chainTime }, expectedError: nil, - checksF: func(t *testing.T, fc *FeeCalculator) { + checksF: func(t *testing.T, fc *Calculator) { require.Equal(t, fc.Config.CreateAssetTxFee, fc.Fee) }, }, @@ -217,16 +217,16 @@ func TestCreateAssetTxFees(t *testing.T) { return &cfg, chainTime }, expectedError: nil, - checksF: func(t *testing.T, fc *FeeCalculator) { - require.Equal(t, 2987*units.MicroAvax, fc.Fee) + checksF: func(t *testing.T, fc *Calculator) { + require.Equal(t, 2985*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ - uint64(len(sTx.Bytes())), + 289, 1090, 172, 0, }, - fc.feeManager.GetCumulatedUnits(), + fc.FeeManager.GetCumulatedUnits(), ) }, }, @@ -239,12 +239,12 @@ func TestCreateAssetTxFees(t *testing.T) { cfg := feeTestsDefaultCfg cfg.DurangoTime = durangoTime cfg.EForkTime = eForkTime - cfg.DefaultBlockMaxConsumedUnits[0] = uint64(len(sTx.Bytes())) - 1 + cfg.DefaultBlockMaxConsumedUnits[0] = 289 - 1 return &cfg, chainTime }, expectedError: errFailedConsumedUnitsCumulation, - checksF: func(t *testing.T, fc *FeeCalculator) {}, + checksF: func(t *testing.T, fc *Calculator) {}, }, } @@ -252,12 +252,12 @@ func TestCreateAssetTxFees(t *testing.T) { t.Run(tt.description, func(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() - fc := &FeeCalculator{ - feeManager: fees.NewManager(cfg.DefaultUnitFees), - Codec: codec, - Config: cfg, - ChainTime: chainTime, - Tx: sTx, + fc := &Calculator{ + FeeManager: fees.NewManager(cfg.DefaultUnitFees), + Codec: codec, + Config: cfg, + ChainTime: chainTime, + Credentials: sTx.Creds, } err := uTx.Visit(fc) r.ErrorIs(err, tt.expectedError) @@ -312,7 +312,7 @@ func TestOperationTxFees(t *testing.T) { return &cfg, chainTime }, expectedError: nil, - checksF: func(t *testing.T, fc *FeeCalculator) { + checksF: func(t *testing.T, fc *Calculator) { require.Equal(t, fc.Config.TxFee, fc.Fee) }, }, @@ -329,16 +329,16 @@ func TestOperationTxFees(t *testing.T) { return &cfg, chainTime }, expectedError: nil, - checksF: func(t *testing.T, fc *FeeCalculator) { - require.Equal(t, 3043*units.MicroAvax, fc.Fee) + checksF: func(t *testing.T, fc *Calculator) { + require.Equal(t, 3041*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ - uint64(len(sTx.Bytes())), + 345, 1090, 172, 0, }, - fc.feeManager.GetCumulatedUnits(), + fc.FeeManager.GetCumulatedUnits(), ) }, }, @@ -356,7 +356,7 @@ func TestOperationTxFees(t *testing.T) { return &cfg, chainTime }, expectedError: errFailedConsumedUnitsCumulation, - checksF: func(t *testing.T, fc *FeeCalculator) {}, + checksF: func(t *testing.T, fc *Calculator) {}, }, } @@ -364,12 +364,12 @@ func TestOperationTxFees(t *testing.T) { t.Run(tt.description, func(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() - fc := &FeeCalculator{ - feeManager: fees.NewManager(cfg.DefaultUnitFees), - Codec: codec, - Config: cfg, - ChainTime: chainTime, - Tx: sTx, + fc := &Calculator{ + FeeManager: fees.NewManager(cfg.DefaultUnitFees), + Codec: codec, + Config: cfg, + ChainTime: chainTime, + Credentials: sTx.Creds, } err := uTx.Visit(fc) r.ErrorIs(err, tt.expectedError) @@ -420,7 +420,7 @@ func TestImportTxFees(t *testing.T) { return &cfg, chainTime }, expectedError: nil, - checksF: func(t *testing.T, fc *FeeCalculator) { + checksF: func(t *testing.T, fc *Calculator) { require.Equal(t, fc.Config.TxFee, fc.Fee) }, }, @@ -437,16 +437,16 @@ func TestImportTxFees(t *testing.T) { return &cfg, chainTime }, expectedError: nil, - checksF: func(t *testing.T, fc *FeeCalculator) { - require.Equal(t, 3046*units.MicroAvax, fc.Fee) + checksF: func(t *testing.T, fc *Calculator) { + require.Equal(t, 5494*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ - uint64(len(sTx.Bytes())), - 1090, - 172, + 348, + 2180, + 262, 0, }, - fc.feeManager.GetCumulatedUnits(), + fc.FeeManager.GetCumulatedUnits(), ) }, }, @@ -464,7 +464,7 @@ func TestImportTxFees(t *testing.T) { return &cfg, chainTime }, expectedError: errFailedConsumedUnitsCumulation, - checksF: func(t *testing.T, fc *FeeCalculator) {}, + checksF: func(t *testing.T, fc *Calculator) {}, }, } @@ -472,12 +472,12 @@ func TestImportTxFees(t *testing.T) { t.Run(tt.description, func(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() - fc := &FeeCalculator{ - feeManager: fees.NewManager(cfg.DefaultUnitFees), - Codec: codec, - Config: cfg, - ChainTime: chainTime, - Tx: sTx, + fc := &Calculator{ + FeeManager: fees.NewManager(cfg.DefaultUnitFees), + Codec: codec, + Config: cfg, + ChainTime: chainTime, + Credentials: sTx.Creds, } err := uTx.Visit(fc) r.ErrorIs(err, tt.expectedError) @@ -518,7 +518,7 @@ func TestExportTxFees(t *testing.T) { return &cfg, chainTime }, expectedError: nil, - checksF: func(t *testing.T, fc *FeeCalculator) { + checksF: func(t *testing.T, fc *Calculator) { require.Equal(t, fc.Config.TxFee, fc.Fee) }, }, @@ -535,16 +535,16 @@ func TestExportTxFees(t *testing.T) { return &cfg, chainTime }, expectedError: nil, - checksF: func(t *testing.T, fc *FeeCalculator) { - require.Equal(t, 3038*units.MicroAvax, fc.Fee) + checksF: func(t *testing.T, fc *Calculator) { + require.Equal(t, 3282*units.MicroAvax, fc.Fee) require.Equal(t, fees.Dimensions{ - uint64(len(sTx.Bytes())), + 340, 1090, - 172, + 254, 0, }, - fc.feeManager.GetCumulatedUnits(), + fc.FeeManager.GetCumulatedUnits(), ) }, }, @@ -562,7 +562,7 @@ func TestExportTxFees(t *testing.T) { return &cfg, chainTime }, expectedError: errFailedConsumedUnitsCumulation, - checksF: func(t *testing.T, fc *FeeCalculator) {}, + checksF: func(t *testing.T, fc *Calculator) {}, }, } @@ -570,12 +570,12 @@ func TestExportTxFees(t *testing.T) { t.Run(tt.description, func(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() - fc := &FeeCalculator{ - feeManager: fees.NewManager(cfg.DefaultUnitFees), - Codec: codec, - Config: cfg, - ChainTime: chainTime, - Tx: sTx, + fc := &Calculator{ + FeeManager: fees.NewManager(cfg.DefaultUnitFees), + Codec: codec, + Config: cfg, + ChainTime: chainTime, + Credentials: sTx.Creds, } err := uTx.Visit(fc) r.ErrorIs(err, tt.expectedError) From 85bff3de467a8bdc6ee8d76dbfb81217e6f984ab Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Wed, 17 Jan 2024 11:45:27 +0100 Subject: [PATCH 045/190] removed some code duplication --- vms/avm/txs/fees/calculator.go | 49 ++-------------------- vms/components/fees/helpers.go | 47 ++++++++++++++++++++++ vms/platformvm/txs/builder/builder.go | 2 +- vms/platformvm/txs/fees/calculator.go | 58 ++------------------------- vms/platformvm/utxo/handler.go | 14 ++++--- 5 files changed, 64 insertions(+), 106 deletions(-) create mode 100644 vms/components/fees/helpers.go diff --git a/vms/avm/txs/fees/calculator.go b/vms/avm/txs/fees/calculator.go index 58d72f780c92..989ef5429e41 100644 --- a/vms/avm/txs/fees/calculator.go +++ b/vms/avm/txs/fees/calculator.go @@ -115,49 +115,6 @@ func (fc *Calculator) ExportTx(tx *txs.ExportTx) error { return fc.AddFeesFor(consumedUnits) } -func getInputsDimensions(evaluteBandwitdh bool, c codec.Manager, ins []*avax.TransferableInput) (fees.Dimensions, error) { - var consumedUnits fees.Dimensions - - for _, in := range ins { - cost, err := in.In.Cost() - if err != nil { - return consumedUnits, fmt.Errorf("failed retrieving cost of input %s: %w", in.ID, err) - } - - inSize, err := c.Size(txs.CodecVersion, in) - if err != nil { - return consumedUnits, fmt.Errorf("failed retrieving size of input %s: %w", in.ID, err) - } - uInSize := uint64(inSize) - - if evaluteBandwitdh { - consumedUnits[fees.Bandwidth] += uInSize - codec.CodecVersionSize - } - consumedUnits[fees.UTXORead] += cost + uInSize // inputs are read - consumedUnits[fees.UTXOWrite] += uInSize // inputs are deleted - } - return consumedUnits, nil -} - -func getOutputsDimensions(evaluteBandwitdh bool, c codec.Manager, outs []*avax.TransferableOutput) (fees.Dimensions, error) { - var consumedUnits fees.Dimensions - - for _, out := range outs { - outSize, err := c.Size(txs.CodecVersion, out) - if err != nil { - return consumedUnits, fmt.Errorf("failed retrieving size of output %s: %w", out.ID, err) - } - uOutSize := uint64(outSize) - - if evaluteBandwitdh { - consumedUnits[fees.Bandwidth] += uOutSize - codec.CodecVersionSize - } - consumedUnits[fees.UTXOWrite] += uOutSize - } - - return consumedUnits, nil -} - func (fc *Calculator) commonConsumedUnits( uTx txs.UnsignedTx, allOuts []*avax.TransferableOutput, @@ -175,19 +132,21 @@ func (fc *Calculator) commonConsumedUnits( } consumedUnits[fees.Bandwidth] = uint64(uTxSize + credsSize) - inputDimensions, err := getInputsDimensions(false, fc.Codec, allIns) + inputDimensions, err := fees.GetInputsDimensions(fc.Codec, txs.CodecVersion, allIns) if err != nil { return consumedUnits, fmt.Errorf("failed retrieving size of inputs: %w", err) } + inputDimensions[fees.Bandwidth] = 0 // inputs bandwidth is already accounted for above, so we zero it consumedUnits, err = fees.Add(consumedUnits, inputDimensions) if err != nil { return consumedUnits, fmt.Errorf("failed adding inputs: %w", err) } - outputDimensions, err := getOutputsDimensions(false, fc.Codec, allOuts) + outputDimensions, err := fees.GetOutputsDimensions(fc.Codec, txs.CodecVersion, allOuts) if err != nil { return consumedUnits, fmt.Errorf("failed retrieving size of outputs: %w", err) } + outputDimensions[fees.Bandwidth] = 0 // outputs bandwidth is already accounted for above, so we zero it consumedUnits, err = fees.Add(consumedUnits, outputDimensions) if err != nil { return consumedUnits, fmt.Errorf("failed adding outputs: %w", err) diff --git a/vms/components/fees/helpers.go b/vms/components/fees/helpers.go new file mode 100644 index 000000000000..3fe2d427706d --- /dev/null +++ b/vms/components/fees/helpers.go @@ -0,0 +1,47 @@ +// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package fees + +import ( + "fmt" + + "github.com/ava-labs/avalanchego/codec" + "github.com/ava-labs/avalanchego/vms/components/avax" +) + +func GetInputsDimensions(c codec.Manager, v uint16, ins []*avax.TransferableInput) (Dimensions, error) { + var consumedUnits Dimensions + for _, in := range ins { + cost, err := in.In.Cost() + if err != nil { + return consumedUnits, fmt.Errorf("failed retrieving cost of input %s: %w", in.ID, err) + } + + inSize, err := c.Size(v, in) + if err != nil { + return consumedUnits, fmt.Errorf("failed retrieving size of input %s: %w", in.ID, err) + } + uInSize := uint64(inSize) + + consumedUnits[Bandwidth] += uInSize - codec.CodecVersionSize + consumedUnits[UTXORead] += cost + uInSize // inputs are read + consumedUnits[UTXOWrite] += uInSize // inputs are deleted + } + return consumedUnits, nil +} + +func GetOutputsDimensions(c codec.Manager, v uint16, outs []*avax.TransferableOutput) (Dimensions, error) { + var consumedUnits Dimensions + for _, out := range outs { + outSize, err := c.Size(v, out) + if err != nil { + return consumedUnits, fmt.Errorf("failed retrieving size of output %s: %w", out.ID, err) + } + uOutSize := uint64(outSize) + + consumedUnits[Bandwidth] += uOutSize - codec.CodecVersionSize + consumedUnits[UTXOWrite] += uOutSize + } + return consumedUnits, nil +} diff --git a/vms/platformvm/txs/builder/builder.go b/vms/platformvm/txs/builder/builder.go index d4edff49b72a..127dc58aeb4a 100644 --- a/vms/platformvm/txs/builder/builder.go +++ b/vms/platformvm/txs/builder/builder.go @@ -348,7 +348,7 @@ func (b *builder) NewImportTx( } // update fees to target given the extra input added - outDimensions, err := fees.GetOutputsDimensions(changeOut) + outDimensions, err := commonfees.GetOutputsDimensions(txs.Codec, txs.CodecVersion, []*avax.TransferableOutput{changeOut}) if err != nil { return nil, fmt.Errorf("failed calculating output size: %w", err) } diff --git a/vms/platformvm/txs/fees/calculator.go b/vms/platformvm/txs/fees/calculator.go index 55036d216818..2173ed397ffa 100644 --- a/vms/platformvm/txs/fees/calculator.go +++ b/vms/platformvm/txs/fees/calculator.go @@ -8,7 +8,6 @@ import ( "fmt" "time" - "github.com/ava-labs/avalanchego/codec" "github.com/ava-labs/avalanchego/utils/constants" "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/components/fees" @@ -259,57 +258,6 @@ func (fc *Calculator) ExportTx(tx *txs.ExportTx) error { return fc.AddFeesFor(consumedUnits) } -func GetInputsDimensions(in *avax.TransferableInput) (fees.Dimensions, error) { - return getInputsDimensions(true, []*avax.TransferableInput{in}) -} - -func getInputsDimensions(evaluteBandwitdh bool, ins []*avax.TransferableInput) (fees.Dimensions, error) { - var consumedUnits fees.Dimensions - - for _, in := range ins { - cost, err := in.In.Cost() - if err != nil { - return consumedUnits, fmt.Errorf("failed retrieving cost of input %s: %w", in.ID, err) - } - - inSize, err := txs.Codec.Size(txs.CodecVersion, in) - if err != nil { - return consumedUnits, fmt.Errorf("failed retrieving size of input %s: %w", in.ID, err) - } - uInSize := uint64(inSize) - - if evaluteBandwitdh { - consumedUnits[fees.Bandwidth] += uInSize - codec.CodecVersionSize - } - consumedUnits[fees.UTXORead] += cost + uInSize // inputs are read - consumedUnits[fees.UTXOWrite] += uInSize // inputs are deleted - } - return consumedUnits, nil -} - -func GetOutputsDimensions(out *avax.TransferableOutput) (fees.Dimensions, error) { - return getOutputsDimensions(true, []*avax.TransferableOutput{out}) -} - -func getOutputsDimensions(evaluteBandwitdh bool, outs []*avax.TransferableOutput) (fees.Dimensions, error) { - var consumedUnits fees.Dimensions - - for _, out := range outs { - outSize, err := txs.Codec.Size(txs.CodecVersion, out) - if err != nil { - return consumedUnits, fmt.Errorf("failed retrieving size of output %s: %w", out.ID, err) - } - uOutSize := uint64(outSize) - - if evaluteBandwitdh { - consumedUnits[fees.Bandwidth] += uOutSize - codec.CodecVersionSize - } - consumedUnits[fees.UTXOWrite] += uOutSize - } - - return consumedUnits, nil -} - func (fc *Calculator) commonConsumedUnits( uTx txs.UnsignedTx, allOuts []*avax.TransferableOutput, @@ -327,19 +275,21 @@ func (fc *Calculator) commonConsumedUnits( } consumedUnits[fees.Bandwidth] = uint64(uTxSize + credsSize) - inputDimensions, err := getInputsDimensions(false, allIns) + inputDimensions, err := fees.GetInputsDimensions(txs.Codec, txs.CodecVersion, allIns) if err != nil { return consumedUnits, fmt.Errorf("failed retrieving size of inputs: %w", err) } + inputDimensions[fees.Bandwidth] = 0 // inputs bandwidth is already accounted for above, so we zero it consumedUnits, err = fees.Add(consumedUnits, inputDimensions) if err != nil { return consumedUnits, fmt.Errorf("failed adding inputs: %w", err) } - outputDimensions, err := getOutputsDimensions(false, allOuts) + outputDimensions, err := fees.GetOutputsDimensions(txs.Codec, txs.CodecVersion, allOuts) if err != nil { return consumedUnits, fmt.Errorf("failed retrieving size of outputs: %w", err) } + outputDimensions[fees.Bandwidth] = 0 // outputs bandwidth is already accounted for above, so we zero it consumedUnits, err = fees.Add(consumedUnits, outputDimensions) if err != nil { return consumedUnits, fmt.Errorf("failed adding outputs: %w", err) diff --git a/vms/platformvm/utxo/handler.go b/vms/platformvm/utxo/handler.go index 111e3e51c6ca..b35c025d66b0 100644 --- a/vms/platformvm/utxo/handler.go +++ b/vms/platformvm/utxo/handler.go @@ -24,6 +24,8 @@ import ( "github.com/ava-labs/avalanchego/vms/platformvm/txs" "github.com/ava-labs/avalanchego/vms/platformvm/txs/fees" "github.com/ava-labs/avalanchego/vms/secp256k1fx" + + commonfees "github.com/ava-labs/avalanchego/vms/components/fees" ) var ( @@ -498,7 +500,7 @@ func (h *handler) FinanceTx( remainingValue := in.Amount() // update fees to target given the extra input added - insDimensions, err := fees.GetInputsDimensions(input) + insDimensions, err := commonfees.GetInputsDimensions(txs.Codec, txs.CodecVersion, []*avax.TransferableInput{input}) if err != nil { return nil, nil, nil, nil, fmt.Errorf("failed calculating input size: %w", err) } @@ -530,7 +532,7 @@ func (h *handler) FinanceTx( } // update fees to target given the staked output added - outDimensions, err := fees.GetOutputsDimensions(stakedOut) + outDimensions, err := commonfees.GetOutputsDimensions(txs.Codec, txs.CodecVersion, []*avax.TransferableOutput{stakedOut}) if err != nil { return nil, nil, nil, nil, fmt.Errorf("failed calculating stakedOut size: %w", err) } @@ -557,7 +559,7 @@ func (h *handler) FinanceTx( } // update fees to target given the change output added - outDimensions, err := fees.GetOutputsDimensions(changeOut) + outDimensions, err := commonfees.GetOutputsDimensions(txs.Codec, txs.CodecVersion, []*avax.TransferableOutput{changeOut}) if err != nil { return nil, nil, nil, nil, fmt.Errorf("failed calculating changeOut size: %w", err) } @@ -621,7 +623,7 @@ func (h *handler) FinanceTx( remainingValue := in.Amount() // update fees to target given the extra input added - insDimensions, err := fees.GetInputsDimensions(input) + insDimensions, err := commonfees.GetInputsDimensions(txs.Codec, txs.CodecVersion, []*avax.TransferableInput{input}) if err != nil { return nil, nil, nil, nil, fmt.Errorf("failed calculating input size: %w", err) } @@ -664,7 +666,7 @@ func (h *handler) FinanceTx( } // update fees to target given the extra input added - outDimensions, err := fees.GetOutputsDimensions(stakedOut) + outDimensions, err := commonfees.GetOutputsDimensions(txs.Codec, txs.CodecVersion, []*avax.TransferableOutput{stakedOut}) if err != nil { return nil, nil, nil, nil, fmt.Errorf("failed calculating output size: %w", err) } @@ -697,7 +699,7 @@ func (h *handler) FinanceTx( } // update fees to target given the extra input added - outDimensions, err := fees.GetOutputsDimensions(changeOut) + outDimensions, err := commonfees.GetOutputsDimensions(txs.Codec, txs.CodecVersion, []*avax.TransferableOutput{changeOut}) if err != nil { return nil, nil, nil, nil, fmt.Errorf("failed calculating output size: %w", err) } From 0d5b6189d2c12206b216323e9edcd854342ef9de Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Wed, 17 Jan 2024 13:14:48 +0100 Subject: [PATCH 046/190] added p-chain fees calculator --- .../txs/executor/staker_tx_verification.go | 80 ++++++-- .../txs/executor/standard_tx_executor.go | 56 +++++- .../txs/executor/standard_tx_executor_test.go | 190 ++++++++++-------- vms/platformvm/txs/fees/calculator.go | 161 +++++++++++++++ 4 files changed, 381 insertions(+), 106 deletions(-) create mode 100644 vms/platformvm/txs/fees/calculator.go diff --git a/vms/platformvm/txs/executor/staker_tx_verification.go b/vms/platformvm/txs/executor/staker_tx_verification.go index a17bbbffc14d..bd83f5482a29 100644 --- a/vms/platformvm/txs/executor/staker_tx_verification.go +++ b/vms/platformvm/txs/executor/staker_tx_verification.go @@ -15,6 +15,7 @@ import ( "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/platformvm/state" "github.com/ava-labs/avalanchego/vms/platformvm/txs" + "github.com/ava-labs/avalanchego/vms/platformvm/txs/fees" safemath "github.com/ava-labs/avalanchego/utils/math" ) @@ -160,6 +161,14 @@ func verifyAddValidatorTx( } // Verify the flowcheck + feeCalculator := fees.Calculator{ + Config: backend.Config, + ChainTime: currentTimestamp, + } + if err := tx.Visit(&feeCalculator); err != nil { + return nil, err + } + if err := backend.FlowChecker.VerifySpend( tx, chainState, @@ -167,7 +176,7 @@ func verifyAddValidatorTx( outs, sTx.Creds, map[ids.ID]uint64{ - backend.Ctx.AVAXAssetID: backend.Config.AddPrimaryNetworkValidatorFee, + backend.Ctx.AVAXAssetID: feeCalculator.Fee, }, ); err != nil { return nil, fmt.Errorf("%w: %w", ErrFlowCheckFailed, err) @@ -246,6 +255,14 @@ func verifyAddSubnetValidatorTx( } // Verify the flowcheck + feeCalculator := fees.Calculator{ + Config: backend.Config, + ChainTime: currentTimestamp, + } + if err := tx.Visit(&feeCalculator); err != nil { + return err + } + if err := backend.FlowChecker.VerifySpend( tx, chainState, @@ -253,7 +270,7 @@ func verifyAddSubnetValidatorTx( tx.Outs, baseTxCreds, map[ids.ID]uint64{ - backend.Ctx.AVAXAssetID: backend.Config.AddSubnetValidatorFee, + backend.Ctx.AVAXAssetID: feeCalculator.Fee, }, ); err != nil { return fmt.Errorf("%w: %w", ErrFlowCheckFailed, err) @@ -315,6 +332,14 @@ func verifyRemoveSubnetValidatorTx( } // Verify the flowcheck + feeCalculator := fees.Calculator{ + Config: backend.Config, + ChainTime: chainState.GetTimestamp(), + } + if err := tx.Visit(&feeCalculator); err != nil { + return nil, false, err + } + if err := backend.FlowChecker.VerifySpend( tx, chainState, @@ -322,7 +347,7 @@ func verifyRemoveSubnetValidatorTx( tx.Outs, baseTxCreds, map[ids.ID]uint64{ - backend.Ctx.AVAXAssetID: backend.Config.TxFee, + backend.Ctx.AVAXAssetID: feeCalculator.Fee, }, ); err != nil { return nil, false, fmt.Errorf("%w: %w", ErrFlowCheckFailed, err) @@ -427,6 +452,14 @@ func verifyAddDelegatorTx( } // Verify the flowcheck + feeCalculator := fees.Calculator{ + Config: backend.Config, + ChainTime: chainState.GetTimestamp(), + } + if err := tx.Visit(&feeCalculator); err != nil { + return nil, err + } + if err := backend.FlowChecker.VerifySpend( tx, chainState, @@ -434,7 +467,7 @@ func verifyAddDelegatorTx( outs, sTx.Creds, map[ids.ID]uint64{ - backend.Ctx.AVAXAssetID: backend.Config.AddPrimaryNetworkDelegatorFee, + backend.Ctx.AVAXAssetID: feeCalculator.Fee, }, ); err != nil { return nil, fmt.Errorf("%w: %w", ErrFlowCheckFailed, err) @@ -531,15 +564,10 @@ func verifyAddPermissionlessValidatorTx( ) } - var txFee uint64 if tx.Subnet != constants.PrimaryNetworkID { if err := verifySubnetValidatorPrimaryNetworkRequirements(isDurangoActive, chainState, tx.Validator); err != nil { return err } - - txFee = backend.Config.AddSubnetValidatorFee - } else { - txFee = backend.Config.AddPrimaryNetworkValidatorFee } outs := make([]*avax.TransferableOutput, len(tx.Outs)+len(tx.StakeOuts)) @@ -547,6 +575,14 @@ func verifyAddPermissionlessValidatorTx( copy(outs[len(tx.Outs):], tx.StakeOuts) // Verify the flowcheck + feeCalculator := fees.Calculator{ + Config: backend.Config, + ChainTime: currentTimestamp, + } + if err := tx.Visit(&feeCalculator); err != nil { + return err + } + if err := backend.FlowChecker.VerifySpend( tx, chainState, @@ -554,7 +590,7 @@ func verifyAddPermissionlessValidatorTx( outs, sTx.Creds, map[ids.ID]uint64{ - backend.Ctx.AVAXAssetID: txFee, + backend.Ctx.AVAXAssetID: feeCalculator.Fee, }, ); err != nil { return fmt.Errorf("%w: %w", ErrFlowCheckFailed, err) @@ -672,7 +708,6 @@ func verifyAddPermissionlessDelegatorTx( copy(outs, tx.Outs) copy(outs[len(tx.Outs):], tx.StakeOuts) - var txFee uint64 if tx.Subnet != constants.PrimaryNetworkID { // Invariant: Delegators must only be able to reference validator // transactions that implement [txs.ValidatorTx]. All @@ -683,10 +718,15 @@ func verifyAddPermissionlessDelegatorTx( if validator.Priority.IsPermissionedValidator() { return ErrDelegateToPermissionedValidator } + } - txFee = backend.Config.AddSubnetDelegatorFee - } else { - txFee = backend.Config.AddPrimaryNetworkDelegatorFee + // Verify the flowcheck + feeCalculator := fees.Calculator{ + Config: backend.Config, + ChainTime: currentTimestamp, + } + if err := tx.Visit(&feeCalculator); err != nil { + return err } // Verify the flowcheck @@ -697,7 +737,7 @@ func verifyAddPermissionlessDelegatorTx( outs, sTx.Creds, map[ids.ID]uint64{ - backend.Ctx.AVAXAssetID: txFee, + backend.Ctx.AVAXAssetID: feeCalculator.Fee, }, ); err != nil { return fmt.Errorf("%w: %w", ErrFlowCheckFailed, err) @@ -739,6 +779,14 @@ func verifyTransferSubnetOwnershipTx( } // Verify the flowcheck + feeCalculator := fees.Calculator{ + Config: backend.Config, + ChainTime: chainState.GetTimestamp(), + } + if err := tx.Visit(&feeCalculator); err != nil { + return err + } + if err := backend.FlowChecker.VerifySpend( tx, chainState, @@ -746,7 +794,7 @@ func verifyTransferSubnetOwnershipTx( tx.Outs, baseTxCreds, map[ids.ID]uint64{ - backend.Ctx.AVAXAssetID: backend.Config.TxFee, + backend.Ctx.AVAXAssetID: feeCalculator.Fee, }, ); err != nil { return fmt.Errorf("%w: %w", ErrFlowCheckFailed, err) diff --git a/vms/platformvm/txs/executor/standard_tx_executor.go b/vms/platformvm/txs/executor/standard_tx_executor.go index e780673e6431..0298f0cddd62 100644 --- a/vms/platformvm/txs/executor/standard_tx_executor.go +++ b/vms/platformvm/txs/executor/standard_tx_executor.go @@ -19,6 +19,7 @@ import ( "github.com/ava-labs/avalanchego/vms/components/verify" "github.com/ava-labs/avalanchego/vms/platformvm/state" "github.com/ava-labs/avalanchego/vms/platformvm/txs" + "github.com/ava-labs/avalanchego/vms/platformvm/txs/fees" ) var ( @@ -60,8 +61,14 @@ func (e *StandardTxExecutor) CreateChainTx(tx *txs.CreateChainTx) error { } // Verify the flowcheck - timestamp := e.State.GetTimestamp() - createBlockchainTxFee := e.Config.GetCreateBlockchainTxFee(timestamp) + feeCalculator := fees.Calculator{ + Config: e.Backend.Config, + ChainTime: e.State.GetTimestamp(), + } + if err := tx.Visit(&feeCalculator); err != nil { + return err + } + if err := e.FlowChecker.VerifySpend( tx, e.State, @@ -69,7 +76,7 @@ func (e *StandardTxExecutor) CreateChainTx(tx *txs.CreateChainTx) error { tx.Outs, baseTxCreds, map[ids.ID]uint64{ - e.Ctx.AVAXAssetID: createBlockchainTxFee, + e.Ctx.AVAXAssetID: feeCalculator.Fee, }, ); err != nil { return err @@ -99,8 +106,14 @@ func (e *StandardTxExecutor) CreateSubnetTx(tx *txs.CreateSubnetTx) error { } // Verify the flowcheck - timestamp := e.State.GetTimestamp() - createSubnetTxFee := e.Config.GetCreateSubnetTxFee(timestamp) + feeCalculator := fees.Calculator{ + Config: e.Backend.Config, + ChainTime: e.State.GetTimestamp(), + } + if err := tx.Visit(&feeCalculator); err != nil { + return err + } + if err := e.FlowChecker.VerifySpend( tx, e.State, @@ -108,7 +121,7 @@ func (e *StandardTxExecutor) CreateSubnetTx(tx *txs.CreateSubnetTx) error { tx.Outs, e.Tx.Creds, map[ids.ID]uint64{ - e.Ctx.AVAXAssetID: createSubnetTxFee, + e.Ctx.AVAXAssetID: feeCalculator.Fee, }, ); err != nil { return err @@ -172,6 +185,15 @@ func (e *StandardTxExecutor) ImportTx(tx *txs.ImportTx) error { copy(ins, tx.Ins) copy(ins[len(tx.Ins):], tx.ImportedInputs) + // Verify the flowcheck + feeCalculator := fees.Calculator{ + Config: e.Backend.Config, + ChainTime: e.State.GetTimestamp(), + } + if err := tx.Visit(&feeCalculator); err != nil { + return err + } + if err := e.FlowChecker.VerifySpendUTXOs( tx, utxos, @@ -179,7 +201,7 @@ func (e *StandardTxExecutor) ImportTx(tx *txs.ImportTx) error { tx.Outs, e.Tx.Creds, map[ids.ID]uint64{ - e.Ctx.AVAXAssetID: e.Config.TxFee, + e.Ctx.AVAXAssetID: feeCalculator.Fee, }, ); err != nil { return err @@ -220,6 +242,14 @@ func (e *StandardTxExecutor) ExportTx(tx *txs.ExportTx) error { } // Verify the flowcheck + feeCalculator := fees.Calculator{ + Config: e.Backend.Config, + ChainTime: e.State.GetTimestamp(), + } + if err := tx.Visit(&feeCalculator); err != nil { + return err + } + if err := e.FlowChecker.VerifySpend( tx, e.State, @@ -227,7 +257,7 @@ func (e *StandardTxExecutor) ExportTx(tx *txs.ExportTx) error { outs, e.Tx.Creds, map[ids.ID]uint64{ - e.Ctx.AVAXAssetID: e.Config.TxFee, + e.Ctx.AVAXAssetID: feeCalculator.Fee, }, ); err != nil { return fmt.Errorf("failed verifySpend: %w", err) @@ -513,6 +543,14 @@ func (e *StandardTxExecutor) BaseTx(tx *txs.BaseTx) error { } // Verify the flowcheck + feeCalculator := fees.Calculator{ + Config: e.Backend.Config, + ChainTime: e.State.GetTimestamp(), + } + if err := tx.Visit(&feeCalculator); err != nil { + return err + } + if err := e.FlowChecker.VerifySpend( tx, e.State, @@ -520,7 +558,7 @@ func (e *StandardTxExecutor) BaseTx(tx *txs.BaseTx) error { tx.Outs, e.Tx.Creds, map[ids.ID]uint64{ - e.Ctx.AVAXAssetID: e.Config.TxFee, + e.Ctx.AVAXAssetID: feeCalculator.Fee, }, ); err != nil { return err diff --git a/vms/platformvm/txs/executor/standard_tx_executor_test.go b/vms/platformvm/txs/executor/standard_tx_executor_test.go index de0e3eebecc2..d5a6f8cffa66 100644 --- a/vms/platformvm/txs/executor/standard_tx_executor_test.go +++ b/vms/platformvm/txs/executor/standard_tx_executor_test.go @@ -1136,6 +1136,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { // Set dependency expectations. env.state.EXPECT().GetCurrentValidator(env.unsignedTx.Subnet, env.unsignedTx.NodeID).Return(env.staker, nil).Times(1) + env.state.EXPECT().GetTimestamp().Return(time.Now()) subnetOwner := fx.NewMockOwner(ctrl) env.state.EXPECT().GetSubnetOwner(env.unsignedTx.Subnet).Return(subnetOwner, nil).Times(1) env.fx.EXPECT().VerifyPermission(env.unsignedTx, env.unsignedTx.SubnetAuth, env.tx.Creds[len(env.tx.Creds)-1], subnetOwner).Return(nil).Times(1) @@ -1145,14 +1146,16 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { env.state.EXPECT().DeleteCurrentValidator(env.staker) env.state.EXPECT().DeleteUTXO(gomock.Any()).Times(len(env.unsignedTx.Ins)) env.state.EXPECT().AddUTXO(gomock.Any()).Times(len(env.unsignedTx.Outs)) + + cfg := &config.Config{ + BanffTime: env.latestForkTime, + CortinaTime: env.latestForkTime, + DurangoTime: env.latestForkTime, + EForkTime: mockable.MaxTime, + } e := &StandardTxExecutor{ Backend: &Backend{ - Config: &config.Config{ - BanffTime: env.latestForkTime, - CortinaTime: env.latestForkTime, - DurangoTime: env.latestForkTime, - EForkTime: mockable.MaxTime, - }, + Config: cfg, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, @@ -1173,14 +1176,16 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { // Setting the subnet ID to the Primary Network ID makes the tx fail syntactic verification env.tx.Unsigned.(*txs.RemoveSubnetValidatorTx).Subnet = constants.PrimaryNetworkID env.state = state.NewMockDiff(ctrl) + + cfg := &config.Config{ + BanffTime: env.latestForkTime, + CortinaTime: env.latestForkTime, + DurangoTime: env.latestForkTime, + EForkTime: mockable.MaxTime, + } e := &StandardTxExecutor{ Backend: &Backend{ - Config: &config.Config{ - BanffTime: env.latestForkTime, - CortinaTime: env.latestForkTime, - DurangoTime: env.latestForkTime, - EForkTime: mockable.MaxTime, - }, + Config: cfg, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, @@ -1201,14 +1206,16 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { env.state = state.NewMockDiff(ctrl) env.state.EXPECT().GetCurrentValidator(env.unsignedTx.Subnet, env.unsignedTx.NodeID).Return(nil, database.ErrNotFound) env.state.EXPECT().GetPendingValidator(env.unsignedTx.Subnet, env.unsignedTx.NodeID).Return(nil, database.ErrNotFound) + + cfg := &config.Config{ + BanffTime: env.latestForkTime, + CortinaTime: env.latestForkTime, + DurangoTime: env.latestForkTime, + EForkTime: mockable.MaxTime, + } e := &StandardTxExecutor{ Backend: &Backend{ - Config: &config.Config{ - BanffTime: env.latestForkTime, - CortinaTime: env.latestForkTime, - DurangoTime: env.latestForkTime, - EForkTime: mockable.MaxTime, - }, + Config: cfg, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, @@ -1232,14 +1239,16 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { // Set dependency expectations. env.state.EXPECT().GetCurrentValidator(env.unsignedTx.Subnet, env.unsignedTx.NodeID).Return(&staker, nil).Times(1) + + cfg := &config.Config{ + BanffTime: env.latestForkTime, + CortinaTime: env.latestForkTime, + DurangoTime: env.latestForkTime, + EForkTime: mockable.MaxTime, + } e := &StandardTxExecutor{ Backend: &Backend{ - Config: &config.Config{ - BanffTime: env.latestForkTime, - CortinaTime: env.latestForkTime, - DurangoTime: env.latestForkTime, - EForkTime: mockable.MaxTime, - }, + Config: cfg, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, @@ -1261,14 +1270,16 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { env.tx.Creds = nil env.state = state.NewMockDiff(ctrl) env.state.EXPECT().GetCurrentValidator(env.unsignedTx.Subnet, env.unsignedTx.NodeID).Return(env.staker, nil) + + cfg := &config.Config{ + BanffTime: env.latestForkTime, + CortinaTime: env.latestForkTime, + DurangoTime: env.latestForkTime, + EForkTime: mockable.MaxTime, + } e := &StandardTxExecutor{ Backend: &Backend{ - Config: &config.Config{ - BanffTime: env.latestForkTime, - CortinaTime: env.latestForkTime, - DurangoTime: env.latestForkTime, - EForkTime: mockable.MaxTime, - }, + Config: cfg, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, @@ -1289,14 +1300,16 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { env.state = state.NewMockDiff(ctrl) env.state.EXPECT().GetCurrentValidator(env.unsignedTx.Subnet, env.unsignedTx.NodeID).Return(env.staker, nil) env.state.EXPECT().GetSubnetOwner(env.unsignedTx.Subnet).Return(nil, database.ErrNotFound) + + cfg := &config.Config{ + BanffTime: env.latestForkTime, + CortinaTime: env.latestForkTime, + DurangoTime: env.latestForkTime, + EForkTime: mockable.MaxTime, + } e := &StandardTxExecutor{ Backend: &Backend{ - Config: &config.Config{ - BanffTime: env.latestForkTime, - CortinaTime: env.latestForkTime, - DurangoTime: env.latestForkTime, - EForkTime: mockable.MaxTime, - }, + Config: cfg, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, @@ -1319,14 +1332,16 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { subnetOwner := fx.NewMockOwner(ctrl) env.state.EXPECT().GetSubnetOwner(env.unsignedTx.Subnet).Return(subnetOwner, nil) env.fx.EXPECT().VerifyPermission(gomock.Any(), env.unsignedTx.SubnetAuth, env.tx.Creds[len(env.tx.Creds)-1], subnetOwner).Return(errTest) + + cfg := &config.Config{ + BanffTime: env.latestForkTime, + CortinaTime: env.latestForkTime, + DurangoTime: env.latestForkTime, + EForkTime: mockable.MaxTime, + } e := &StandardTxExecutor{ Backend: &Backend{ - Config: &config.Config{ - BanffTime: env.latestForkTime, - CortinaTime: env.latestForkTime, - DurangoTime: env.latestForkTime, - EForkTime: mockable.MaxTime, - }, + Config: cfg, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, @@ -1345,6 +1360,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { newExecutor: func(ctrl *gomock.Controller) (*txs.RemoveSubnetValidatorTx, *StandardTxExecutor) { env := newValidRemoveSubnetValidatorTxVerifyEnv(t, ctrl) env.state = state.NewMockDiff(ctrl) + env.state.EXPECT().GetTimestamp().Return(time.Now()) env.state.EXPECT().GetCurrentValidator(env.unsignedTx.Subnet, env.unsignedTx.NodeID).Return(env.staker, nil) subnetOwner := fx.NewMockOwner(ctrl) env.state.EXPECT().GetSubnetOwner(env.unsignedTx.Subnet).Return(subnetOwner, nil) @@ -1352,14 +1368,16 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { env.flowChecker.EXPECT().VerifySpend( gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), ).Return(errTest) + + cfg := &config.Config{ + BanffTime: env.latestForkTime, + CortinaTime: env.latestForkTime, + DurangoTime: env.latestForkTime, + EForkTime: mockable.MaxTime, + } e := &StandardTxExecutor{ Backend: &Backend{ - Config: &config.Config{ - BanffTime: env.latestForkTime, - CortinaTime: env.latestForkTime, - DurangoTime: env.latestForkTime, - EForkTime: mockable.MaxTime, - }, + Config: cfg, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, @@ -1510,14 +1528,16 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { // Setting the tx to nil makes the tx fail syntactic verification env.tx.Unsigned = (*txs.TransformSubnetTx)(nil) env.state = state.NewMockDiff(ctrl) + + cfg := &config.Config{ + BanffTime: env.latestForkTime, + CortinaTime: env.latestForkTime, + DurangoTime: env.latestForkTime, + EForkTime: mockable.MaxTime, + } e := &StandardTxExecutor{ Backend: &Backend{ - Config: &config.Config{ - BanffTime: env.latestForkTime, - CortinaTime: env.latestForkTime, - DurangoTime: env.latestForkTime, - EForkTime: mockable.MaxTime, - }, + Config: cfg, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, @@ -1537,14 +1557,16 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { env := newValidTransformSubnetTxVerifyEnv(t, ctrl) env.unsignedTx.MaxStakeDuration = math.MaxUint32 env.state = state.NewMockDiff(ctrl) + + cfg := &config.Config{ + BanffTime: env.latestForkTime, + CortinaTime: env.latestForkTime, + DurangoTime: env.latestForkTime, + EForkTime: mockable.MaxTime, + } e := &StandardTxExecutor{ Backend: &Backend{ - Config: &config.Config{ - BanffTime: env.latestForkTime, - CortinaTime: env.latestForkTime, - DurangoTime: env.latestForkTime, - EForkTime: mockable.MaxTime, - }, + Config: cfg, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, @@ -1565,15 +1587,17 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { // Remove credentials env.tx.Creds = nil env.state = state.NewMockDiff(ctrl) + + cfg := &config.Config{ + BanffTime: env.latestForkTime, + CortinaTime: env.latestForkTime, + DurangoTime: env.latestForkTime, + EForkTime: mockable.MaxTime, + MaxStakeDuration: math.MaxInt64, + } e := &StandardTxExecutor{ Backend: &Backend{ - Config: &config.Config{ - BanffTime: env.latestForkTime, - CortinaTime: env.latestForkTime, - DurangoTime: env.latestForkTime, - MaxStakeDuration: math.MaxInt64, - EForkTime: mockable.MaxTime, - }, + Config: cfg, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, @@ -1599,15 +1623,17 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { env.flowChecker.EXPECT().VerifySpend( gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), ).Return(ErrFlowCheckFailed) + + cfg := &config.Config{ + BanffTime: env.latestForkTime, + CortinaTime: env.latestForkTime, + DurangoTime: env.latestForkTime, + EForkTime: mockable.MaxTime, + MaxStakeDuration: math.MaxInt64, + } e := &StandardTxExecutor{ Backend: &Backend{ - Config: &config.Config{ - BanffTime: env.latestForkTime, - CortinaTime: env.latestForkTime, - DurangoTime: env.latestForkTime, - EForkTime: mockable.MaxTime, - MaxStakeDuration: math.MaxInt64, - }, + Config: cfg, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, @@ -1638,15 +1664,17 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { env.state.EXPECT().SetCurrentSupply(env.unsignedTx.Subnet, env.unsignedTx.InitialSupply) env.state.EXPECT().DeleteUTXO(gomock.Any()).Times(len(env.unsignedTx.Ins)) env.state.EXPECT().AddUTXO(gomock.Any()).Times(len(env.unsignedTx.Outs)) + + cfg := &config.Config{ + BanffTime: env.latestForkTime, + CortinaTime: env.latestForkTime, + DurangoTime: env.latestForkTime, + EForkTime: mockable.MaxTime, + MaxStakeDuration: math.MaxInt64, + } e := &StandardTxExecutor{ Backend: &Backend{ - Config: &config.Config{ - BanffTime: env.latestForkTime, - CortinaTime: env.latestForkTime, - DurangoTime: env.latestForkTime, - EForkTime: mockable.MaxTime, - MaxStakeDuration: math.MaxInt64, - }, + Config: cfg, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, diff --git a/vms/platformvm/txs/fees/calculator.go b/vms/platformvm/txs/fees/calculator.go new file mode 100644 index 000000000000..5ee928102cb0 --- /dev/null +++ b/vms/platformvm/txs/fees/calculator.go @@ -0,0 +1,161 @@ +// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package fees + +import ( + "errors" + "time" + + "github.com/ava-labs/avalanchego/utils/constants" + "github.com/ava-labs/avalanchego/vms/platformvm/config" + "github.com/ava-labs/avalanchego/vms/platformvm/txs" +) + +var ( + _ txs.Visitor = (*Calculator)(nil) + + errEForkFeesNotDefinedYet = errors.New("fees in E fork not defined yet") +) + +type Calculator struct { + // setup, to be filled before visitor methods are called + Config *config.Config + ChainTime time.Time + + // outputs of visitor execution + Fee uint64 +} + +func (fc *Calculator) AddValidatorTx(*txs.AddValidatorTx) error { + if !fc.Config.IsEForkActivated(fc.ChainTime) { + fc.Fee = fc.Config.AddPrimaryNetworkValidatorFee + return nil + } + + return errEForkFeesNotDefinedYet +} + +func (fc *Calculator) AddSubnetValidatorTx(*txs.AddSubnetValidatorTx) error { + if !fc.Config.IsEForkActivated(fc.ChainTime) { + fc.Fee = fc.Config.AddSubnetValidatorFee + return nil + } + + return errEForkFeesNotDefinedYet +} + +func (fc *Calculator) AddDelegatorTx(*txs.AddDelegatorTx) error { + if !fc.Config.IsEForkActivated(fc.ChainTime) { + fc.Fee = fc.Config.AddPrimaryNetworkDelegatorFee + return nil + } + + return errEForkFeesNotDefinedYet +} + +func (fc *Calculator) CreateChainTx(*txs.CreateChainTx) error { + if !fc.Config.IsEForkActivated(fc.ChainTime) { + fc.Fee = fc.Config.GetCreateBlockchainTxFee(fc.ChainTime) + return nil + } + + return errEForkFeesNotDefinedYet +} + +func (fc *Calculator) CreateSubnetTx(*txs.CreateSubnetTx) error { + if !fc.Config.IsEForkActivated(fc.ChainTime) { + fc.Fee = fc.Config.GetCreateSubnetTxFee(fc.ChainTime) + return nil + } + + return errEForkFeesNotDefinedYet +} + +func (*Calculator) AdvanceTimeTx(*txs.AdvanceTimeTx) error { + return nil // no fees +} + +func (*Calculator) RewardValidatorTx(*txs.RewardValidatorTx) error { + return nil // no fees +} + +func (fc *Calculator) RemoveSubnetValidatorTx(*txs.RemoveSubnetValidatorTx) error { + if !fc.Config.IsEForkActivated(fc.ChainTime) { + fc.Fee = fc.Config.TxFee + return nil + } + + return errEForkFeesNotDefinedYet +} + +func (fc *Calculator) TransformSubnetTx(*txs.TransformSubnetTx) error { + if !fc.Config.IsEForkActivated(fc.ChainTime) { + fc.Fee = fc.Config.TransformSubnetTxFee + return nil + } + + return errEForkFeesNotDefinedYet +} + +func (fc *Calculator) TransferSubnetOwnershipTx(*txs.TransferSubnetOwnershipTx) error { + if !fc.Config.IsEForkActivated(fc.ChainTime) { + fc.Fee = fc.Config.TxFee + return nil + } + + return errEForkFeesNotDefinedYet +} + +func (fc *Calculator) AddPermissionlessValidatorTx(tx *txs.AddPermissionlessValidatorTx) error { + if !fc.Config.IsEForkActivated(fc.ChainTime) { + if tx.Subnet != constants.PrimaryNetworkID { + fc.Fee = fc.Config.AddSubnetValidatorFee + } else { + fc.Fee = fc.Config.AddPrimaryNetworkValidatorFee + } + return nil + } + + return errEForkFeesNotDefinedYet +} + +func (fc *Calculator) AddPermissionlessDelegatorTx(tx *txs.AddPermissionlessDelegatorTx) error { + if !fc.Config.IsEForkActivated(fc.ChainTime) { + if tx.Subnet != constants.PrimaryNetworkID { + fc.Fee = fc.Config.AddSubnetDelegatorFee + } else { + fc.Fee = fc.Config.AddPrimaryNetworkDelegatorFee + } + return nil + } + + return errEForkFeesNotDefinedYet +} + +func (fc *Calculator) BaseTx(*txs.BaseTx) error { + if !fc.Config.IsEForkActivated(fc.ChainTime) { + fc.Fee = fc.Config.TxFee + return nil + } + + return errEForkFeesNotDefinedYet +} + +func (fc *Calculator) ImportTx(*txs.ImportTx) error { + if !fc.Config.IsEForkActivated(fc.ChainTime) { + fc.Fee = fc.Config.TxFee + return nil + } + + return errEForkFeesNotDefinedYet +} + +func (fc *Calculator) ExportTx(*txs.ExportTx) error { + if !fc.Config.IsEForkActivated(fc.ChainTime) { + fc.Fee = fc.Config.TxFee + return nil + } + + return errEForkFeesNotDefinedYet +} From 8623d08c47e73e18aebeffd9beac87b48babcb12 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Wed, 17 Jan 2024 13:52:45 +0100 Subject: [PATCH 047/190] added x-chain fees calculator --- vms/avm/block/executor/block.go | 5 +- vms/avm/block/executor/manager.go | 5 +- vms/avm/block/executor/manager_test.go | 11 ++-- vms/avm/txs/executor/syntactic_verifier.go | 55 +++++++++++++++-- vms/avm/txs/fees/calculator.go | 72 ++++++++++++++++++++++ vms/avm/vm.go | 5 +- 6 files changed, 137 insertions(+), 16 deletions(-) create mode 100644 vms/avm/txs/fees/calculator.go diff --git a/vms/avm/block/executor/block.go b/vms/avm/block/executor/block.go index 8663f27ba123..e49f1f482f8d 100644 --- a/vms/avm/block/executor/block.go +++ b/vms/avm/block/executor/block.go @@ -77,8 +77,9 @@ func (b *Block) Verify(context.Context) error { // before performing any possible DB reads. for _, tx := range txs { err := tx.Unsigned.Visit(&executor.SyntacticVerifier{ - Backend: b.manager.backend, - Tx: tx, + Backend: b.manager.backend, + BlkTimestamp: newChainTime, + Tx: tx, }) if err != nil { txID := tx.ID() diff --git a/vms/avm/block/executor/manager.go b/vms/avm/block/executor/manager.go index 9822743b7fd3..a2a981c5185d 100644 --- a/vms/avm/block/executor/manager.go +++ b/vms/avm/block/executor/manager.go @@ -148,8 +148,9 @@ func (m *manager) VerifyTx(tx *txs.Tx) error { } err := tx.Unsigned.Visit(&executor.SyntacticVerifier{ - Backend: m.backend, - Tx: tx, + Backend: m.backend, + BlkTimestamp: m.state.GetTimestamp(), + Tx: tx, }) if err != nil { return err diff --git a/vms/avm/block/executor/manager_test.go b/vms/avm/block/executor/manager_test.go index 89b547eed967..de09f434d904 100644 --- a/vms/avm/block/executor/manager_test.go +++ b/vms/avm/block/executor/manager_test.go @@ -145,7 +145,9 @@ func TestManagerVerifyTx(t *testing.T) { Unsigned: unsigned, } }, - managerF: func(*gomock.Controller) *manager { + managerF: func(ctrl *gomock.Controller) *manager { + state := state.NewMockState(ctrl) + state.EXPECT().GetTimestamp().Return(time.Time{}) return &manager{ backend: &executor.Backend{ Bootstrapped: true, @@ -154,6 +156,7 @@ func TestManagerVerifyTx(t *testing.T) { EForkTime: mockable.MaxTime, }, }, + state: state, } }, expectedErr: errTestSyntacticVerifyFail, @@ -176,7 +179,7 @@ func TestManagerVerifyTx(t *testing.T) { // These values don't matter for this test state := state.NewMockState(ctrl) state.EXPECT().GetLastAccepted().Return(lastAcceptedID) - state.EXPECT().GetTimestamp().Return(time.Time{}) + state.EXPECT().GetTimestamp().Return(time.Time{}).Times(2) return &manager{ backend: &executor.Backend{ @@ -212,7 +215,7 @@ func TestManagerVerifyTx(t *testing.T) { // These values don't matter for this test state := state.NewMockState(ctrl) state.EXPECT().GetLastAccepted().Return(lastAcceptedID) - state.EXPECT().GetTimestamp().Return(time.Time{}) + state.EXPECT().GetTimestamp().Return(time.Time{}).Times(2) return &manager{ backend: &executor.Backend{ @@ -248,7 +251,7 @@ func TestManagerVerifyTx(t *testing.T) { // These values don't matter for this test state := state.NewMockState(ctrl) state.EXPECT().GetLastAccepted().Return(lastAcceptedID) - state.EXPECT().GetTimestamp().Return(time.Time{}) + state.EXPECT().GetTimestamp().Return(time.Time{}).Times(2) return &manager{ backend: &executor.Backend{ diff --git a/vms/avm/txs/executor/syntactic_verifier.go b/vms/avm/txs/executor/syntactic_verifier.go index 81a2f2a715f4..2bb1fc6c5aa0 100644 --- a/vms/avm/txs/executor/syntactic_verifier.go +++ b/vms/avm/txs/executor/syntactic_verifier.go @@ -7,12 +7,14 @@ import ( "errors" "fmt" "strings" + "time" "unicode" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils" "github.com/ava-labs/avalanchego/utils/set" "github.com/ava-labs/avalanchego/vms/avm/txs" + "github.com/ava-labs/avalanchego/vms/avm/txs/fees" "github.com/ava-labs/avalanchego/vms/components/avax" ) @@ -47,7 +49,8 @@ var ( type SyntacticVerifier struct { *Backend - Tx *txs.Tx + BlkTimestamp time.Time + Tx *txs.Tx } func (v *SyntacticVerifier) BaseTx(tx *txs.BaseTx) error { @@ -55,8 +58,16 @@ func (v *SyntacticVerifier) BaseTx(tx *txs.BaseTx) error { return err } + feeCalculator := fees.Calculator{ + Config: v.Config, + ChainTime: v.BlkTimestamp, + } + if err := tx.Visit(&feeCalculator); err != nil { + return err + } + err := avax.VerifyTx( - v.Config.TxFee, + feeCalculator.Fee, v.FeeAssetID, [][]*avax.TransferableInput{tx.Ins}, [][]*avax.TransferableOutput{tx.Outs}, @@ -118,8 +129,16 @@ func (v *SyntacticVerifier) CreateAssetTx(tx *txs.CreateAssetTx) error { return err } + feeCalculator := fees.Calculator{ + Config: v.Config, + ChainTime: v.BlkTimestamp, + } + if err := tx.Visit(&feeCalculator); err != nil { + return err + } + err := avax.VerifyTx( - v.Config.CreateAssetTxFee, + feeCalculator.Fee, v.FeeAssetID, [][]*avax.TransferableInput{tx.Ins}, [][]*avax.TransferableOutput{tx.Outs}, @@ -166,8 +185,16 @@ func (v *SyntacticVerifier) OperationTx(tx *txs.OperationTx) error { return err } + feeCalculator := fees.Calculator{ + Config: v.Config, + ChainTime: v.BlkTimestamp, + } + if err := tx.Visit(&feeCalculator); err != nil { + return err + } + err := avax.VerifyTx( - v.Config.TxFee, + feeCalculator.Fee, v.FeeAssetID, [][]*avax.TransferableInput{tx.Ins}, [][]*avax.TransferableOutput{tx.Outs}, @@ -226,8 +253,16 @@ func (v *SyntacticVerifier) ImportTx(tx *txs.ImportTx) error { return err } + feeCalculator := fees.Calculator{ + Config: v.Config, + ChainTime: v.BlkTimestamp, + } + if err := tx.Visit(&feeCalculator); err != nil { + return err + } + err := avax.VerifyTx( - v.Config.TxFee, + feeCalculator.Fee, v.FeeAssetID, [][]*avax.TransferableInput{ tx.Ins, @@ -268,8 +303,16 @@ func (v *SyntacticVerifier) ExportTx(tx *txs.ExportTx) error { return err } + feeCalculator := fees.Calculator{ + Config: v.Config, + ChainTime: v.BlkTimestamp, + } + if err := tx.Visit(&feeCalculator); err != nil { + return err + } + err := avax.VerifyTx( - v.Config.TxFee, + feeCalculator.Fee, v.FeeAssetID, [][]*avax.TransferableInput{tx.Ins}, [][]*avax.TransferableOutput{ diff --git a/vms/avm/txs/fees/calculator.go b/vms/avm/txs/fees/calculator.go new file mode 100644 index 000000000000..dad73ae3607b --- /dev/null +++ b/vms/avm/txs/fees/calculator.go @@ -0,0 +1,72 @@ +// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package fees + +import ( + "errors" + "time" + + "github.com/ava-labs/avalanchego/vms/avm/config" + "github.com/ava-labs/avalanchego/vms/avm/txs" +) + +var ( + _ txs.Visitor = (*Calculator)(nil) + + errEForkFeesNotDefinedYet = errors.New("fees in E fork not defined yet") +) + +type Calculator struct { + // setup, to be filled before visitor methods are called + Config *config.Config + ChainTime time.Time + + // outputs of visitor execution + Fee uint64 +} + +func (fc *Calculator) BaseTx(*txs.BaseTx) error { + if !fc.Config.IsEForkActivated(fc.ChainTime) { + fc.Fee = fc.Config.TxFee + return nil + } + + return errEForkFeesNotDefinedYet +} + +func (fc *Calculator) CreateAssetTx(*txs.CreateAssetTx) error { + if !fc.Config.IsEForkActivated(fc.ChainTime) { + fc.Fee = fc.Config.CreateAssetTxFee + return nil + } + + return errEForkFeesNotDefinedYet +} + +func (fc *Calculator) OperationTx(*txs.OperationTx) error { + if !fc.Config.IsEForkActivated(fc.ChainTime) { + fc.Fee = fc.Config.TxFee + return nil + } + + return errEForkFeesNotDefinedYet +} + +func (fc *Calculator) ImportTx(*txs.ImportTx) error { + if !fc.Config.IsEForkActivated(fc.ChainTime) { + fc.Fee = fc.Config.TxFee + return nil + } + + return errEForkFeesNotDefinedYet +} + +func (fc *Calculator) ExportTx(*txs.ExportTx) error { + if !fc.Config.IsEForkActivated(fc.ChainTime) { + fc.Fee = fc.Config.TxFee + return nil + } + + return errEForkFeesNotDefinedYet +} diff --git a/vms/avm/vm.go b/vms/avm/vm.go index 59907c934e91..e739a352a48f 100644 --- a/vms/avm/vm.go +++ b/vms/avm/vm.go @@ -501,8 +501,9 @@ func (vm *VM) ParseTx(_ context.Context, bytes []byte) (snowstorm.Tx, error) { } err = tx.Unsigned.Visit(&txexecutor.SyntacticVerifier{ - Backend: vm.txBackend, - Tx: tx, + Backend: vm.txBackend, + BlkTimestamp: vm.state.GetTimestamp(), + Tx: tx, }) if err != nil { return nil, err From ed2875c3024fec034b5faf156bd2f75e84ba3af0 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Wed, 17 Jan 2024 16:39:17 +0100 Subject: [PATCH 048/190] extended codec size --- codec/manager.go | 4 +++- codec/reflectcodec/type_codec.go | 16 +++++++--------- codec/test_codec.go | 26 ++++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 10 deletions(-) diff --git a/codec/manager.go b/codec/manager.go index 6fb48aaad9f8..2afc011aa3fe 100644 --- a/codec/manager.go +++ b/codec/manager.go @@ -13,6 +13,8 @@ import ( ) const ( + CodecVersionSize = wrappers.ShortLen + // default max size, in bytes, of something being marshalled by Marshal() defaultMaxSize = 256 * units.KiB @@ -103,7 +105,7 @@ func (m *manager) Size(version uint16, value interface{}) (int, error) { res, err := c.Size(value) // Add [wrappers.ShortLen] for the codec version - return wrappers.ShortLen + res, err + return CodecVersionSize + res, err } // To marshal an interface, [value] must be a pointer to the interface. diff --git a/codec/reflectcodec/type_codec.go b/codec/reflectcodec/type_codec.go index 312927559280..1b0d8dd78b7c 100644 --- a/codec/reflectcodec/type_codec.go +++ b/codec/reflectcodec/type_codec.go @@ -27,8 +27,6 @@ const ( var ( _ codec.Codec = (*genericCodec)(nil) - errMarshalNil = errors.New("can't marshal nil pointer or interface") - errUnmarshalNil = errors.New("can't unmarshal nil") errNeedPointer = errors.New("argument to unmarshal must be a pointer") errRecursiveInterfaceTypes = errors.New("recursive interface types") ) @@ -90,7 +88,7 @@ func New(typer TypeCodec, tagNames []string, durangoTime time.Time, maxSliceLen func (c *genericCodec) Size(value interface{}) (int, error) { if value == nil { - return 0, errMarshalNil // can't marshal nil + return 0, nil // can't marshal nil } size, _, err := c.size(reflect.ValueOf(value), nil /*=typeStack*/) @@ -126,14 +124,14 @@ func (c *genericCodec) size( return wrappers.StringLen(value.String()), false, nil case reflect.Ptr: if value.IsNil() { - return 0, false, errMarshalNil + return 0, true, nil } return c.size(value.Elem(), typeStack) case reflect.Interface: if value.IsNil() { - return 0, false, errMarshalNil + return 0, true, nil } underlyingValue := value.Interface() @@ -292,7 +290,7 @@ func (c *genericCodec) size( // To marshal an interface, [value] must be a pointer to the interface func (c *genericCodec) MarshalInto(value interface{}, p *wrappers.Packer) error { if value == nil { - return errMarshalNil // can't marshal nil + return codec.ErrMarshalNil // can't marshal nil } return c.marshal(reflect.ValueOf(value), p, nil /*=typeStack*/) @@ -339,13 +337,13 @@ func (c *genericCodec) marshal( return p.Err case reflect.Ptr: if value.IsNil() { - return errMarshalNil + return codec.ErrMarshalNil } return c.marshal(value.Elem(), p, typeStack) case reflect.Interface: if value.IsNil() { - return errMarshalNil + return codec.ErrMarshalNil } underlyingValue := value.Interface() @@ -505,7 +503,7 @@ func (c *genericCodec) marshal( // interface func (c *genericCodec) Unmarshal(bytes []byte, dest interface{}) error { if dest == nil { - return errUnmarshalNil + return codec.ErrUnmarshalNil } p := wrappers.Packer{ diff --git a/codec/test_codec.go b/codec/test_codec.go index d58e2d818f9e..c3804a666ecc 100644 --- a/codec/test_codec.go +++ b/codec/test_codec.go @@ -15,6 +15,7 @@ import ( var ( Tests = []func(c GeneralCodec, t testing.TB){ TestStruct, + TestPartiallyFilledStruct, TestRegisterStructTwice, TestUInt32, TestUIntPtr, @@ -132,6 +133,31 @@ type myStruct struct { String string `serialize:"true"` } +func TestPartiallyFilledStruct(codec GeneralCodec, t testing.TB) { + require := require.New(t) + + manager := NewDefaultManager() + require.NoError(manager.RegisterCodec(0, codec)) + + // a nil point cannot be marshalled but we can get its size + var nilStruct *myStruct + _, err := manager.Marshal(0, nilStruct) + require.ErrorIs(err, ErrMarshalNil) + + bytesLen, err := manager.Size(0, nilStruct) + require.NoError(err) + require.Equal(CodecVersionSize, bytesLen) + + // empty struct cannot be marshalled but we can get its size + emptyStruct := &myStruct{} + _, err = manager.Marshal(0, nilStruct) + require.ErrorIs(err, ErrMarshalNil) + + bytesLen, err = manager.Size(0, emptyStruct) + require.NoError(err) + require.Equal(119, bytesLen) +} + // Test marshaling/unmarshaling a complicated struct func TestStruct(codec GeneralCodec, t testing.TB) { require := require.New(t) From 1b1cc993a472b11c2b67a817169cbae0cd3c2f9f Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 18 Jan 2024 11:03:06 +0100 Subject: [PATCH 049/190] nits --- codec/reflectcodec/type_codec.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/codec/reflectcodec/type_codec.go b/codec/reflectcodec/type_codec.go index 1b0d8dd78b7c..2ff4287955b3 100644 --- a/codec/reflectcodec/type_codec.go +++ b/codec/reflectcodec/type_codec.go @@ -88,7 +88,7 @@ func New(typer TypeCodec, tagNames []string, durangoTime time.Time, maxSliceLen func (c *genericCodec) Size(value interface{}) (int, error) { if value == nil { - return 0, nil // can't marshal nil + return 0, nil // can't marshal nil, we return zero size } size, _, err := c.size(reflect.ValueOf(value), nil /*=typeStack*/) @@ -124,14 +124,14 @@ func (c *genericCodec) size( return wrappers.StringLen(value.String()), false, nil case reflect.Ptr: if value.IsNil() { - return 0, true, nil + return 0, true, nil // can't marshal nil, we return zero size } return c.size(value.Elem(), typeStack) case reflect.Interface: if value.IsNil() { - return 0, true, nil + return 0, true, nil // can't marshal nil, we return zero size } underlyingValue := value.Interface() From 504f6c70e5a93fa910d4831bf34fc110d6a6be2f Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 18 Jan 2024 11:40:03 +0100 Subject: [PATCH 050/190] added UT --- codec/reflectcodec/type_codec.go | 4 +- codec/test_codec.go | 105 +++++++++++++++++++++++-------- 2 files changed, 82 insertions(+), 27 deletions(-) diff --git a/codec/reflectcodec/type_codec.go b/codec/reflectcodec/type_codec.go index 2ff4287955b3..e8b19e80fe83 100644 --- a/codec/reflectcodec/type_codec.go +++ b/codec/reflectcodec/type_codec.go @@ -124,14 +124,14 @@ func (c *genericCodec) size( return wrappers.StringLen(value.String()), false, nil case reflect.Ptr: if value.IsNil() { - return 0, true, nil // can't marshal nil, we return zero size + return 0, false, nil // can't marshal nil, we return zero size } return c.size(value.Elem(), typeStack) case reflect.Interface: if value.IsNil() { - return 0, true, nil // can't marshal nil, we return zero size + return 0, false, nil // can't marshal nil, we return zero size } underlyingValue := value.Interface() diff --git a/codec/test_codec.go b/codec/test_codec.go index c3804a666ecc..ed484042941b 100644 --- a/codec/test_codec.go +++ b/codec/test_codec.go @@ -16,6 +16,7 @@ var ( Tests = []func(c GeneralCodec, t testing.TB){ TestStruct, TestPartiallyFilledStruct, + TestSliceWithEmptyElements, TestRegisterStructTwice, TestUInt32, TestUIntPtr, @@ -133,31 +134,6 @@ type myStruct struct { String string `serialize:"true"` } -func TestPartiallyFilledStruct(codec GeneralCodec, t testing.TB) { - require := require.New(t) - - manager := NewDefaultManager() - require.NoError(manager.RegisterCodec(0, codec)) - - // a nil point cannot be marshalled but we can get its size - var nilStruct *myStruct - _, err := manager.Marshal(0, nilStruct) - require.ErrorIs(err, ErrMarshalNil) - - bytesLen, err := manager.Size(0, nilStruct) - require.NoError(err) - require.Equal(CodecVersionSize, bytesLen) - - // empty struct cannot be marshalled but we can get its size - emptyStruct := &myStruct{} - _, err = manager.Marshal(0, nilStruct) - require.ErrorIs(err, ErrMarshalNil) - - bytesLen, err = manager.Size(0, emptyStruct) - require.NoError(err) - require.Equal(119, bytesLen) -} - // Test marshaling/unmarshaling a complicated struct func TestStruct(codec GeneralCodec, t testing.TB) { require := require.New(t) @@ -275,6 +251,85 @@ func TestStruct(codec GeneralCodec, t testing.TB) { require.Equal(myStructInstance, *myStructUnmarshaled) } +func TestPartiallyFilledStruct(codec GeneralCodec, t testing.TB) { + require := require.New(t) + + manager := NewDefaultManager() + require.NoError(manager.RegisterCodec(0, codec)) + + // a nil pointer cannot be marshalled but we can get its size + var nilStruct *myStruct + _, err := manager.Marshal(0, nilStruct) + require.ErrorIs(err, ErrMarshalNil) + + bytesLen, err := manager.Size(0, nilStruct) + require.NoError(err) + require.Equal(CodecVersionSize, bytesLen) + + // an empty struct cannot be marshalled but we can get its size + emptyStruct := &myStruct{} + _, err = manager.Marshal(0, nilStruct) + require.ErrorIs(err, ErrMarshalNil) + + emptyStructLen := CodecVersionSize + 117 + bytesLen, err = manager.Size(0, emptyStruct) + require.NoError(err) + require.Equal(emptyStructLen, bytesLen) + + // an partially filled struct cannot be marshalled but we can get its size + elem := &MyInnerStruct{ + Str: "a", + } + elemLen := CodecVersionSize + wrappers.StringLen(elem.Str) + + partialStruct := &myStruct{ + InnerStruct2: elem, + } + partialStructLen := emptyStructLen + elemLen - CodecVersionSize + bytesLen, err = manager.Size(0, partialStruct) + require.NoError(err) + require.Equal(partialStructLen, bytesLen) +} + +func TestSliceWithEmptyElements(codec GeneralCodec, t testing.TB) { + require := require.New(t) + + manager := NewDefaultManager() + require.NoError(manager.RegisterCodec(0, codec)) + + // a non-empty slice with nil pointers cannot be marshalled but we can get its size + slice := make([]*MyInnerStruct, 10) + + _, err := manager.Marshal(0, slice) + require.ErrorIs(err, ErrMarshalNil) + + emptySliceLen := CodecVersionSize + wrappers.IntLen // Codec version + slice size. Slice elements have zero size + bytesLen, err := manager.Size(0, slice) + require.NoError(err) + require.Equal(emptySliceLen, bytesLen) + + elem := &MyInnerStruct{ + Str: "aaa", + } + elemLen := CodecVersionSize + wrappers.StringLen(elem.Str) + bytesLen, err = manager.Size(0, elem) + require.NoError(err) + require.Equal(elemLen, bytesLen) + + // we can fill some elements and leave other empty. Size will be sub-additive + slice[1] = elem + sliceLen := emptySliceLen + elemLen - CodecVersionSize // codec version is marshelled only once + bytesLen, err = manager.Size(0, slice) + require.NoError(err) + require.Equal(sliceLen, bytesLen) + + slice[5] = elem + sliceLen += elemLen - CodecVersionSize // codec version is marshelled only once + bytesLen, err = manager.Size(0, slice) + require.NoError(err) + require.Equal(sliceLen, bytesLen) +} + func TestRegisterStructTwice(codec GeneralCodec, t testing.TB) { require := require.New(t) From 524631c04efac7cad01b1154980b0164a9e4852a Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 18 Jan 2024 12:13:46 +0100 Subject: [PATCH 051/190] reduced diff --- node/node.go | 62 ++- vms/platformvm/block/builder/helpers_test.go | 18 +- vms/platformvm/block/executor/helpers_test.go | 18 +- vms/platformvm/config/config.go | 36 +- vms/platformvm/config/fee_config.go | 43 -- vms/platformvm/txs/executor/helpers_test.go | 18 +- .../executor/staker_tx_verification_test.go | 26 +- vms/platformvm/txs/fees/calculator_test.go | 400 +++++++----------- vms/platformvm/utxo/handler_test.go | 24 +- vms/platformvm/validator_set_property_test.go | 34 +- vms/platformvm/vm_test.go | 34 +- 11 files changed, 300 insertions(+), 413 deletions(-) delete mode 100644 vms/platformvm/config/fee_config.go diff --git a/node/node.go b/node/node.go index 6f74fba9179c..d62ddc3237e8 100644 --- a/node/node.go +++ b/node/node.go @@ -1188,38 +1188,36 @@ func (n *Node) initVMs() error { err := utils.Err( n.VMManager.RegisterFactory(context.TODO(), constants.PlatformVMID, &platformvm.Factory{ Config: platformconfig.Config{ - Chains: n.chainManager, - Validators: vdrs, - UptimeLockedCalculator: n.uptimeCalculator, - SybilProtectionEnabled: n.Config.SybilProtectionEnabled, - PartialSyncPrimaryNetwork: n.Config.PartialSyncPrimaryNetwork, - TrackedSubnets: n.Config.TrackedSubnets, - FeeConfig: platformconfig.FeeConfig{ - TxFee: n.Config.TxFee, - CreateAssetTxFee: n.Config.CreateAssetTxFee, - CreateSubnetTxFee: n.Config.CreateSubnetTxFee, - TransformSubnetTxFee: n.Config.TransformSubnetTxFee, - CreateBlockchainTxFee: n.Config.CreateBlockchainTxFee, - AddPrimaryNetworkValidatorFee: n.Config.AddPrimaryNetworkValidatorFee, - AddPrimaryNetworkDelegatorFee: n.Config.AddPrimaryNetworkDelegatorFee, - AddSubnetValidatorFee: n.Config.AddSubnetValidatorFee, - AddSubnetDelegatorFee: n.Config.AddSubnetDelegatorFee, - }, - UptimePercentage: n.Config.UptimeRequirement, - MinValidatorStake: n.Config.MinValidatorStake, - MaxValidatorStake: n.Config.MaxValidatorStake, - MinDelegatorStake: n.Config.MinDelegatorStake, - MinDelegationFee: n.Config.MinDelegationFee, - MinStakeDuration: n.Config.MinStakeDuration, - MaxStakeDuration: n.Config.MaxStakeDuration, - RewardConfig: n.Config.RewardConfig, - ApricotPhase3Time: version.GetApricotPhase3Time(n.Config.NetworkID), - ApricotPhase5Time: version.GetApricotPhase5Time(n.Config.NetworkID), - BanffTime: version.GetBanffTime(n.Config.NetworkID), - CortinaTime: version.GetCortinaTime(n.Config.NetworkID), - DurangoTime: durangoTime, - EForkTime: eForkTime, - UseCurrentHeight: n.Config.UseCurrentHeight, + Chains: n.chainManager, + Validators: vdrs, + UptimeLockedCalculator: n.uptimeCalculator, + SybilProtectionEnabled: n.Config.SybilProtectionEnabled, + PartialSyncPrimaryNetwork: n.Config.PartialSyncPrimaryNetwork, + TrackedSubnets: n.Config.TrackedSubnets, + TxFee: n.Config.TxFee, + CreateAssetTxFee: n.Config.CreateAssetTxFee, + CreateSubnetTxFee: n.Config.CreateSubnetTxFee, + TransformSubnetTxFee: n.Config.TransformSubnetTxFee, + CreateBlockchainTxFee: n.Config.CreateBlockchainTxFee, + AddPrimaryNetworkValidatorFee: n.Config.AddPrimaryNetworkValidatorFee, + AddPrimaryNetworkDelegatorFee: n.Config.AddPrimaryNetworkDelegatorFee, + AddSubnetValidatorFee: n.Config.AddSubnetValidatorFee, + AddSubnetDelegatorFee: n.Config.AddSubnetDelegatorFee, + UptimePercentage: n.Config.UptimeRequirement, + MinValidatorStake: n.Config.MinValidatorStake, + MaxValidatorStake: n.Config.MaxValidatorStake, + MinDelegatorStake: n.Config.MinDelegatorStake, + MinDelegationFee: n.Config.MinDelegationFee, + MinStakeDuration: n.Config.MinStakeDuration, + MaxStakeDuration: n.Config.MaxStakeDuration, + RewardConfig: n.Config.RewardConfig, + ApricotPhase3Time: version.GetApricotPhase3Time(n.Config.NetworkID), + ApricotPhase5Time: version.GetApricotPhase5Time(n.Config.NetworkID), + BanffTime: version.GetBanffTime(n.Config.NetworkID), + CortinaTime: version.GetCortinaTime(n.Config.NetworkID), + DurangoTime: durangoTime, + EForkTime: eForkTime, + UseCurrentHeight: n.Config.UseCurrentHeight, }, }), n.VMManager.RegisterFactory(context.TODO(), constants.AVMID, &avm.Factory{ diff --git a/vms/platformvm/block/builder/helpers_test.go b/vms/platformvm/block/builder/helpers_test.go index ceacb117f14b..6ea35f262b31 100644 --- a/vms/platformvm/block/builder/helpers_test.go +++ b/vms/platformvm/block/builder/helpers_test.go @@ -283,16 +283,14 @@ func defaultConfig() *config.Config { Chains: chains.TestManager, UptimeLockedCalculator: uptime.NewLockedCalculator(), Validators: validators.NewManager(), - FeeConfig: config.FeeConfig{ - TxFee: defaultTxFee, - CreateSubnetTxFee: 100 * defaultTxFee, - CreateBlockchainTxFee: 100 * defaultTxFee, - }, - MinValidatorStake: 5 * units.MilliAvax, - MaxValidatorStake: 500 * units.MilliAvax, - MinDelegatorStake: 1 * units.MilliAvax, - MinStakeDuration: defaultMinStakingDuration, - MaxStakeDuration: defaultMaxStakingDuration, + TxFee: defaultTxFee, + CreateSubnetTxFee: 100 * defaultTxFee, + CreateBlockchainTxFee: 100 * defaultTxFee, + MinValidatorStake: 5 * units.MilliAvax, + MaxValidatorStake: 500 * units.MilliAvax, + MinDelegatorStake: 1 * units.MilliAvax, + MinStakeDuration: defaultMinStakingDuration, + MaxStakeDuration: defaultMaxStakingDuration, RewardConfig: reward.Config{ MaxConsumptionRate: .12 * reward.PercentDenominator, MinConsumptionRate: .10 * reward.PercentDenominator, diff --git a/vms/platformvm/block/executor/helpers_test.go b/vms/platformvm/block/executor/helpers_test.go index 2a848823dff5..61871f0b36c1 100644 --- a/vms/platformvm/block/executor/helpers_test.go +++ b/vms/platformvm/block/executor/helpers_test.go @@ -301,16 +301,14 @@ func defaultConfig() *config.Config { Chains: chains.TestManager, UptimeLockedCalculator: uptime.NewLockedCalculator(), Validators: validators.NewManager(), - FeeConfig: config.FeeConfig{ - TxFee: defaultTxFee, - CreateSubnetTxFee: 100 * defaultTxFee, - CreateBlockchainTxFee: 100 * defaultTxFee, - }, - MinValidatorStake: 5 * units.MilliAvax, - MaxValidatorStake: 500 * units.MilliAvax, - MinDelegatorStake: 1 * units.MilliAvax, - MinStakeDuration: defaultMinStakingDuration, - MaxStakeDuration: defaultMaxStakingDuration, + TxFee: defaultTxFee, + CreateSubnetTxFee: 100 * defaultTxFee, + CreateBlockchainTxFee: 100 * defaultTxFee, + MinValidatorStake: 5 * units.MilliAvax, + MaxValidatorStake: 500 * units.MilliAvax, + MinDelegatorStake: 1 * units.MilliAvax, + MinStakeDuration: defaultMinStakingDuration, + MaxStakeDuration: defaultMaxStakingDuration, RewardConfig: reward.Config{ MaxConsumptionRate: .12 * reward.PercentDenominator, MinConsumptionRate: .10 * reward.PercentDenominator, diff --git a/vms/platformvm/config/config.go b/vms/platformvm/config/config.go index 00073586ddae..a61be143c3ac 100644 --- a/vms/platformvm/config/config.go +++ b/vms/platformvm/config/config.go @@ -43,8 +43,40 @@ type Config struct { // Set of subnets that this node is validating TrackedSubnets set.Set[ids.ID] - // All related to fees (static and multivariate/dynamic) - FeeConfig + // Post E Fork, the unit fee for each dimension, denominated in Avax + // As long as fees are multidimensional but not dynamic, [DefaultUnitFees] + // will be the unit fees + DefaultUnitFees fees.Dimensions + + // Post E Fork, the max complexity of a block for each dimension + DefaultBlockMaxConsumedUnits fees.Dimensions + + // Pre E Fork, fee that is burned by every non-state creating transaction + TxFee uint64 + + // Pre E Fork, fee that must be burned by every state creating transaction before AP3 + CreateAssetTxFee uint64 + + // Pre E Fork, fee that must be burned by every subnet creating transaction after AP3 + CreateSubnetTxFee uint64 + + // Pre E Fork, fee that must be burned by every transform subnet transaction + TransformSubnetTxFee uint64 + + // Pre E Fork, fee that must be burned by every blockchain creating transaction after AP3 + CreateBlockchainTxFee uint64 + + // Pre E Fork, transaction fee for adding a primary network validator + AddPrimaryNetworkValidatorFee uint64 + + // Pre E Fork, transaction fee for adding a primary network delegator + AddPrimaryNetworkDelegatorFee uint64 + + // Pre E Fork, transaction fee for adding a subnet validator + AddSubnetValidatorFee uint64 + + // Pre E Fork, transaction fee for adding a subnet delegator + AddSubnetDelegatorFee uint64 // The minimum amount of tokens one must bond to be a validator MinValidatorStake uint64 diff --git a/vms/platformvm/config/fee_config.go b/vms/platformvm/config/fee_config.go deleted file mode 100644 index bb8c3b5ee99e..000000000000 --- a/vms/platformvm/config/fee_config.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. -// See the file LICENSE for licensing terms. - -package config - -import "github.com/ava-labs/avalanchego/vms/components/fees" - -type FeeConfig struct { - // Post E Fork, the unit fee for each dimension, denominated in Avax - // As long as fees are multidimensional but not dynamic, [DefaultUnitFees] - // will be the unit fees - DefaultUnitFees fees.Dimensions - - // Post E Fork, the max complexity of a block for each dimension - DefaultBlockMaxConsumedUnits fees.Dimensions - - // Pre E Fork, fee that is burned by every non-state creating transaction - TxFee uint64 - - // Pre E Fork, fee that must be burned by every state creating transaction before AP3 - CreateAssetTxFee uint64 - - // Pre E Fork, fee that must be burned by every subnet creating transaction after AP3 - CreateSubnetTxFee uint64 - - // Pre E Fork, fee that must be burned by every transform subnet transaction - TransformSubnetTxFee uint64 - - // Pre E Fork, fee that must be burned by every blockchain creating transaction after AP3 - CreateBlockchainTxFee uint64 - - // Pre E Fork, transaction fee for adding a primary network validator - AddPrimaryNetworkValidatorFee uint64 - - // Pre E Fork, transaction fee for adding a primary network delegator - AddPrimaryNetworkDelegatorFee uint64 - - // Pre E Fork, transaction fee for adding a subnet validator - AddSubnetValidatorFee uint64 - - // Pre E Fork, transaction fee for adding a subnet delegator - AddSubnetDelegatorFee uint64 -} diff --git a/vms/platformvm/txs/executor/helpers_test.go b/vms/platformvm/txs/executor/helpers_test.go index f80ff8fe5963..bf72c1faaba4 100644 --- a/vms/platformvm/txs/executor/helpers_test.go +++ b/vms/platformvm/txs/executor/helpers_test.go @@ -267,16 +267,14 @@ func defaultConfig(postBanff, postCortina, postDurango bool) *config.Config { Chains: chains.TestManager, UptimeLockedCalculator: uptime.NewLockedCalculator(), Validators: validators.NewManager(), - FeeConfig: config.FeeConfig{ - TxFee: defaultTxFee, - CreateSubnetTxFee: 100 * defaultTxFee, - CreateBlockchainTxFee: 100 * defaultTxFee, - }, - MinValidatorStake: 5 * units.MilliAvax, - MaxValidatorStake: 500 * units.MilliAvax, - MinDelegatorStake: 1 * units.MilliAvax, - MinStakeDuration: defaultMinStakingDuration, - MaxStakeDuration: defaultMaxStakingDuration, + TxFee: defaultTxFee, + CreateSubnetTxFee: 100 * defaultTxFee, + CreateBlockchainTxFee: 100 * defaultTxFee, + MinValidatorStake: 5 * units.MilliAvax, + MaxValidatorStake: 500 * units.MilliAvax, + MinDelegatorStake: 1 * units.MilliAvax, + MinStakeDuration: defaultMinStakingDuration, + MaxStakeDuration: defaultMaxStakingDuration, RewardConfig: reward.Config{ MaxConsumptionRate: .12 * reward.PercentDenominator, MinConsumptionRate: .10 * reward.PercentDenominator, diff --git a/vms/platformvm/txs/executor/staker_tx_verification_test.go b/vms/platformvm/txs/executor/staker_tx_verification_test.go index 7347c9a0f32e..27f44ed08714 100644 --- a/vms/platformvm/txs/executor/staker_tx_verification_test.go +++ b/vms/platformvm/txs/executor/staker_tx_verification_test.go @@ -462,11 +462,9 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { return &Backend{ FlowChecker: flowChecker, Config: &config.Config{ - FeeConfig: config.FeeConfig{ - AddSubnetValidatorFee: 1, - }, - DurangoTime: activeForkTime, // activate latest fork, - EForkTime: mockable.MaxTime, + AddSubnetValidatorFee: 1, + DurangoTime: activeForkTime, // activate latest fork, + EForkTime: mockable.MaxTime, }, Ctx: ctx, Bootstrapped: bootstrapped, @@ -511,12 +509,10 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { return &Backend{ FlowChecker: flowChecker, Config: &config.Config{ - FeeConfig: config.FeeConfig{ - AddSubnetValidatorFee: 1, - }, - CortinaTime: activeForkTime, - DurangoTime: mockable.MaxTime, - EForkTime: mockable.MaxTime, + AddSubnetValidatorFee: 1, + CortinaTime: activeForkTime, + DurangoTime: mockable.MaxTime, + EForkTime: mockable.MaxTime, }, Ctx: ctx, Bootstrapped: bootstrapped, @@ -566,11 +562,9 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { return &Backend{ FlowChecker: flowChecker, Config: &config.Config{ - FeeConfig: config.FeeConfig{ - AddSubnetValidatorFee: 1, - }, - DurangoTime: activeForkTime, // activate latest fork, - EForkTime: mockable.MaxTime, + AddSubnetValidatorFee: 1, + DurangoTime: activeForkTime, // activate latest fork, + EForkTime: mockable.MaxTime, }, Ctx: ctx, Bootstrapped: bootstrapped, diff --git a/vms/platformvm/txs/fees/calculator_test.go b/vms/platformvm/txs/fees/calculator_test.go index c8cd85af0e05..fed70539c207 100644 --- a/vms/platformvm/txs/fees/calculator_test.go +++ b/vms/platformvm/txs/fees/calculator_test.go @@ -29,7 +29,7 @@ import ( ) var ( - feeTestsDefaultCfg = config.FeeConfig{ + feeTestsDefaultCfg = config.Config{ DefaultUnitFees: fees.Dimensions{ 1 * units.MicroAvax, 2 * units.MicroAvax, @@ -120,13 +120,9 @@ func TestPartiallyFulledTransactionsSizes(t *testing.T) { func TestAddAndRemoveFees(t *testing.T) { r := require.New(t) - cfg := &config.Config{ - FeeConfig: feeTestsDefaultCfg, - } - fc := &Calculator{ - FeeManager: fees.NewManager(cfg.DefaultUnitFees), - Config: cfg, + FeeManager: fees.NewManager(feeTestsDefaultCfg.DefaultUnitFees), + Config: &feeTestsDefaultCfg, } units := fees.Dimensions{ @@ -253,13 +249,11 @@ func TestAddValidatorTxFees(t *testing.T) { eForkTime := time.Now().Truncate(time.Second) chainTime := eForkTime.Add(-1 * time.Second) - cfg := &config.Config{ - FeeConfig: feeTestsDefaultCfg, - DurangoTime: durangoTime, - EForkTime: eForkTime, - } + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime - return cfg, chainTime + return &cfg, chainTime }, expectedError: nil, checksF: func(t *testing.T, fc *Calculator) { @@ -272,13 +266,11 @@ func TestAddValidatorTxFees(t *testing.T) { eForkTime := time.Now().Truncate(time.Second) chainTime := eForkTime.Add(time.Second) - cfg := &config.Config{ - FeeConfig: feeTestsDefaultCfg, - DurangoTime: durangoTime, - EForkTime: eForkTime, - } + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime - return cfg, chainTime + return &cfg, chainTime }, expectedError: nil, checksF: func(t *testing.T, fc *Calculator) { @@ -300,14 +292,12 @@ func TestAddValidatorTxFees(t *testing.T) { eForkTime := time.Now().Truncate(time.Second) chainTime := eForkTime.Add(time.Second) - cfg := &config.Config{ - FeeConfig: feeTestsDefaultCfg, - DurangoTime: durangoTime, - EForkTime: eForkTime, - } + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime cfg.DefaultBlockMaxConsumedUnits[0] = 741 - 1 - return cfg, chainTime + return &cfg, chainTime }, expectedError: errFailedConsumedUnitsCumulation, checksF: func(t *testing.T, fc *Calculator) {}, @@ -361,13 +351,11 @@ func TestAddSubnetValidatorTxFees(t *testing.T) { eForkTime := time.Now().Truncate(time.Second) chainTime := eForkTime.Add(-1 * time.Second) - cfg := &config.Config{ - FeeConfig: feeTestsDefaultCfg, - DurangoTime: durangoTime, - EForkTime: eForkTime, - } + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime - return cfg, chainTime + return &cfg, chainTime }, expectedError: nil, checksF: func(t *testing.T, fc *Calculator) { @@ -380,13 +368,11 @@ func TestAddSubnetValidatorTxFees(t *testing.T) { eForkTime := time.Now().Truncate(time.Second) chainTime := eForkTime.Add(time.Second) - cfg := &config.Config{ - FeeConfig: feeTestsDefaultCfg, - DurangoTime: durangoTime, - EForkTime: eForkTime, - } + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime - return cfg, chainTime + return &cfg, chainTime }, expectedError: nil, checksF: func(t *testing.T, fc *Calculator) { @@ -408,14 +394,12 @@ func TestAddSubnetValidatorTxFees(t *testing.T) { eForkTime := time.Now().Truncate(time.Second) chainTime := eForkTime.Add(time.Second) - cfg := &config.Config{ - FeeConfig: feeTestsDefaultCfg, - DurangoTime: durangoTime, - EForkTime: eForkTime, - } + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime cfg.DefaultBlockMaxConsumedUnits[1] = 1090 - 1 - return cfg, chainTime + return &cfg, chainTime }, expectedError: errFailedConsumedUnitsCumulation, checksF: func(t *testing.T, fc *Calculator) {}, @@ -470,13 +454,11 @@ func TestAddDelegatorTxFees(t *testing.T) { eForkTime := time.Now().Truncate(time.Second) chainTime := eForkTime.Add(-1 * time.Second) - cfg := &config.Config{ - FeeConfig: feeTestsDefaultCfg, - DurangoTime: durangoTime, - EForkTime: eForkTime, - } + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime - return cfg, chainTime + return &cfg, chainTime }, expectedError: nil, checksF: func(t *testing.T, fc *Calculator) { @@ -489,13 +471,11 @@ func TestAddDelegatorTxFees(t *testing.T) { eForkTime := time.Now().Truncate(time.Second) chainTime := eForkTime.Add(time.Second) - cfg := &config.Config{ - FeeConfig: feeTestsDefaultCfg, - DurangoTime: durangoTime, - EForkTime: eForkTime, - } + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime - return cfg, chainTime + return &cfg, chainTime }, expectedError: nil, checksF: func(t *testing.T, fc *Calculator) { @@ -517,14 +497,12 @@ func TestAddDelegatorTxFees(t *testing.T) { eForkTime := time.Now().Truncate(time.Second) chainTime := eForkTime.Add(time.Second) - cfg := &config.Config{ - FeeConfig: feeTestsDefaultCfg, - DurangoTime: durangoTime, - EForkTime: eForkTime, - } + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime cfg.DefaultBlockMaxConsumedUnits[1] = 1090 - 1 - return cfg, chainTime + return &cfg, chainTime }, expectedError: errFailedConsumedUnitsCumulation, checksF: func(t *testing.T, fc *Calculator) {}, @@ -573,13 +551,11 @@ func TestCreateChainTxFees(t *testing.T) { eForkTime := time.Now().Truncate(time.Second) chainTime := eForkTime.Add(-1 * time.Second) - cfg := &config.Config{ - FeeConfig: feeTestsDefaultCfg, - DurangoTime: durangoTime, - EForkTime: eForkTime, - } + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime - return cfg, chainTime + return &cfg, chainTime }, expectedError: nil, checksF: func(t *testing.T, fc *Calculator) { @@ -592,13 +568,11 @@ func TestCreateChainTxFees(t *testing.T) { eForkTime := time.Now().Truncate(time.Second) chainTime := eForkTime.Add(time.Second) - cfg := &config.Config{ - FeeConfig: feeTestsDefaultCfg, - DurangoTime: durangoTime, - EForkTime: eForkTime, - } + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime - return cfg, chainTime + return &cfg, chainTime }, expectedError: nil, checksF: func(t *testing.T, fc *Calculator) { @@ -620,14 +594,12 @@ func TestCreateChainTxFees(t *testing.T) { eForkTime := time.Now().Truncate(time.Second) chainTime := eForkTime.Add(time.Second) - cfg := &config.Config{ - FeeConfig: feeTestsDefaultCfg, - DurangoTime: durangoTime, - EForkTime: eForkTime, - } + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime cfg.DefaultBlockMaxConsumedUnits[1] = 1090 - 1 - return cfg, chainTime + return &cfg, chainTime }, expectedError: errFailedConsumedUnitsCumulation, checksF: func(t *testing.T, fc *Calculator) {}, @@ -674,13 +646,11 @@ func TestCreateSubnetTxFees(t *testing.T) { eForkTime := time.Now().Truncate(time.Second) chainTime := eForkTime.Add(-1 * time.Second) - cfg := &config.Config{ - FeeConfig: feeTestsDefaultCfg, - DurangoTime: durangoTime, - EForkTime: eForkTime, - } + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime - return cfg, chainTime + return &cfg, chainTime }, expectedError: nil, checksF: func(t *testing.T, fc *Calculator) { @@ -693,13 +663,11 @@ func TestCreateSubnetTxFees(t *testing.T) { eForkTime := time.Now().Truncate(time.Second) chainTime := eForkTime.Add(time.Second) - cfg := &config.Config{ - FeeConfig: feeTestsDefaultCfg, - DurangoTime: durangoTime, - EForkTime: eForkTime, - } + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime - return cfg, chainTime + return &cfg, chainTime }, expectedError: nil, checksF: func(t *testing.T, fc *Calculator) { @@ -721,14 +689,12 @@ func TestCreateSubnetTxFees(t *testing.T) { eForkTime := time.Now().Truncate(time.Second) chainTime := eForkTime.Add(time.Second) - cfg := &config.Config{ - FeeConfig: feeTestsDefaultCfg, - DurangoTime: durangoTime, - EForkTime: eForkTime, - } + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime cfg.DefaultBlockMaxConsumedUnits[1] = 1090 - 1 - return cfg, chainTime + return &cfg, chainTime }, expectedError: errFailedConsumedUnitsCumulation, checksF: func(t *testing.T, fc *Calculator) {}, @@ -774,13 +740,11 @@ func TestRemoveSubnetValidatorTxFees(t *testing.T) { eForkTime := time.Now().Truncate(time.Second) chainTime := eForkTime.Add(-1 * time.Second) - cfg := &config.Config{ - FeeConfig: feeTestsDefaultCfg, - DurangoTime: durangoTime, - EForkTime: eForkTime, - } + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime - return cfg, chainTime + return &cfg, chainTime }, expectedError: nil, checksF: func(t *testing.T, fc *Calculator) { @@ -793,13 +757,11 @@ func TestRemoveSubnetValidatorTxFees(t *testing.T) { eForkTime := time.Now().Truncate(time.Second) chainTime := eForkTime.Add(time.Second) - cfg := &config.Config{ - FeeConfig: feeTestsDefaultCfg, - DurangoTime: durangoTime, - EForkTime: eForkTime, - } + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime - return cfg, chainTime + return &cfg, chainTime }, expectedError: nil, checksF: func(t *testing.T, fc *Calculator) { @@ -821,14 +783,12 @@ func TestRemoveSubnetValidatorTxFees(t *testing.T) { eForkTime := time.Now().Truncate(time.Second) chainTime := eForkTime.Add(time.Second) - cfg := &config.Config{ - FeeConfig: feeTestsDefaultCfg, - DurangoTime: durangoTime, - EForkTime: eForkTime, - } + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime cfg.DefaultBlockMaxConsumedUnits[1] = 1090 - 1 - return cfg, chainTime + return &cfg, chainTime }, expectedError: errFailedConsumedUnitsCumulation, checksF: func(t *testing.T, fc *Calculator) {}, @@ -886,13 +846,11 @@ func TestTransformSubnetTxFees(t *testing.T) { eForkTime := time.Now().Truncate(time.Second) chainTime := eForkTime.Add(-1 * time.Second) - cfg := &config.Config{ - FeeConfig: feeTestsDefaultCfg, - DurangoTime: durangoTime, - EForkTime: eForkTime, - } + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime - return cfg, chainTime + return &cfg, chainTime }, expectedError: nil, checksF: func(t *testing.T, fc *Calculator) { @@ -905,13 +863,11 @@ func TestTransformSubnetTxFees(t *testing.T) { eForkTime := time.Now().Truncate(time.Second) chainTime := eForkTime.Add(time.Second) - cfg := &config.Config{ - FeeConfig: feeTestsDefaultCfg, - DurangoTime: durangoTime, - EForkTime: eForkTime, - } + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime - return cfg, chainTime + return &cfg, chainTime }, expectedError: nil, checksF: func(t *testing.T, fc *Calculator) { @@ -933,14 +889,12 @@ func TestTransformSubnetTxFees(t *testing.T) { eForkTime := time.Now().Truncate(time.Second) chainTime := eForkTime.Add(time.Second) - cfg := &config.Config{ - FeeConfig: feeTestsDefaultCfg, - DurangoTime: durangoTime, - EForkTime: eForkTime, - } + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime cfg.DefaultBlockMaxConsumedUnits[1] = 1090 - 1 - return cfg, chainTime + return &cfg, chainTime }, expectedError: errFailedConsumedUnitsCumulation, checksF: func(t *testing.T, fc *Calculator) {}, @@ -994,13 +948,11 @@ func TestTransferSubnetOwnershipTxFees(t *testing.T) { eForkTime := time.Now().Truncate(time.Second) chainTime := eForkTime.Add(-1 * time.Second) - cfg := &config.Config{ - FeeConfig: feeTestsDefaultCfg, - DurangoTime: durangoTime, - EForkTime: eForkTime, - } + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime - return cfg, chainTime + return &cfg, chainTime }, expectedError: nil, checksF: func(t *testing.T, fc *Calculator) { @@ -1013,13 +965,11 @@ func TestTransferSubnetOwnershipTxFees(t *testing.T) { eForkTime := time.Now().Truncate(time.Second) chainTime := eForkTime.Add(time.Second) - cfg := &config.Config{ - FeeConfig: feeTestsDefaultCfg, - DurangoTime: durangoTime, - EForkTime: eForkTime, - } + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime - return cfg, chainTime + return &cfg, chainTime }, expectedError: nil, checksF: func(t *testing.T, fc *Calculator) { @@ -1041,14 +991,12 @@ func TestTransferSubnetOwnershipTxFees(t *testing.T) { eForkTime := time.Now().Truncate(time.Second) chainTime := eForkTime.Add(time.Second) - cfg := &config.Config{ - FeeConfig: feeTestsDefaultCfg, - DurangoTime: durangoTime, - EForkTime: eForkTime, - } + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime cfg.DefaultBlockMaxConsumedUnits[1] = 1090 - 1 - return cfg, chainTime + return &cfg, chainTime }, expectedError: errFailedConsumedUnitsCumulation, checksF: func(t *testing.T, fc *Calculator) {}, @@ -1111,13 +1059,11 @@ func TestAddPermissionlessValidatorTxFees(t *testing.T) { eForkTime := time.Now().Truncate(time.Second) chainTime := eForkTime.Add(-1 * time.Second) - cfg := &config.Config{ - FeeConfig: feeTestsDefaultCfg, - DurangoTime: durangoTime, - EForkTime: eForkTime, - } + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime - return cfg, chainTime + return &cfg, chainTime }, expectedError: nil, checksF: func(t *testing.T, fc *Calculator) { @@ -1130,13 +1076,11 @@ func TestAddPermissionlessValidatorTxFees(t *testing.T) { eForkTime := time.Now().Truncate(time.Second) chainTime := eForkTime.Add(time.Second) - cfg := &config.Config{ - FeeConfig: feeTestsDefaultCfg, - DurangoTime: durangoTime, - EForkTime: eForkTime, - } + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime - return cfg, chainTime + return &cfg, chainTime }, expectedError: nil, checksF: func(t *testing.T, fc *Calculator) { @@ -1158,14 +1102,12 @@ func TestAddPermissionlessValidatorTxFees(t *testing.T) { eForkTime := time.Now().Truncate(time.Second) chainTime := eForkTime.Add(time.Second) - cfg := &config.Config{ - FeeConfig: feeTestsDefaultCfg, - DurangoTime: durangoTime, - EForkTime: eForkTime, - } + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime cfg.DefaultBlockMaxConsumedUnits[1] = 1090 - 1 - return cfg, chainTime + return &cfg, chainTime }, expectedError: errFailedConsumedUnitsCumulation, checksF: func(t *testing.T, fc *Calculator) {}, @@ -1223,13 +1165,11 @@ func TestAddPermissionlessDelegatorTxFees(t *testing.T) { eForkTime := time.Now().Truncate(time.Second) chainTime := eForkTime.Add(-1 * time.Second) - cfg := &config.Config{ - FeeConfig: feeTestsDefaultCfg, - DurangoTime: durangoTime, - EForkTime: eForkTime, - } + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime - return cfg, chainTime + return &cfg, chainTime }, expectedError: nil, checksF: func(t *testing.T, fc *Calculator) { @@ -1242,13 +1182,11 @@ func TestAddPermissionlessDelegatorTxFees(t *testing.T) { eForkTime := time.Now().Truncate(time.Second) chainTime := eForkTime.Add(time.Second) - cfg := &config.Config{ - FeeConfig: feeTestsDefaultCfg, - DurangoTime: durangoTime, - EForkTime: eForkTime, - } + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime - return cfg, chainTime + return &cfg, chainTime }, expectedError: nil, checksF: func(t *testing.T, fc *Calculator) { @@ -1270,14 +1208,12 @@ func TestAddPermissionlessDelegatorTxFees(t *testing.T) { eForkTime := time.Now().Truncate(time.Second) chainTime := eForkTime.Add(time.Second) - cfg := &config.Config{ - FeeConfig: feeTestsDefaultCfg, - DurangoTime: durangoTime, - EForkTime: eForkTime, - } + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime cfg.DefaultBlockMaxConsumedUnits[1] = 1090 - 1 - return cfg, chainTime + return &cfg, chainTime }, expectedError: errFailedConsumedUnitsCumulation, checksF: func(t *testing.T, fc *Calculator) {}, @@ -1318,13 +1254,11 @@ func TestBaseTxFees(t *testing.T) { eForkTime := time.Now().Truncate(time.Second) chainTime := eForkTime.Add(-1 * time.Second) - cfg := &config.Config{ - FeeConfig: feeTestsDefaultCfg, - DurangoTime: durangoTime, - EForkTime: eForkTime, - } + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime - return cfg, chainTime + return &cfg, chainTime }, expectedError: nil, checksF: func(t *testing.T, fc *Calculator) { @@ -1337,13 +1271,11 @@ func TestBaseTxFees(t *testing.T) { eForkTime := time.Now().Truncate(time.Second) chainTime := eForkTime.Add(time.Second) - cfg := &config.Config{ - FeeConfig: feeTestsDefaultCfg, - DurangoTime: durangoTime, - EForkTime: eForkTime, - } + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime - return cfg, chainTime + return &cfg, chainTime }, expectedError: nil, checksF: func(t *testing.T, fc *Calculator) { @@ -1365,14 +1297,12 @@ func TestBaseTxFees(t *testing.T) { eForkTime := time.Now().Truncate(time.Second) chainTime := eForkTime.Add(time.Second) - cfg := &config.Config{ - FeeConfig: feeTestsDefaultCfg, - DurangoTime: durangoTime, - EForkTime: eForkTime, - } + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime cfg.DefaultBlockMaxConsumedUnits[1] = 1090 - 1 - return cfg, chainTime + return &cfg, chainTime }, expectedError: errFailedConsumedUnitsCumulation, checksF: func(t *testing.T, fc *Calculator) {}, @@ -1427,13 +1357,11 @@ func TestImportTxFees(t *testing.T) { eForkTime := time.Now().Truncate(time.Second) chainTime := eForkTime.Add(-1 * time.Second) - cfg := &config.Config{ - FeeConfig: feeTestsDefaultCfg, - DurangoTime: durangoTime, - EForkTime: eForkTime, - } + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime - return cfg, chainTime + return &cfg, chainTime }, expectedError: nil, checksF: func(t *testing.T, fc *Calculator) { @@ -1446,13 +1374,11 @@ func TestImportTxFees(t *testing.T) { eForkTime := time.Now().Truncate(time.Second) chainTime := eForkTime.Add(time.Second) - cfg := &config.Config{ - FeeConfig: feeTestsDefaultCfg, - DurangoTime: durangoTime, - EForkTime: eForkTime, - } + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime - return cfg, chainTime + return &cfg, chainTime }, expectedError: nil, checksF: func(t *testing.T, fc *Calculator) { @@ -1474,14 +1400,12 @@ func TestImportTxFees(t *testing.T) { eForkTime := time.Now().Truncate(time.Second) chainTime := eForkTime.Add(time.Second) - cfg := &config.Config{ - FeeConfig: feeTestsDefaultCfg, - DurangoTime: durangoTime, - EForkTime: eForkTime, - } + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime cfg.DefaultBlockMaxConsumedUnits[1] = 1090 - 1 - return cfg, chainTime + return &cfg, chainTime }, expectedError: errFailedConsumedUnitsCumulation, checksF: func(t *testing.T, fc *Calculator) {}, @@ -1526,13 +1450,11 @@ func TestExportTxFees(t *testing.T) { eForkTime := time.Now().Truncate(time.Second) chainTime := eForkTime.Add(-1 * time.Second) - cfg := &config.Config{ - FeeConfig: feeTestsDefaultCfg, - DurangoTime: durangoTime, - EForkTime: eForkTime, - } + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime - return cfg, chainTime + return &cfg, chainTime }, expectedError: nil, checksF: func(t *testing.T, fc *Calculator) { @@ -1545,13 +1467,11 @@ func TestExportTxFees(t *testing.T) { eForkTime := time.Now().Truncate(time.Second) chainTime := eForkTime.Add(time.Second) - cfg := &config.Config{ - FeeConfig: feeTestsDefaultCfg, - DurangoTime: durangoTime, - EForkTime: eForkTime, - } + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime - return cfg, chainTime + return &cfg, chainTime }, expectedError: nil, checksF: func(t *testing.T, fc *Calculator) { @@ -1573,14 +1493,12 @@ func TestExportTxFees(t *testing.T) { eForkTime := time.Now().Truncate(time.Second) chainTime := eForkTime.Add(time.Second) - cfg := &config.Config{ - FeeConfig: feeTestsDefaultCfg, - DurangoTime: durangoTime, - EForkTime: eForkTime, - } + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime cfg.DefaultBlockMaxConsumedUnits[1] = 1090 - 1 - return cfg, chainTime + return &cfg, chainTime }, expectedError: errFailedConsumedUnitsCumulation, checksF: func(t *testing.T, fc *Calculator) {}, diff --git a/vms/platformvm/utxo/handler_test.go b/vms/platformvm/utxo/handler_test.go index 2027c6cee7c0..476548bd9aed 100644 --- a/vms/platformvm/utxo/handler_test.go +++ b/vms/platformvm/utxo/handler_test.go @@ -55,19 +55,17 @@ func TestVerifyFinanceTx(t *testing.T) { } cfg := &config.Config{ - FeeConfig: config.FeeConfig{ - DefaultUnitFees: commonfees.Dimensions{ - 1 * units.MicroAvax, - 2 * units.MicroAvax, - 3 * units.MicroAvax, - 4 * units.MicroAvax, - }, - DefaultBlockMaxConsumedUnits: commonfees.Dimensions{ - math.MaxUint64, - math.MaxUint64, - math.MaxUint64, - math.MaxUint64, - }, + DefaultUnitFees: commonfees.Dimensions{ + 1 * units.MicroAvax, + 2 * units.MicroAvax, + 3 * units.MicroAvax, + 4 * units.MicroAvax, + }, + DefaultBlockMaxConsumedUnits: commonfees.Dimensions{ + math.MaxUint64, + math.MaxUint64, + math.MaxUint64, + math.MaxUint64, }, } diff --git a/vms/platformvm/validator_set_property_test.go b/vms/platformvm/validator_set_property_test.go index 4c46132b9a3c..ca161f744011 100644 --- a/vms/platformvm/validator_set_property_test.go +++ b/vms/platformvm/validator_set_property_test.go @@ -716,24 +716,22 @@ func buildVM(t *testing.T) (*VM, ids.ID, error) { UptimeLockedCalculator: uptime.NewLockedCalculator(), SybilProtectionEnabled: true, Validators: validators.NewManager(), - FeeConfig: config.FeeConfig{ - TxFee: defaultTxFee, - CreateSubnetTxFee: 100 * defaultTxFee, - TransformSubnetTxFee: 100 * defaultTxFee, - CreateBlockchainTxFee: 100 * defaultTxFee, - }, - MinValidatorStake: defaultMinValidatorStake, - MaxValidatorStake: defaultMaxValidatorStake, - MinDelegatorStake: defaultMinDelegatorStake, - MinStakeDuration: defaultMinStakingDuration, - MaxStakeDuration: defaultMaxStakingDuration, - RewardConfig: defaultRewardConfig, - ApricotPhase3Time: forkTime, - ApricotPhase5Time: forkTime, - BanffTime: forkTime, - CortinaTime: forkTime, - DurangoTime: forkTime, - EForkTime: mockable.MaxTime, + TxFee: defaultTxFee, + CreateSubnetTxFee: 100 * defaultTxFee, + TransformSubnetTxFee: 100 * defaultTxFee, + CreateBlockchainTxFee: 100 * defaultTxFee, + MinValidatorStake: defaultMinValidatorStake, + MaxValidatorStake: defaultMaxValidatorStake, + MinDelegatorStake: defaultMinDelegatorStake, + MinStakeDuration: defaultMinStakingDuration, + MaxStakeDuration: defaultMaxStakingDuration, + RewardConfig: defaultRewardConfig, + ApricotPhase3Time: forkTime, + ApricotPhase5Time: forkTime, + BanffTime: forkTime, + CortinaTime: forkTime, + DurangoTime: forkTime, + EForkTime: mockable.MaxTime, }} vm.clock.Set(forkTime.Add(time.Second)) diff --git a/vms/platformvm/vm_test.go b/vms/platformvm/vm_test.go index e25e3cbf4088..6c8733550d09 100644 --- a/vms/platformvm/vm_test.go +++ b/vms/platformvm/vm_test.go @@ -237,24 +237,22 @@ func defaultVM(t *testing.T, fork activeFork) (*VM, database.Database, *mutableS UptimeLockedCalculator: uptime.NewLockedCalculator(), SybilProtectionEnabled: true, Validators: validators.NewManager(), - FeeConfig: config.FeeConfig{ - TxFee: defaultTxFee, - CreateSubnetTxFee: 100 * defaultTxFee, - TransformSubnetTxFee: 100 * defaultTxFee, - CreateBlockchainTxFee: 100 * defaultTxFee, - }, - MinValidatorStake: defaultMinValidatorStake, - MaxValidatorStake: defaultMaxValidatorStake, - MinDelegatorStake: defaultMinDelegatorStake, - MinStakeDuration: defaultMinStakingDuration, - MaxStakeDuration: defaultMaxStakingDuration, - RewardConfig: defaultRewardConfig, - ApricotPhase3Time: apricotPhase3Time, - ApricotPhase5Time: apricotPhase5Time, - BanffTime: banffTime, - CortinaTime: cortinaTime, - DurangoTime: durangoTime, - EForkTime: mockable.MaxTime, + TxFee: defaultTxFee, + CreateSubnetTxFee: 100 * defaultTxFee, + TransformSubnetTxFee: 100 * defaultTxFee, + CreateBlockchainTxFee: 100 * defaultTxFee, + MinValidatorStake: defaultMinValidatorStake, + MaxValidatorStake: defaultMaxValidatorStake, + MinDelegatorStake: defaultMinDelegatorStake, + MinStakeDuration: defaultMinStakingDuration, + MaxStakeDuration: defaultMaxStakingDuration, + RewardConfig: defaultRewardConfig, + ApricotPhase3Time: apricotPhase3Time, + ApricotPhase5Time: apricotPhase5Time, + BanffTime: banffTime, + CortinaTime: cortinaTime, + DurangoTime: durangoTime, + EForkTime: mockable.MaxTime, }} db := memdb.New() From 9e668d5aea8e1c8c3799ae572bc61cc0738e3052 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 18 Jan 2024 12:19:02 +0100 Subject: [PATCH 052/190] nit --- vms/platformvm/state/metadata_validator.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vms/platformvm/state/metadata_validator.go b/vms/platformvm/state/metadata_validator.go index 0c725368505b..74242150d37f 100644 --- a/vms/platformvm/state/metadata_validator.go +++ b/vms/platformvm/state/metadata_validator.go @@ -6,6 +6,7 @@ package state import ( "time" + "github.com/ava-labs/avalanchego/codec" "github.com/ava-labs/avalanchego/database" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils/constants" @@ -17,7 +18,7 @@ import ( // [preDelegateeRewardMetadata]. // // CodecVersionLen + UpDurationLen + LastUpdatedLen + PotentialRewardLen -const preDelegateeRewardSize = wrappers.ShortLen + 3*wrappers.LongLen +const preDelegateeRewardSize = codec.CodecVersionSize + 3*wrappers.LongLen var _ validatorState = (*metadata)(nil) From 057a4e4d8902a6a457c1747d7b63f334189c362c Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 22 Jan 2024 11:07:00 +0100 Subject: [PATCH 053/190] exported p-chain unit fees via API --- vms/platformvm/client.go | 10 ++++++++++ vms/platformvm/service.go | 21 +++++++++++++++++++++ vms/platformvm/service_test.go | 30 ++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+) diff --git a/vms/platformvm/client.go b/vms/platformvm/client.go index 9311fd290a7e..a9bf62ec944e 100644 --- a/vms/platformvm/client.go +++ b/vms/platformvm/client.go @@ -18,6 +18,7 @@ import ( "github.com/ava-labs/avalanchego/utils/rpc" "github.com/ava-labs/avalanchego/vms/platformvm/status" + commonfees "github.com/ava-labs/avalanchego/vms/components/fees" platformapi "github.com/ava-labs/avalanchego/vms/platformvm/api" ) @@ -263,6 +264,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) + + // GetUnitFees returns the current unit fees that a transaction must pay to be accepted + GetUnitFees(ctx context.Context, options ...rpc.Option) (commonfees.Dimensions, error) } // Client implementation for interacting with the P Chain endpoint @@ -891,3 +895,9 @@ func (c *client) GetBlockByHeight(ctx context.Context, height uint64, options .. } return formatting.Decode(res.Encoding, res.Block) } + +func (c *client) GetUnitFees(ctx context.Context, options ...rpc.Option) (commonfees.Dimensions, error) { + res := &GetUnitFeesReply{} + err := c.requester.SendRequest(ctx, "platform.getUnitFees", struct{}{}, res, options...) + return res.UnitFees, err +} diff --git a/vms/platformvm/service.go b/vms/platformvm/service.go index 16e5b16844c6..3b897112c8df 100644 --- a/vms/platformvm/service.go +++ b/vms/platformvm/service.go @@ -44,6 +44,7 @@ import ( "github.com/ava-labs/avalanchego/vms/secp256k1fx" safemath "github.com/ava-labs/avalanchego/utils/math" + commonfees "github.com/ava-labs/avalanchego/vms/components/fees" platformapi "github.com/ava-labs/avalanchego/vms/platformvm/api" ) @@ -2810,6 +2811,26 @@ func (s *Service) GetBlockByHeight(_ *http.Request, args *api.GetBlockByHeightAr return err } +// GetUnitFeesReply is the response from GetUnitFees +type GetUnitFeesReply struct { + // Current timestamp + UnitFees commonfees.Dimensions `json:"unitfees"` +} + +// GetTimestamp returns the current timestamp on chain. +func (s *Service) GetUnitFees(_ *http.Request, _ *struct{}, reply *GetUnitFeesReply) error { + s.vm.ctx.Log.Debug("API called", + zap.String("service", "platform"), + zap.String("method", "getUnitFees"), + ) + + s.vm.ctx.Lock.Lock() + defer s.vm.ctx.Lock.Unlock() + + reply.UnitFees = s.vm.DefaultUnitFees + return nil +} + func (s *Service) getAPIUptime(staker *state.Staker) (*json.Float32, error) { // Only report uptimes that we have been actively tracking. if constants.PrimaryNetworkID != staker.SubnetID && !s.vm.TrackedSubnets.Contains(staker.SubnetID) { diff --git a/vms/platformvm/service_test.go b/vms/platformvm/service_test.go index 2c6b72255c3f..0db19ad36458 100644 --- a/vms/platformvm/service_test.go +++ b/vms/platformvm/service_test.go @@ -36,6 +36,7 @@ import ( "github.com/ava-labs/avalanchego/utils/json" "github.com/ava-labs/avalanchego/utils/logging" "github.com/ava-labs/avalanchego/vms/components/avax" + commonfees "github.com/ava-labs/avalanchego/vms/components/fees" "github.com/ava-labs/avalanchego/vms/platformvm/block" "github.com/ava-labs/avalanchego/vms/platformvm/state" "github.com/ava-labs/avalanchego/vms/platformvm/status" @@ -1057,3 +1058,32 @@ func TestServiceGetBlockByHeight(t *testing.T) { }) } } + +func TestGetUnitFees(t *testing.T) { + require := require.New(t) + service, _ := defaultService(t) + defer func() { + service.vm.ctx.Lock.Lock() + require.NoError(service.vm.Shutdown(context.Background())) + service.vm.ctx.Lock.Unlock() + }() + + reply := GetUnitFeesReply{} + require.NoError(service.GetUnitFees(nil, nil, &reply)) + + service.vm.ctx.Lock.Lock() + + require.Equal(service.vm.Config.DefaultUnitFees, reply.UnitFees) + + service.vm.Config.DefaultUnitFees = commonfees.Dimensions{ + 123, + 456, + 789, + 1011, + } + + service.vm.ctx.Lock.Unlock() + + require.NoError(service.GetUnitFees(nil, nil, &reply)) + require.Equal(service.vm.Config.DefaultUnitFees, reply.UnitFees) +} From 27eb36d777ffda34a1b34ec7fa64c30bb536cfde Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 22 Jan 2024 12:44:11 +0100 Subject: [PATCH 054/190] exported p-chain block units cap via API --- vms/platformvm/client.go | 9 +++++++++ vms/platformvm/service.go | 20 ++++++++++++++++++++ vms/platformvm/service_test.go | 29 +++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+) diff --git a/vms/platformvm/client.go b/vms/platformvm/client.go index a9bf62ec944e..ab92a9f97002 100644 --- a/vms/platformvm/client.go +++ b/vms/platformvm/client.go @@ -267,6 +267,9 @@ type Client interface { // GetUnitFees returns the current unit fees that a transaction must pay to be accepted GetUnitFees(ctx context.Context, options ...rpc.Option) (commonfees.Dimensions, error) + + // GetBlockUnitsCap returns the current maximal units that can be consumed in a block + GetBlockUnitsCap(ctx context.Context, options ...rpc.Option) (commonfees.Dimensions, error) } // Client implementation for interacting with the P Chain endpoint @@ -901,3 +904,9 @@ func (c *client) GetUnitFees(ctx context.Context, options ...rpc.Option) (common err := c.requester.SendRequest(ctx, "platform.getUnitFees", struct{}{}, res, options...) return res.UnitFees, err } + +func (c *client) GetBlockUnitsCap(ctx context.Context, options ...rpc.Option) (commonfees.Dimensions, error) { + res := &GetBlockUnitsCapReply{} + err := c.requester.SendRequest(ctx, "platform.GetBlockUnitsCapReply", struct{}{}, res, options...) + return res.MaxUnits, err +} diff --git a/vms/platformvm/service.go b/vms/platformvm/service.go index 3b897112c8df..6df95b035ddc 100644 --- a/vms/platformvm/service.go +++ b/vms/platformvm/service.go @@ -2831,6 +2831,26 @@ func (s *Service) GetUnitFees(_ *http.Request, _ *struct{}, reply *GetUnitFeesRe return nil } +// GetBlockUnitsCapReply is the response from GetBlockUnitsCap +type GetBlockUnitsCapReply struct { + // Current timestamp + MaxUnits commonfees.Dimensions `json:"maxUnits"` +} + +// GetTimestamp returns the current timestamp on chain. +func (s *Service) GetBlockUnitsCap(_ *http.Request, _ *struct{}, reply *GetBlockUnitsCapReply) error { + s.vm.ctx.Log.Debug("API called", + zap.String("service", "platform"), + zap.String("method", "getBlockUnitsCap"), + ) + + s.vm.ctx.Lock.Lock() + defer s.vm.ctx.Lock.Unlock() + + reply.MaxUnits = s.vm.DefaultBlockMaxConsumedUnits + return nil +} + func (s *Service) getAPIUptime(staker *state.Staker) (*json.Float32, error) { // Only report uptimes that we have been actively tracking. if constants.PrimaryNetworkID != staker.SubnetID && !s.vm.TrackedSubnets.Contains(staker.SubnetID) { diff --git a/vms/platformvm/service_test.go b/vms/platformvm/service_test.go index 0db19ad36458..554ae3a3e31b 100644 --- a/vms/platformvm/service_test.go +++ b/vms/platformvm/service_test.go @@ -1087,3 +1087,32 @@ func TestGetUnitFees(t *testing.T) { require.NoError(service.GetUnitFees(nil, nil, &reply)) require.Equal(service.vm.Config.DefaultUnitFees, reply.UnitFees) } + +func TestGetBlockUnitsCap(t *testing.T) { + require := require.New(t) + service, _ := defaultService(t) + defer func() { + service.vm.ctx.Lock.Lock() + require.NoError(service.vm.Shutdown(context.Background())) + service.vm.ctx.Lock.Unlock() + }() + + reply := GetBlockUnitsCapReply{} + require.NoError(service.GetBlockUnitsCap(nil, nil, &reply)) + + service.vm.ctx.Lock.Lock() + + require.Equal(service.vm.Config.DefaultBlockMaxConsumedUnits, reply.MaxUnits) + + service.vm.Config.DefaultBlockMaxConsumedUnits = commonfees.Dimensions{ + 123, + 456, + 789, + 1011, + } + + service.vm.ctx.Lock.Unlock() + + require.NoError(service.GetBlockUnitsCap(nil, nil, &reply)) + require.Equal(service.vm.Config.DefaultBlockMaxConsumedUnits, reply.MaxUnits) +} From e9c440bbac5fd63fe4a57949fe9c706d12d424d7 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 22 Jan 2024 13:45:11 +0100 Subject: [PATCH 055/190] wip: restructured fees calculator --- vms/platformvm/txs/builder/builder.go | 210 +++++++++--------- .../txs/executor/staker_tx_verification.go | 73 +++--- .../txs/executor/standard_tx_executor.go | 70 ++++-- vms/platformvm/txs/fees/calculator.go | 40 ++-- vms/platformvm/txs/fees/calculator_test.go | 135 ++++++----- vms/platformvm/utxo/handler_test.go | 8 +- 6 files changed, 308 insertions(+), 228 deletions(-) diff --git a/vms/platformvm/txs/builder/builder.go b/vms/platformvm/txs/builder/builder.go index 127dc58aeb4a..b45e250572c2 100644 --- a/vms/platformvm/txs/builder/builder.go +++ b/vms/platformvm/txs/builder/builder.go @@ -310,18 +310,18 @@ func (b *builder) NewImportTx( var ( ins []*avax.TransferableInput - importedAVAX = importedAmounts[b.ctx.AVAXAssetID] // the only entry left in importedAmounts - chainTime = b.state.GetTimestamp() + importedAVAX = importedAmounts[b.ctx.AVAXAssetID] // the only entry left in importedAmounts + chainTime = b.state.GetTimestamp() + isEForkActive = b.cfg.IsEForkActivated(chainTime) ) - if b.cfg.IsEForkActivated(chainTime) { + if isEForkActive { // while outs are not ordered we add them to get current fees. We'll fix ordering later on utx.BaseTx.Outs = outs - feesMan := commonfees.NewManager(b.cfg.DefaultUnitFees) feeCalc := &fees.Calculator{ - FeeManager: feesMan, - Config: b.cfg, - ChainTime: b.state.GetTimestamp(), - Credentials: txs.EmptyCredentials(signers), + IsEForkActive: isEForkActive, + FeeManager: commonfees.NewManager(b.cfg.DefaultUnitFees), + ConsumedUnitsCap: b.cfg.DefaultBlockMaxConsumedUnits, + Credentials: txs.EmptyCredentials(signers), } // feesMan cumulates consumed units. Let's init it with utx filled so far @@ -460,19 +460,19 @@ func (b *builder) NewExportTx( // 2. Finance the tx by building the utxos (inputs, outputs and stakes) var ( - chainTime = b.state.GetTimestamp() - ins []*avax.TransferableInput - outs []*avax.TransferableOutput - signers [][]*secp256k1.PrivateKey - err error + chainTime = b.state.GetTimestamp() + isEForkActive = b.cfg.IsEForkActivated(chainTime) + ins []*avax.TransferableInput + outs []*avax.TransferableOutput + signers [][]*secp256k1.PrivateKey + err error ) - if b.cfg.IsEForkActivated(chainTime) { - feesMan := commonfees.NewManager(b.cfg.DefaultUnitFees) + if isEForkActive { feeCalc := &fees.Calculator{ - FeeManager: feesMan, - Config: b.cfg, - ChainTime: b.state.GetTimestamp(), - Credentials: txs.EmptyCredentials(signers), + IsEForkActive: isEForkActive, + FeeManager: commonfees.NewManager(b.cfg.DefaultUnitFees), + ConsumedUnitsCap: b.cfg.DefaultBlockMaxConsumedUnits, + Credentials: txs.EmptyCredentials(signers), } // feesMan cumulates consumed units. Let's init it with utx filled so far @@ -542,18 +542,18 @@ func (b *builder) NewCreateChainTx( // 2. Finance the tx by building the utxos (inputs, outputs and stakes) var ( - chainTime = b.state.GetTimestamp() - ins []*avax.TransferableInput - outs []*avax.TransferableOutput - signers [][]*secp256k1.PrivateKey + chainTime = b.state.GetTimestamp() + isEForkActive = b.cfg.IsEForkActivated(chainTime) + ins []*avax.TransferableInput + outs []*avax.TransferableOutput + signers [][]*secp256k1.PrivateKey ) - if b.cfg.IsEForkActivated(chainTime) { - feesMan := commonfees.NewManager(b.cfg.DefaultUnitFees) + if isEForkActive { feeCalc := &fees.Calculator{ - FeeManager: feesMan, - Config: b.cfg, - ChainTime: b.state.GetTimestamp(), - Credentials: txs.EmptyCredentials(signers), + IsEForkActive: isEForkActive, + FeeManager: commonfees.NewManager(b.cfg.DefaultUnitFees), + ConsumedUnitsCap: b.cfg.DefaultBlockMaxConsumedUnits, + Credentials: txs.EmptyCredentials(signers), } // feesMan cumulates consumed units. Let's init it with utx filled so far @@ -611,19 +611,19 @@ func (b *builder) NewCreateSubnetTx( // 2. Finance the tx by building the utxos (inputs, outputs and stakes) var ( - chainTime = b.state.GetTimestamp() - ins []*avax.TransferableInput - outs []*avax.TransferableOutput - signers [][]*secp256k1.PrivateKey - err error + chainTime = b.state.GetTimestamp() + isEForkActive = b.cfg.IsEForkActivated(chainTime) + ins []*avax.TransferableInput + outs []*avax.TransferableOutput + signers [][]*secp256k1.PrivateKey + err error ) - if b.cfg.IsEForkActivated(chainTime) { - feesMan := commonfees.NewManager(b.cfg.DefaultUnitFees) + if isEForkActive { feeCalc := &fees.Calculator{ - FeeManager: feesMan, - Config: b.cfg, - ChainTime: b.state.GetTimestamp(), - Credentials: txs.EmptyCredentials(signers), + IsEForkActive: isEForkActive, + FeeManager: commonfees.NewManager(b.cfg.DefaultUnitFees), + ConsumedUnitsCap: b.cfg.DefaultBlockMaxConsumedUnits, + Credentials: txs.EmptyCredentials(signers), } // feesMan cumulates consumed units. Let's init it with utx filled so far @@ -689,20 +689,20 @@ func (b *builder) NewAddValidatorTx( // 2. Finance the tx by building the utxos (inputs, outputs and stakes) var ( - chainTime = b.state.GetTimestamp() - ins []*avax.TransferableInput - outs []*avax.TransferableOutput - stakedOuts []*avax.TransferableOutput - signers [][]*secp256k1.PrivateKey - err error + chainTime = b.state.GetTimestamp() + isEForkActive = b.cfg.IsEForkActivated(chainTime) + ins []*avax.TransferableInput + outs []*avax.TransferableOutput + stakedOuts []*avax.TransferableOutput + signers [][]*secp256k1.PrivateKey + err error ) - if b.cfg.IsEForkActivated(chainTime) { - feesMan := commonfees.NewManager(b.cfg.DefaultUnitFees) + if isEForkActive { feeCalc := &fees.Calculator{ - FeeManager: feesMan, - Config: b.cfg, - ChainTime: b.state.GetTimestamp(), - Credentials: txs.EmptyCredentials(signers), + IsEForkActive: isEForkActive, + FeeManager: commonfees.NewManager(b.cfg.DefaultUnitFees), + ConsumedUnitsCap: b.cfg.DefaultBlockMaxConsumedUnits, + Credentials: txs.EmptyCredentials(signers), } // feesMan cumulates consumed units. Let's init it with utx filled so far @@ -766,20 +766,20 @@ func (b *builder) NewAddDelegatorTx( // 2. Finance the tx by building the utxos (inputs, outputs and stakes) var ( - chainTime = b.state.GetTimestamp() - ins []*avax.TransferableInput - outs []*avax.TransferableOutput - stakedOuts []*avax.TransferableOutput - signers [][]*secp256k1.PrivateKey - err error + chainTime = b.state.GetTimestamp() + isEForkActive = b.cfg.IsEForkActivated(chainTime) + ins []*avax.TransferableInput + outs []*avax.TransferableOutput + stakedOuts []*avax.TransferableOutput + signers [][]*secp256k1.PrivateKey + err error ) - if b.cfg.IsEForkActivated(chainTime) { - feesMan := commonfees.NewManager(b.cfg.DefaultUnitFees) + if isEForkActive { feeCalc := &fees.Calculator{ - FeeManager: feesMan, - Config: b.cfg, - ChainTime: b.state.GetTimestamp(), - Credentials: txs.EmptyCredentials(signers), + IsEForkActive: isEForkActive, + FeeManager: commonfees.NewManager(b.cfg.DefaultUnitFees), + ConsumedUnitsCap: b.cfg.DefaultBlockMaxConsumedUnits, + Credentials: txs.EmptyCredentials(signers), } // feesMan cumulates consumed units. Let's init it with utx filled so far @@ -846,18 +846,18 @@ func (b *builder) NewAddSubnetValidatorTx( // 2. Finance the tx by building the utxos (inputs, outputs and stakes) var ( - chainTime = b.state.GetTimestamp() - ins []*avax.TransferableInput - outs []*avax.TransferableOutput - signers [][]*secp256k1.PrivateKey + chainTime = b.state.GetTimestamp() + isEForkActive = b.cfg.IsEForkActivated(chainTime) + ins []*avax.TransferableInput + outs []*avax.TransferableOutput + signers [][]*secp256k1.PrivateKey ) - if b.cfg.IsEForkActivated(chainTime) { - feesMan := commonfees.NewManager(b.cfg.DefaultUnitFees) + if isEForkActive { feeCalc := &fees.Calculator{ - FeeManager: feesMan, - Config: b.cfg, - ChainTime: b.state.GetTimestamp(), - Credentials: txs.EmptyCredentials(signers), + IsEForkActive: isEForkActive, + FeeManager: commonfees.NewManager(b.cfg.DefaultUnitFees), + ConsumedUnitsCap: b.cfg.DefaultBlockMaxConsumedUnits, + Credentials: txs.EmptyCredentials(signers), } // feesMan cumulates consumed units. Let's init it with utx filled so far @@ -914,18 +914,18 @@ func (b *builder) NewRemoveSubnetValidatorTx( // 2. Finance the tx by building the utxos (inputs, outputs and stakes) var ( - chainTime = b.state.GetTimestamp() - ins []*avax.TransferableInput - outs []*avax.TransferableOutput - signers [][]*secp256k1.PrivateKey + chainTime = b.state.GetTimestamp() + isEForkActive = b.cfg.IsEForkActivated(chainTime) + ins []*avax.TransferableInput + outs []*avax.TransferableOutput + signers [][]*secp256k1.PrivateKey ) - if b.cfg.IsEForkActivated(chainTime) { - feesMan := commonfees.NewManager(b.cfg.DefaultUnitFees) + if isEForkActive { feeCalc := &fees.Calculator{ - FeeManager: feesMan, - Config: b.cfg, - ChainTime: b.state.GetTimestamp(), - Credentials: txs.EmptyCredentials(signers), + IsEForkActive: isEForkActive, + FeeManager: commonfees.NewManager(b.cfg.DefaultUnitFees), + ConsumedUnitsCap: b.cfg.DefaultBlockMaxConsumedUnits, + Credentials: txs.EmptyCredentials(signers), } // feesMan cumulates consumed units. Let's init it with utx filled so far @@ -1005,18 +1005,18 @@ func (b *builder) NewTransferSubnetOwnershipTx( // 2. Finance the tx by building the utxos (inputs, outputs and stakes) var ( - chainTime = b.state.GetTimestamp() - ins []*avax.TransferableInput - outs []*avax.TransferableOutput - signers [][]*secp256k1.PrivateKey + chainTime = b.state.GetTimestamp() + isEForkActive = b.cfg.IsEForkActivated(chainTime) + ins []*avax.TransferableInput + outs []*avax.TransferableOutput + signers [][]*secp256k1.PrivateKey ) - if b.cfg.IsEForkActivated(chainTime) { - feesMan := commonfees.NewManager(b.cfg.DefaultUnitFees) + if isEForkActive { feeCalc := &fees.Calculator{ - FeeManager: feesMan, - Config: b.cfg, - ChainTime: b.state.GetTimestamp(), - Credentials: txs.EmptyCredentials(signers), + IsEForkActive: isEForkActive, + FeeManager: commonfees.NewManager(b.cfg.DefaultUnitFees), + ConsumedUnitsCap: b.cfg.DefaultBlockMaxConsumedUnits, + Credentials: txs.EmptyCredentials(signers), } // feesMan cumulates consumed units. Let's init it with utx filled so far @@ -1066,19 +1066,19 @@ func (b *builder) NewBaseTx( // 2. Finance the tx by building the utxos (inputs, outputs and stakes) var ( - chainTime = b.state.GetTimestamp() - ins []*avax.TransferableInput - outs []*avax.TransferableOutput - signers [][]*secp256k1.PrivateKey - err error + chainTime = b.state.GetTimestamp() + isEForkActive = b.cfg.IsEForkActivated(chainTime) + ins []*avax.TransferableInput + outs []*avax.TransferableOutput + signers [][]*secp256k1.PrivateKey + err error ) - if b.cfg.IsEForkActivated(chainTime) { - feesMan := commonfees.NewManager(b.cfg.DefaultUnitFees) + if isEForkActive { feeCalc := &fees.Calculator{ - FeeManager: feesMan, - Config: b.cfg, - ChainTime: b.state.GetTimestamp(), - Credentials: txs.EmptyCredentials(signers), + IsEForkActive: isEForkActive, + FeeManager: commonfees.NewManager(b.cfg.DefaultUnitFees), + ConsumedUnitsCap: b.cfg.DefaultBlockMaxConsumedUnits, + Credentials: txs.EmptyCredentials(signers), } // feesMan cumulates consumed units. Let's init it with utx filled so far diff --git a/vms/platformvm/txs/executor/staker_tx_verification.go b/vms/platformvm/txs/executor/staker_tx_verification.go index 76832480359f..f7c8de5f97f7 100644 --- a/vms/platformvm/txs/executor/staker_tx_verification.go +++ b/vms/platformvm/txs/executor/staker_tx_verification.go @@ -164,10 +164,12 @@ func verifyAddValidatorTx( // Verify the flowcheck feeCalculator := fees.Calculator{ - FeeManager: feeManager, - Config: backend.Config, - ChainTime: currentTimestamp, - Credentials: sTx.Creds, + IsEForkActive: backend.Config.IsEForkActivated(currentTimestamp), + Config: backend.Config, + ChainTime: currentTimestamp, + FeeManager: feeManager, + ConsumedUnitsCap: backend.Config.DefaultBlockMaxConsumedUnits, + Credentials: sTx.Creds, } if err := tx.Visit(&feeCalculator); err != nil { return nil, err @@ -261,10 +263,12 @@ func verifyAddSubnetValidatorTx( // Verify the flowcheck feeCalculator := fees.Calculator{ - FeeManager: feeManager, - Config: backend.Config, - ChainTime: currentTimestamp, - Credentials: sTx.Creds, + IsEForkActive: backend.Config.IsEForkActivated(currentTimestamp), + Config: backend.Config, + ChainTime: currentTimestamp, + FeeManager: feeManager, + ConsumedUnitsCap: backend.Config.DefaultBlockMaxConsumedUnits, + Credentials: sTx.Creds, } if err := tx.Visit(&feeCalculator); err != nil { return err @@ -340,11 +344,14 @@ func verifyRemoveSubnetValidatorTx( } // Verify the flowcheck + currentTimestamp := chainState.GetTimestamp() feeCalculator := fees.Calculator{ - FeeManager: feeManager, - Config: backend.Config, - ChainTime: chainState.GetTimestamp(), - Credentials: sTx.Creds, + IsEForkActive: backend.Config.IsEForkActivated(currentTimestamp), + Config: backend.Config, + ChainTime: currentTimestamp, + FeeManager: feeManager, + ConsumedUnitsCap: backend.Config.DefaultBlockMaxConsumedUnits, + Credentials: sTx.Creds, } if err := tx.Visit(&feeCalculator); err != nil { return nil, false, err @@ -464,10 +471,12 @@ func verifyAddDelegatorTx( // Verify the flowcheck feeCalculator := fees.Calculator{ - FeeManager: feeManager, - Config: backend.Config, - ChainTime: chainState.GetTimestamp(), - Credentials: sTx.Creds, + IsEForkActive: backend.Config.IsEForkActivated(currentTimestamp), + Config: backend.Config, + ChainTime: currentTimestamp, + FeeManager: feeManager, + ConsumedUnitsCap: backend.Config.DefaultBlockMaxConsumedUnits, + Credentials: sTx.Creds, } if err := tx.Visit(&feeCalculator); err != nil { return nil, err @@ -590,10 +599,12 @@ func verifyAddPermissionlessValidatorTx( // Verify the flowcheck feeCalculator := fees.Calculator{ - FeeManager: feeManager, - Config: backend.Config, - ChainTime: currentTimestamp, - Credentials: sTx.Creds, + IsEForkActive: backend.Config.IsEForkActivated(currentTimestamp), + Config: backend.Config, + ChainTime: currentTimestamp, + FeeManager: feeManager, + ConsumedUnitsCap: backend.Config.DefaultBlockMaxConsumedUnits, + Credentials: sTx.Creds, } if err := tx.Visit(&feeCalculator); err != nil { return err @@ -739,10 +750,12 @@ func verifyAddPermissionlessDelegatorTx( // Verify the flowcheck feeCalculator := fees.Calculator{ - FeeManager: feeManager, - Config: backend.Config, - ChainTime: currentTimestamp, - Credentials: sTx.Creds, + IsEForkActive: backend.Config.IsEForkActivated(currentTimestamp), + Config: backend.Config, + ChainTime: currentTimestamp, + FeeManager: feeManager, + ConsumedUnitsCap: backend.Config.DefaultBlockMaxConsumedUnits, + Credentials: sTx.Creds, } if err := tx.Visit(&feeCalculator); err != nil { return err @@ -798,12 +811,16 @@ func verifyTransferSubnetOwnershipTx( } // Verify the flowcheck + currentTimestamp := chainState.GetTimestamp() feeCalculator := fees.Calculator{ - FeeManager: feeManager, - Config: backend.Config, - ChainTime: chainState.GetTimestamp(), - Credentials: sTx.Creds, + IsEForkActive: backend.Config.IsEForkActivated(currentTimestamp), + Config: backend.Config, + ChainTime: currentTimestamp, + FeeManager: feeManager, + ConsumedUnitsCap: backend.Config.DefaultBlockMaxConsumedUnits, + Credentials: sTx.Creds, } + if err := tx.Visit(&feeCalculator); err != nil { return err } diff --git a/vms/platformvm/txs/executor/standard_tx_executor.go b/vms/platformvm/txs/executor/standard_tx_executor.go index 0abc86f9d099..b6ed02f3852b 100644 --- a/vms/platformvm/txs/executor/standard_tx_executor.go +++ b/vms/platformvm/txs/executor/standard_tx_executor.go @@ -64,11 +64,17 @@ func (e *StandardTxExecutor) CreateChainTx(tx *txs.CreateChainTx) error { } // Verify the flowcheck + var ( + cfg = e.Backend.Config + currentTimestamp = e.State.GetTimestamp() + ) feeCalculator := fees.Calculator{ - FeeManager: e.BlkFeeManager, - Config: e.Backend.Config, - ChainTime: e.State.GetTimestamp(), - Credentials: e.Tx.Creds, + IsEForkActive: cfg.IsEForkActivated(currentTimestamp), + Config: cfg, + ChainTime: currentTimestamp, + FeeManager: e.BlkFeeManager, + ConsumedUnitsCap: cfg.DefaultBlockMaxConsumedUnits, + Credentials: e.Tx.Creds, } if err := tx.Visit(&feeCalculator); err != nil { return err @@ -111,11 +117,17 @@ func (e *StandardTxExecutor) CreateSubnetTx(tx *txs.CreateSubnetTx) error { } // Verify the flowcheck + var ( + cfg = e.Backend.Config + currentTimestamp = e.State.GetTimestamp() + ) feeCalculator := fees.Calculator{ - FeeManager: e.BlkFeeManager, - Config: e.Backend.Config, - ChainTime: e.State.GetTimestamp(), - Credentials: e.Tx.Creds, + IsEForkActive: cfg.IsEForkActivated(currentTimestamp), + Config: cfg, + ChainTime: currentTimestamp, + FeeManager: e.BlkFeeManager, + ConsumedUnitsCap: cfg.DefaultBlockMaxConsumedUnits, + Credentials: e.Tx.Creds, } if err := tx.Visit(&feeCalculator); err != nil { return err @@ -193,11 +205,17 @@ func (e *StandardTxExecutor) ImportTx(tx *txs.ImportTx) error { copy(ins[len(tx.Ins):], tx.ImportedInputs) // Verify the flowcheck + var ( + cfg = e.Backend.Config + currentTimestamp = e.State.GetTimestamp() + ) feeCalculator := fees.Calculator{ - FeeManager: e.BlkFeeManager, - Config: e.Backend.Config, - ChainTime: e.State.GetTimestamp(), - Credentials: e.Tx.Creds, + IsEForkActive: cfg.IsEForkActivated(currentTimestamp), + Config: cfg, + ChainTime: currentTimestamp, + FeeManager: e.BlkFeeManager, + ConsumedUnitsCap: cfg.DefaultBlockMaxConsumedUnits, + Credentials: e.Tx.Creds, } if err := tx.Visit(&feeCalculator); err != nil { return err @@ -251,11 +269,17 @@ func (e *StandardTxExecutor) ExportTx(tx *txs.ExportTx) error { } // Verify the flowcheck + var ( + cfg = e.Backend.Config + currentTimestamp = e.State.GetTimestamp() + ) feeCalculator := fees.Calculator{ - FeeManager: e.BlkFeeManager, - Config: e.Backend.Config, - ChainTime: e.State.GetTimestamp(), - Credentials: e.Tx.Creds, + IsEForkActive: cfg.IsEForkActivated(currentTimestamp), + Config: cfg, + ChainTime: currentTimestamp, + FeeManager: e.BlkFeeManager, + ConsumedUnitsCap: cfg.DefaultBlockMaxConsumedUnits, + Credentials: e.Tx.Creds, } if err := tx.Visit(&feeCalculator); err != nil { return err @@ -561,11 +585,17 @@ func (e *StandardTxExecutor) BaseTx(tx *txs.BaseTx) error { } // Verify the flowcheck + var ( + cfg = e.Backend.Config + currentTimestamp = e.State.GetTimestamp() + ) feeCalculator := fees.Calculator{ - FeeManager: e.BlkFeeManager, - Config: e.Backend.Config, - ChainTime: e.State.GetTimestamp(), - Credentials: e.Tx.Creds, + IsEForkActive: cfg.IsEForkActivated(currentTimestamp), + Config: cfg, + ChainTime: currentTimestamp, + FeeManager: e.BlkFeeManager, + ConsumedUnitsCap: cfg.DefaultBlockMaxConsumedUnits, + Credentials: e.Tx.Creds, } if err := tx.Visit(&feeCalculator); err != nil { return err diff --git a/vms/platformvm/txs/fees/calculator.go b/vms/platformvm/txs/fees/calculator.go index 2173ed397ffa..139b04d58132 100644 --- a/vms/platformvm/txs/fees/calculator.go +++ b/vms/platformvm/txs/fees/calculator.go @@ -25,9 +25,15 @@ var ( type Calculator struct { // setup, to be filled before visitor methods are called - FeeManager *fees.Manager - Config *config.Config - ChainTime time.Time + IsEForkActive bool + + // Pre E-fork inputs + Config *config.Config + ChainTime time.Time + + // Post E-fork inputs + FeeManager *fees.Manager + ConsumedUnitsCap fees.Dimensions // inputs, to be filled before visitor methods are called Credentials []verify.Verifiable @@ -37,7 +43,7 @@ type Calculator struct { } func (fc *Calculator) AddValidatorTx(tx *txs.AddValidatorTx) error { - if !fc.Config.IsEForkActivated(fc.ChainTime) { + if !fc.IsEForkActive { fc.Fee = fc.Config.AddPrimaryNetworkValidatorFee return nil } @@ -55,7 +61,7 @@ func (fc *Calculator) AddValidatorTx(tx *txs.AddValidatorTx) error { } func (fc *Calculator) AddSubnetValidatorTx(tx *txs.AddSubnetValidatorTx) error { - if !fc.Config.IsEForkActivated(fc.ChainTime) { + if !fc.IsEForkActive { fc.Fee = fc.Config.AddSubnetValidatorFee return nil } @@ -69,7 +75,7 @@ func (fc *Calculator) AddSubnetValidatorTx(tx *txs.AddSubnetValidatorTx) error { } func (fc *Calculator) AddDelegatorTx(tx *txs.AddDelegatorTx) error { - if !fc.Config.IsEForkActivated(fc.ChainTime) { + if !fc.IsEForkActive { fc.Fee = fc.Config.AddPrimaryNetworkDelegatorFee return nil } @@ -87,7 +93,7 @@ func (fc *Calculator) AddDelegatorTx(tx *txs.AddDelegatorTx) error { } func (fc *Calculator) CreateChainTx(tx *txs.CreateChainTx) error { - if !fc.Config.IsEForkActivated(fc.ChainTime) { + if !fc.IsEForkActive { fc.Fee = fc.Config.GetCreateBlockchainTxFee(fc.ChainTime) return nil } @@ -101,7 +107,7 @@ func (fc *Calculator) CreateChainTx(tx *txs.CreateChainTx) error { } func (fc *Calculator) CreateSubnetTx(tx *txs.CreateSubnetTx) error { - if !fc.Config.IsEForkActivated(fc.ChainTime) { + if !fc.IsEForkActive { fc.Fee = fc.Config.GetCreateSubnetTxFee(fc.ChainTime) return nil } @@ -123,7 +129,7 @@ func (*Calculator) RewardValidatorTx(*txs.RewardValidatorTx) error { } func (fc *Calculator) RemoveSubnetValidatorTx(tx *txs.RemoveSubnetValidatorTx) error { - if !fc.Config.IsEForkActivated(fc.ChainTime) { + if !fc.IsEForkActive { fc.Fee = fc.Config.TxFee return nil } @@ -137,7 +143,7 @@ func (fc *Calculator) RemoveSubnetValidatorTx(tx *txs.RemoveSubnetValidatorTx) e } func (fc *Calculator) TransformSubnetTx(tx *txs.TransformSubnetTx) error { - if !fc.Config.IsEForkActivated(fc.ChainTime) { + if !fc.IsEForkActive { fc.Fee = fc.Config.TransformSubnetTxFee return nil } @@ -151,7 +157,7 @@ func (fc *Calculator) TransformSubnetTx(tx *txs.TransformSubnetTx) error { } func (fc *Calculator) TransferSubnetOwnershipTx(tx *txs.TransferSubnetOwnershipTx) error { - if !fc.Config.IsEForkActivated(fc.ChainTime) { + if !fc.IsEForkActive { fc.Fee = fc.Config.TxFee return nil } @@ -165,7 +171,7 @@ func (fc *Calculator) TransferSubnetOwnershipTx(tx *txs.TransferSubnetOwnershipT } func (fc *Calculator) AddPermissionlessValidatorTx(tx *txs.AddPermissionlessValidatorTx) error { - if !fc.Config.IsEForkActivated(fc.ChainTime) { + if !fc.IsEForkActive { if tx.Subnet != constants.PrimaryNetworkID { fc.Fee = fc.Config.AddSubnetValidatorFee } else { @@ -187,7 +193,7 @@ func (fc *Calculator) AddPermissionlessValidatorTx(tx *txs.AddPermissionlessVali } func (fc *Calculator) AddPermissionlessDelegatorTx(tx *txs.AddPermissionlessDelegatorTx) error { - if !fc.Config.IsEForkActivated(fc.ChainTime) { + if !fc.IsEForkActive { if tx.Subnet != constants.PrimaryNetworkID { fc.Fee = fc.Config.AddSubnetDelegatorFee } else { @@ -209,7 +215,7 @@ func (fc *Calculator) AddPermissionlessDelegatorTx(tx *txs.AddPermissionlessDele } func (fc *Calculator) BaseTx(tx *txs.BaseTx) error { - if !fc.Config.IsEForkActivated(fc.ChainTime) { + if !fc.IsEForkActive { fc.Fee = fc.Config.TxFee return nil } @@ -223,7 +229,7 @@ func (fc *Calculator) BaseTx(tx *txs.BaseTx) error { } func (fc *Calculator) ImportTx(tx *txs.ImportTx) error { - if !fc.Config.IsEForkActivated(fc.ChainTime) { + if !fc.IsEForkActive { fc.Fee = fc.Config.TxFee return nil } @@ -241,7 +247,7 @@ func (fc *Calculator) ImportTx(tx *txs.ImportTx) error { } func (fc *Calculator) ExportTx(tx *txs.ExportTx) error { - if !fc.Config.IsEForkActivated(fc.ChainTime) { + if !fc.IsEForkActive { fc.Fee = fc.Config.TxFee return nil } @@ -299,7 +305,7 @@ func (fc *Calculator) commonConsumedUnits( } func (fc *Calculator) AddFeesFor(consumedUnits fees.Dimensions) error { - boundBreached, dimension := fc.FeeManager.CumulateUnits(consumedUnits, fc.Config.BlockMaxConsumedUnits(fc.ChainTime)) + boundBreached, dimension := fc.FeeManager.CumulateUnits(consumedUnits, fc.ConsumedUnitsCap) if boundBreached { return fmt.Errorf("%w: breached dimension %d", errFailedConsumedUnitsCumulation, dimension) } diff --git a/vms/platformvm/txs/fees/calculator_test.go b/vms/platformvm/txs/fees/calculator_test.go index fed70539c207..e2ce019d0798 100644 --- a/vms/platformvm/txs/fees/calculator_test.go +++ b/vms/platformvm/txs/fees/calculator_test.go @@ -121,8 +121,9 @@ func TestAddAndRemoveFees(t *testing.T) { r := require.New(t) fc := &Calculator{ - FeeManager: fees.NewManager(feeTestsDefaultCfg.DefaultUnitFees), - Config: &feeTestsDefaultCfg, + IsEForkActive: true, + FeeManager: fees.NewManager(feeTestsDefaultCfg.DefaultUnitFees), + ConsumedUnitsCap: feeTestsDefaultCfg.DefaultBlockMaxConsumedUnits, } units := fees.Dimensions{ @@ -309,10 +310,12 @@ func TestAddValidatorTxFees(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() fc := &Calculator{ - FeeManager: fees.NewManager(cfg.DefaultUnitFees), - Config: cfg, - ChainTime: chainTime, - Credentials: sTx.Creds, + IsEForkActive: cfg.IsEForkActivated(chainTime), + Config: cfg, + ChainTime: chainTime, + FeeManager: fees.NewManager(cfg.DefaultUnitFees), + ConsumedUnitsCap: cfg.DefaultBlockMaxConsumedUnits, + Credentials: sTx.Creds, } err := uTx.Visit(fc) r.ErrorIs(err, tt.expectedError) @@ -411,10 +414,12 @@ func TestAddSubnetValidatorTxFees(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() fc := &Calculator{ - FeeManager: fees.NewManager(cfg.DefaultUnitFees), - Config: cfg, - ChainTime: chainTime, - Credentials: sTx.Creds, + IsEForkActive: cfg.IsEForkActivated(chainTime), + Config: cfg, + ChainTime: chainTime, + FeeManager: fees.NewManager(cfg.DefaultUnitFees), + ConsumedUnitsCap: cfg.DefaultBlockMaxConsumedUnits, + Credentials: sTx.Creds, } err := uTx.Visit(fc) r.ErrorIs(err, tt.expectedError) @@ -514,10 +519,12 @@ func TestAddDelegatorTxFees(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() fc := &Calculator{ - FeeManager: fees.NewManager(cfg.DefaultUnitFees), - Config: cfg, - ChainTime: chainTime, - Credentials: sTx.Creds, + IsEForkActive: cfg.IsEForkActivated(chainTime), + Config: cfg, + ChainTime: chainTime, + FeeManager: fees.NewManager(cfg.DefaultUnitFees), + ConsumedUnitsCap: cfg.DefaultBlockMaxConsumedUnits, + Credentials: sTx.Creds, } err := uTx.Visit(fc) r.ErrorIs(err, tt.expectedError) @@ -611,10 +618,12 @@ func TestCreateChainTxFees(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() fc := &Calculator{ - FeeManager: fees.NewManager(cfg.DefaultUnitFees), - Config: cfg, - ChainTime: chainTime, - Credentials: sTx.Creds, + IsEForkActive: cfg.IsEForkActivated(chainTime), + Config: cfg, + ChainTime: chainTime, + FeeManager: fees.NewManager(cfg.DefaultUnitFees), + ConsumedUnitsCap: cfg.DefaultBlockMaxConsumedUnits, + Credentials: sTx.Creds, } err := uTx.Visit(fc) r.ErrorIs(err, tt.expectedError) @@ -706,10 +715,12 @@ func TestCreateSubnetTxFees(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() fc := &Calculator{ - FeeManager: fees.NewManager(cfg.DefaultUnitFees), - Config: cfg, - ChainTime: chainTime, - Credentials: sTx.Creds, + IsEForkActive: cfg.IsEForkActivated(chainTime), + Config: cfg, + ChainTime: chainTime, + FeeManager: fees.NewManager(cfg.DefaultUnitFees), + ConsumedUnitsCap: cfg.DefaultBlockMaxConsumedUnits, + Credentials: sTx.Creds, } err := uTx.Visit(fc) r.ErrorIs(err, tt.expectedError) @@ -800,10 +811,12 @@ func TestRemoveSubnetValidatorTxFees(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() fc := &Calculator{ - FeeManager: fees.NewManager(cfg.DefaultUnitFees), - Config: cfg, - ChainTime: chainTime, - Credentials: sTx.Creds, + IsEForkActive: cfg.IsEForkActivated(chainTime), + Config: cfg, + ChainTime: chainTime, + FeeManager: fees.NewManager(cfg.DefaultUnitFees), + ConsumedUnitsCap: cfg.DefaultBlockMaxConsumedUnits, + Credentials: sTx.Creds, } err := uTx.Visit(fc) r.ErrorIs(err, tt.expectedError) @@ -906,10 +919,12 @@ func TestTransformSubnetTxFees(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() fc := &Calculator{ - FeeManager: fees.NewManager(cfg.DefaultUnitFees), - Config: cfg, - ChainTime: chainTime, - Credentials: sTx.Creds, + IsEForkActive: cfg.IsEForkActivated(chainTime), + Config: cfg, + ChainTime: chainTime, + FeeManager: fees.NewManager(cfg.DefaultUnitFees), + ConsumedUnitsCap: cfg.DefaultBlockMaxConsumedUnits, + Credentials: sTx.Creds, } err := uTx.Visit(fc) r.ErrorIs(err, tt.expectedError) @@ -1008,10 +1023,12 @@ func TestTransferSubnetOwnershipTxFees(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() fc := &Calculator{ - FeeManager: fees.NewManager(cfg.DefaultUnitFees), - Config: cfg, - ChainTime: chainTime, - Credentials: sTx.Creds, + IsEForkActive: cfg.IsEForkActivated(chainTime), + Config: cfg, + ChainTime: chainTime, + FeeManager: fees.NewManager(cfg.DefaultUnitFees), + ConsumedUnitsCap: cfg.DefaultBlockMaxConsumedUnits, + Credentials: sTx.Creds, } err := uTx.Visit(fc) r.ErrorIs(err, tt.expectedError) @@ -1119,10 +1136,12 @@ func TestAddPermissionlessValidatorTxFees(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() fc := &Calculator{ - FeeManager: fees.NewManager(cfg.DefaultUnitFees), - Config: cfg, - ChainTime: chainTime, - Credentials: sTx.Creds, + IsEForkActive: cfg.IsEForkActivated(chainTime), + Config: cfg, + ChainTime: chainTime, + FeeManager: fees.NewManager(cfg.DefaultUnitFees), + ConsumedUnitsCap: cfg.DefaultBlockMaxConsumedUnits, + Credentials: sTx.Creds, } err := uTx.Visit(fc) r.ErrorIs(err, tt.expectedError) @@ -1225,10 +1244,12 @@ func TestAddPermissionlessDelegatorTxFees(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() fc := &Calculator{ - FeeManager: fees.NewManager(cfg.DefaultUnitFees), - Config: cfg, - ChainTime: chainTime, - Credentials: sTx.Creds, + IsEForkActive: cfg.IsEForkActivated(chainTime), + Config: cfg, + ChainTime: chainTime, + FeeManager: fees.NewManager(cfg.DefaultUnitFees), + ConsumedUnitsCap: cfg.DefaultBlockMaxConsumedUnits, + Credentials: sTx.Creds, } err := uTx.Visit(fc) r.ErrorIs(err, tt.expectedError) @@ -1314,10 +1335,12 @@ func TestBaseTxFees(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() fc := &Calculator{ - FeeManager: fees.NewManager(cfg.DefaultUnitFees), - Config: cfg, - ChainTime: chainTime, - Credentials: sTx.Creds, + IsEForkActive: cfg.IsEForkActivated(chainTime), + Config: cfg, + ChainTime: chainTime, + FeeManager: fees.NewManager(cfg.DefaultUnitFees), + ConsumedUnitsCap: cfg.DefaultBlockMaxConsumedUnits, + Credentials: sTx.Creds, } err := uTx.Visit(fc) r.ErrorIs(err, tt.expectedError) @@ -1417,10 +1440,12 @@ func TestImportTxFees(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() fc := &Calculator{ - FeeManager: fees.NewManager(cfg.DefaultUnitFees), - Config: cfg, - ChainTime: chainTime, - Credentials: sTx.Creds, + IsEForkActive: cfg.IsEForkActivated(chainTime), + Config: cfg, + ChainTime: chainTime, + FeeManager: fees.NewManager(cfg.DefaultUnitFees), + ConsumedUnitsCap: cfg.DefaultBlockMaxConsumedUnits, + Credentials: sTx.Creds, } err := uTx.Visit(fc) r.ErrorIs(err, tt.expectedError) @@ -1510,10 +1535,12 @@ func TestExportTxFees(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() fc := &Calculator{ - FeeManager: fees.NewManager(cfg.DefaultUnitFees), - Config: cfg, - ChainTime: chainTime, - Credentials: sTx.Creds, + IsEForkActive: cfg.IsEForkActivated(chainTime), + Config: cfg, + ChainTime: chainTime, + FeeManager: fees.NewManager(cfg.DefaultUnitFees), + ConsumedUnitsCap: cfg.DefaultBlockMaxConsumedUnits, + Credentials: sTx.Creds, } err := uTx.Visit(fc) r.ErrorIs(err, tt.expectedError) diff --git a/vms/platformvm/utxo/handler_test.go b/vms/platformvm/utxo/handler_test.go index 476548bd9aed..1c8168f1689a 100644 --- a/vms/platformvm/utxo/handler_test.go +++ b/vms/platformvm/utxo/handler_test.go @@ -632,10 +632,10 @@ func TestVerifyFinanceTx(t *testing.T) { fm := commonfees.NewManager(cfg.DefaultUnitFees) feeCalc := &fees.Calculator{ - FeeManager: fm, - Config: cfg, - ChainTime: time.Time{}, - Credentials: []verify.Verifiable{}, + IsEForkActive: true, + FeeManager: fm, + ConsumedUnitsCap: cfg.DefaultBlockMaxConsumedUnits, + Credentials: []verify.Verifiable{}, } // init fee calc with the uTx data From b41754617e53a192a64ecf3162338e7293c5fc54 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 22 Jan 2024 14:40:40 +0100 Subject: [PATCH 056/190] wip: moving multidimensional fees configs to state --- vms/platformvm/block/builder/builder.go | 7 +- vms/platformvm/block/builder/helpers_test.go | 5 +- vms/platformvm/block/executor/helpers_test.go | 7 +- .../block/executor/proposal_block_test.go | 2 + .../block/executor/standard_block_test.go | 4 +- vms/platformvm/block/executor/verifier.go | 8 +- .../block/executor/verifier_test.go | 3 + vms/platformvm/config/config.go | 21 -- vms/platformvm/service.go | 10 +- vms/platformvm/service_test.go | 20 +- vms/platformvm/state/diff.go | 17 ++ vms/platformvm/state/mock_state.go | 119 +++++++++ vms/platformvm/state/state.go | 32 +++ vms/platformvm/txs/builder/builder.go | 180 ++++++++++++-- .../txs/executor/atomic_tx_executor.go | 6 +- .../txs/executor/create_chain_test.go | 14 +- .../txs/executor/create_subnet_test.go | 6 +- vms/platformvm/txs/executor/helpers_test.go | 5 +- .../txs/executor/proposal_tx_executor.go | 9 +- .../txs/executor/staker_tx_verification.go | 21 +- .../executor/staker_tx_verification_test.go | 8 +- .../txs/executor/standard_tx_executor.go | 18 +- .../txs/executor/standard_tx_executor_test.go | 68 ++--- .../txs/executor/tx_mempool_verifier.go | 7 +- vms/platformvm/txs/fees/calculator.go | 19 ++ vms/platformvm/txs/fees/calculator_test.go | 234 +++++++++++++----- vms/platformvm/utxo/handler_test.go | 29 +-- 27 files changed, 687 insertions(+), 192 deletions(-) diff --git a/vms/platformvm/block/builder/builder.go b/vms/platformvm/block/builder/builder.go index 82f92076a91c..daafbf296b68 100644 --- a/vms/platformvm/block/builder/builder.go +++ b/vms/platformvm/block/builder/builder.go @@ -378,9 +378,14 @@ func packBlockTxs( return nil, err } + unitFees, err := txDiff.GetUnitFees() + if err != nil { + return nil, err + } + executor := &txexecutor.StandardTxExecutor{ Backend: backend, - BlkFeeManager: fees.NewManager(backend.Config.DefaultUnitFees), + BlkFeeManager: fees.NewManager(unitFees), State: txDiff, Tx: tx, } diff --git a/vms/platformvm/block/builder/helpers_test.go b/vms/platformvm/block/builder/helpers_test.go index 6ea35f262b31..f7d56b9e1f20 100644 --- a/vms/platformvm/block/builder/helpers_test.go +++ b/vms/platformvm/block/builder/helpers_test.go @@ -237,9 +237,12 @@ func addSubnet(t *testing.T, env *environment) { stateDiff, err := state.NewDiff(genesisID, env.blkManager) require.NoError(err) + unitFees, err := env.state.GetUnitFees() + require.NoError(err) + executor := txexecutor.StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitFees), + BlkFeeManager: fees.NewManager(unitFees), State: stateDiff, Tx: testSubnet1, } diff --git a/vms/platformvm/block/executor/helpers_test.go b/vms/platformvm/block/executor/helpers_test.go index 61871f0b36c1..3195dee9083f 100644 --- a/vms/platformvm/block/executor/helpers_test.go +++ b/vms/platformvm/block/executor/helpers_test.go @@ -248,9 +248,14 @@ func addSubnet(env *environment) { panic(err) } + unitFees, err := env.state.GetUnitFees() + if err != nil { + panic(err) + } + executor := executor.StandardTxExecutor{ Backend: env.backend, - BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitFees), + BlkFeeManager: fees.NewManager(unitFees), State: stateDiff, Tx: testSubnet1, } diff --git a/vms/platformvm/block/executor/proposal_block_test.go b/vms/platformvm/block/executor/proposal_block_test.go index 549a3fbe25df..f6b9570da4a9 100644 --- a/vms/platformvm/block/executor/proposal_block_test.go +++ b/vms/platformvm/block/executor/proposal_block_test.go @@ -26,6 +26,7 @@ import ( "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/fees" "github.com/ava-labs/avalanchego/vms/secp256k1fx" ) @@ -173,6 +174,7 @@ func TestBanffProposalBlockTimeVerification(t *testing.T) { onParentAccept := state.NewMockDiff(ctrl) onParentAccept.EXPECT().GetTimestamp().Return(parentTime).AnyTimes() + onParentAccept.EXPECT().GetUnitFees().Return(fees.EmptyUnitFees, 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 435ee6618af0..1c5f62524492 100644 --- a/vms/platformvm/block/executor/standard_block_test.go +++ b/vms/platformvm/block/executor/standard_block_test.go @@ -23,6 +23,7 @@ import ( "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/fees" "github.com/ava-labs/avalanchego/vms/secp256k1fx" ) @@ -59,7 +60,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().GetUnitFees().Return(fees.EmptyUnitFees, nil).AnyTimes() // wrong height apricotChildBlk, err := block.NewApricotStandardBlock( apricotParentBlk.ID(), @@ -156,6 +157,7 @@ func TestBanffStandardBlockTimeVerification(t *testing.T) { } utxoID := utxo.InputID() onParentAccept.EXPECT().GetUTXO(utxoID).Return(utxo, nil).AnyTimes() + onParentAccept.EXPECT().GetUnitFees().Return(fees.EmptyUnitFees, 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 61e527608561..003bfd1ba80a 100644 --- a/vms/platformvm/block/executor/verifier.go +++ b/vms/platformvm/block/executor/verifier.go @@ -456,8 +456,14 @@ func (v *verifier) processStandardTxs(txs []*txs.Tx, state state.Diff, parentID inputs set.Set[ids.ID] funcs = make([]func(), 0, len(txs)) atomicRequests = make(map[ids.ID]*atomic.Requests) - feeManager = fees.NewManager(v.txExecutorBackend.Config.DefaultUnitFees) ) + + unitFees, err := state.GetUnitFees() + if err != nil { + return nil, nil, nil, err + } + feeManager := fees.NewManager(unitFees) + for _, tx := range txs { txExecutor := executor.StandardTxExecutor{ Backend: v.txExecutorBackend, diff --git a/vms/platformvm/block/executor/verifier_test.go b/vms/platformvm/block/executor/verifier_test.go index ccac3da3b7e3..7a4fab27d81e 100644 --- a/vms/platformvm/block/executor/verifier_test.go +++ b/vms/platformvm/block/executor/verifier_test.go @@ -26,6 +26,7 @@ import ( "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/fees" "github.com/ava-labs/avalanchego/vms/platformvm/txs/mempool" ) @@ -285,6 +286,7 @@ func TestVerifierVisitStandardBlock(t *testing.T) { // Set expectations for dependencies. timestamp := time.Now() parentState.EXPECT().GetTimestamp().Return(timestamp).Times(1) + parentState.EXPECT().GetUnitFees().Return(fees.EmptyUnitFees, nil) parentStatelessBlk.EXPECT().Height().Return(uint64(1)).Times(1) mempool.EXPECT().Remove(apricotBlk.Txs()).Times(1) @@ -764,6 +766,7 @@ func TestVerifierVisitStandardBlockWithDuplicateInputs(t *testing.T) { timestamp := time.Now() parentStatelessBlk.EXPECT().Height().Return(uint64(1)).Times(1) parentState.EXPECT().GetTimestamp().Return(timestamp).Times(1) + parentState.EXPECT().GetUnitFees().Return(fees.EmptyUnitFees, nil) parentStatelessBlk.EXPECT().Parent().Return(grandParentID).Times(1) err = verifier.ApricotStandardBlock(blk) diff --git a/vms/platformvm/config/config.go b/vms/platformvm/config/config.go index a61be143c3ac..aca79f446024 100644 --- a/vms/platformvm/config/config.go +++ b/vms/platformvm/config/config.go @@ -4,7 +4,6 @@ package config import ( - "math" "time" "github.com/ava-labs/avalanchego/chains" @@ -13,7 +12,6 @@ import ( "github.com/ava-labs/avalanchego/snow/validators" "github.com/ava-labs/avalanchego/utils/constants" "github.com/ava-labs/avalanchego/utils/set" - "github.com/ava-labs/avalanchego/vms/components/fees" "github.com/ava-labs/avalanchego/vms/platformvm/reward" "github.com/ava-labs/avalanchego/vms/platformvm/txs" ) @@ -43,14 +41,6 @@ type Config struct { // Set of subnets that this node is validating TrackedSubnets set.Set[ids.ID] - // Post E Fork, the unit fee for each dimension, denominated in Avax - // As long as fees are multidimensional but not dynamic, [DefaultUnitFees] - // will be the unit fees - DefaultUnitFees fees.Dimensions - - // Post E Fork, the max complexity of a block for each dimension - DefaultBlockMaxConsumedUnits fees.Dimensions - // Pre E Fork, fee that is burned by every non-state creating transaction TxFee uint64 @@ -187,14 +177,3 @@ func (c *Config) CreateChain(chainID ids.ID, tx *txs.CreateChainTx) { c.Chains.QueueChainCreation(chainParams) } - -func (c *Config) BlockMaxConsumedUnits(timestamp time.Time) fees.Dimensions { - if !c.IsEForkActivated(timestamp) { - var res fees.Dimensions - for i := fees.Dimension(0); i < fees.FeeDimensions; i++ { - res[i] = math.MaxUint64 - } - return res - } - return c.DefaultBlockMaxConsumedUnits -} diff --git a/vms/platformvm/service.go b/vms/platformvm/service.go index 6df95b035ddc..2a211dd738f6 100644 --- a/vms/platformvm/service.go +++ b/vms/platformvm/service.go @@ -2827,8 +2827,9 @@ func (s *Service) GetUnitFees(_ *http.Request, _ *struct{}, reply *GetUnitFeesRe s.vm.ctx.Lock.Lock() defer s.vm.ctx.Lock.Unlock() - reply.UnitFees = s.vm.DefaultUnitFees - return nil + var err error + reply.UnitFees, err = s.vm.state.GetUnitFees() + return err } // GetBlockUnitsCapReply is the response from GetBlockUnitsCap @@ -2847,8 +2848,9 @@ func (s *Service) GetBlockUnitsCap(_ *http.Request, _ *struct{}, reply *GetBlock s.vm.ctx.Lock.Lock() defer s.vm.ctx.Lock.Unlock() - reply.MaxUnits = s.vm.DefaultBlockMaxConsumedUnits - return nil + var err error + reply.MaxUnits, err = s.vm.state.GetBlockUnitCaps() + return err } func (s *Service) getAPIUptime(staker *state.Staker) (*json.Float32, error) { diff --git a/vms/platformvm/service_test.go b/vms/platformvm/service_test.go index 554ae3a3e31b..78b62496fd52 100644 --- a/vms/platformvm/service_test.go +++ b/vms/platformvm/service_test.go @@ -1073,19 +1073,23 @@ func TestGetUnitFees(t *testing.T) { service.vm.ctx.Lock.Lock() - require.Equal(service.vm.Config.DefaultUnitFees, reply.UnitFees) + unitFees, err := service.vm.state.GetUnitFees() + require.NoError(err) + + require.Equal(unitFees, reply.UnitFees) - service.vm.Config.DefaultUnitFees = commonfees.Dimensions{ + updatedUnitFees := commonfees.Dimensions{ 123, 456, 789, 1011, } + require.NoError(service.vm.state.SetUnitFees(updatedUnitFees)) service.vm.ctx.Lock.Unlock() require.NoError(service.GetUnitFees(nil, nil, &reply)) - require.Equal(service.vm.Config.DefaultUnitFees, reply.UnitFees) + require.Equal(updatedUnitFees, reply.UnitFees) } func TestGetBlockUnitsCap(t *testing.T) { @@ -1102,17 +1106,21 @@ func TestGetBlockUnitsCap(t *testing.T) { service.vm.ctx.Lock.Lock() - require.Equal(service.vm.Config.DefaultBlockMaxConsumedUnits, reply.MaxUnits) + unitCaps, err := service.vm.state.GetBlockUnitCaps() + require.NoError(err) + + require.Equal(unitCaps, reply.MaxUnits) - service.vm.Config.DefaultBlockMaxConsumedUnits = commonfees.Dimensions{ + updatedUnitCaps := commonfees.Dimensions{ 123, 456, 789, 1011, } + require.NoError(service.vm.state.SetBlockUnitCaps(updatedUnitCaps)) service.vm.ctx.Lock.Unlock() require.NoError(service.GetBlockUnitsCap(nil, nil, &reply)) - require.Equal(service.vm.Config.DefaultBlockMaxConsumedUnits, reply.MaxUnits) + require.Equal(updatedUnitCaps, reply.MaxUnits) } diff --git a/vms/platformvm/state/diff.go b/vms/platformvm/state/diff.go index 907c3c56ef7d..d6fa41fcbe01 100644 --- a/vms/platformvm/state/diff.go +++ b/vms/platformvm/state/diff.go @@ -11,6 +11,7 @@ import ( "github.com/ava-labs/avalanchego/database" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/vms/components/avax" + commonfees "github.com/ava-labs/avalanchego/vms/components/fees" "github.com/ava-labs/avalanchego/vms/platformvm/fx" "github.com/ava-labs/avalanchego/vms/platformvm/status" "github.com/ava-labs/avalanchego/vms/platformvm/txs" @@ -89,6 +90,22 @@ func NewDiffOn(parentState Chain) (Diff, error) { }) } +func (d *diff) GetUnitFees() (commonfees.Dimensions, error) { + parentState, ok := d.stateVersions.GetState(d.parentID) + if !ok { + return commonfees.Dimensions{}, fmt.Errorf("%w: %s", ErrMissingParentState, d.parentID) + } + return parentState.GetUnitFees() +} + +func (d *diff) GetBlockUnitCaps() (commonfees.Dimensions, error) { + parentState, ok := d.stateVersions.GetState(d.parentID) + if !ok { + return commonfees.Dimensions{}, fmt.Errorf("%w: %s", ErrMissingParentState, d.parentID) + } + return parentState.GetBlockUnitCaps() +} + func (d *diff) GetTimestamp() time.Time { return d.timestamp } diff --git a/vms/platformvm/state/mock_state.go b/vms/platformvm/state/mock_state.go index cfb9dd16944a..573127bdbe32 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" + fees "github.com/ava-labs/avalanchego/vms/components/fees" 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" @@ -182,6 +183,21 @@ func (mr *MockChainMockRecorder) DeleteUTXO(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteUTXO", reflect.TypeOf((*MockChain)(nil).DeleteUTXO), arg0) } +// GetBlockUnitCaps mocks base method. +func (m *MockChain) GetBlockUnitCaps() (fees.Dimensions, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetBlockUnitCaps") + ret0, _ := ret[0].(fees.Dimensions) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetBlockUnitCaps indicates an expected call of GetBlockUnitCaps. +func (mr *MockChainMockRecorder) GetBlockUnitCaps() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBlockUnitCaps", reflect.TypeOf((*MockChain)(nil).GetBlockUnitCaps)) +} + // GetCurrentDelegatorIterator mocks base method. func (m *MockChain) GetCurrentDelegatorIterator(arg0 ids.ID, arg1 ids.NodeID) (StakerIterator, error) { m.ctrl.T.Helper() @@ -377,6 +393,21 @@ func (mr *MockChainMockRecorder) GetUTXO(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUTXO", reflect.TypeOf((*MockChain)(nil).GetUTXO), arg0) } +// GetUnitFees mocks base method. +func (m *MockChain) GetUnitFees() (fees.Dimensions, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetUnitFees") + ret0, _ := ret[0].(fees.Dimensions) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetUnitFees indicates an expected call of GetUnitFees. +func (mr *MockChainMockRecorder) GetUnitFees() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUnitFees", reflect.TypeOf((*MockChain)(nil).GetUnitFees)) +} + // PutCurrentDelegator mocks base method. func (m *MockChain) PutCurrentDelegator(arg0 *Staker) { m.ctrl.T.Helper() @@ -644,6 +675,21 @@ func (mr *MockDiffMockRecorder) DeleteUTXO(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteUTXO", reflect.TypeOf((*MockDiff)(nil).DeleteUTXO), arg0) } +// GetBlockUnitCaps mocks base method. +func (m *MockDiff) GetBlockUnitCaps() (fees.Dimensions, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetBlockUnitCaps") + ret0, _ := ret[0].(fees.Dimensions) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetBlockUnitCaps indicates an expected call of GetBlockUnitCaps. +func (mr *MockDiffMockRecorder) GetBlockUnitCaps() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBlockUnitCaps", reflect.TypeOf((*MockDiff)(nil).GetBlockUnitCaps)) +} + // GetCurrentDelegatorIterator mocks base method. func (m *MockDiff) GetCurrentDelegatorIterator(arg0 ids.ID, arg1 ids.NodeID) (StakerIterator, error) { m.ctrl.T.Helper() @@ -839,6 +885,21 @@ func (mr *MockDiffMockRecorder) GetUTXO(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUTXO", reflect.TypeOf((*MockDiff)(nil).GetUTXO), arg0) } +// GetUnitFees mocks base method. +func (m *MockDiff) GetUnitFees() (fees.Dimensions, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetUnitFees") + ret0, _ := ret[0].(fees.Dimensions) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetUnitFees indicates an expected call of GetUnitFees. +func (mr *MockDiffMockRecorder) GetUnitFees() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUnitFees", reflect.TypeOf((*MockDiff)(nil).GetUnitFees)) +} + // PutCurrentDelegator mocks base method. func (m *MockDiff) PutCurrentDelegator(arg0 *Staker) { m.ctrl.T.Helper() @@ -1216,6 +1277,21 @@ func (mr *MockStateMockRecorder) GetBlockIDAtHeight(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBlockIDAtHeight", reflect.TypeOf((*MockState)(nil).GetBlockIDAtHeight), arg0) } +// GetBlockUnitCaps mocks base method. +func (m *MockState) GetBlockUnitCaps() (fees.Dimensions, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetBlockUnitCaps") + ret0, _ := ret[0].(fees.Dimensions) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetBlockUnitCaps indicates an expected call of GetBlockUnitCaps. +func (mr *MockStateMockRecorder) GetBlockUnitCaps() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBlockUnitCaps", reflect.TypeOf((*MockState)(nil).GetBlockUnitCaps)) +} + // GetChains mocks base method. func (m *MockState) GetChains(arg0 ids.ID) ([]*txs.Tx, error) { m.ctrl.T.Helper() @@ -1500,6 +1576,21 @@ func (mr *MockStateMockRecorder) GetUTXO(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUTXO", reflect.TypeOf((*MockState)(nil).GetUTXO), arg0) } +// GetUnitFees mocks base method. +func (m *MockState) GetUnitFees() (fees.Dimensions, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetUnitFees") + ret0, _ := ret[0].(fees.Dimensions) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetUnitFees indicates an expected call of GetUnitFees. +func (mr *MockStateMockRecorder) GetUnitFees() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUnitFees", reflect.TypeOf((*MockState)(nil).GetUnitFees)) +} + // GetUptime mocks base method. func (m *MockState) GetUptime(arg0 ids.NodeID, arg1 ids.ID) (time.Duration, time.Time, error) { m.ctrl.T.Helper() @@ -1578,6 +1669,20 @@ func (mr *MockStateMockRecorder) PutPendingValidator(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PutPendingValidator", reflect.TypeOf((*MockState)(nil).PutPendingValidator), arg0) } +// SetBlockUnitCaps mocks base method. +func (m *MockState) SetBlockUnitCaps(arg0 fees.Dimensions) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetBlockUnitCaps", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// SetBlockUnitCaps indicates an expected call of SetBlockUnitCaps. +func (mr *MockStateMockRecorder) SetBlockUnitCaps(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetBlockUnitCaps", reflect.TypeOf((*MockState)(nil).SetBlockUnitCaps), arg0) +} + // SetCurrentSupply mocks base method. func (m *MockState) SetCurrentSupply(arg0 ids.ID, arg1 uint64) { m.ctrl.T.Helper() @@ -1652,6 +1757,20 @@ func (mr *MockStateMockRecorder) SetTimestamp(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetTimestamp", reflect.TypeOf((*MockState)(nil).SetTimestamp), arg0) } +// SetUnitFees mocks base method. +func (m *MockState) SetUnitFees(arg0 fees.Dimensions) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetUnitFees", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// SetUnitFees indicates an expected call of SetUnitFees. +func (mr *MockStateMockRecorder) SetUnitFees(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetUnitFees", reflect.TypeOf((*MockState)(nil).SetUnitFees), arg0) +} + // SetUptime mocks base method. func (m *MockState) SetUptime(arg0 ids.NodeID, arg1 ids.ID, arg2 time.Duration, arg3 time.Time) error { m.ctrl.T.Helper() diff --git a/vms/platformvm/state/state.go b/vms/platformvm/state/state.go index 92e646ed6975..d8fe7b885620 100644 --- a/vms/platformvm/state/state.go +++ b/vms/platformvm/state/state.go @@ -46,6 +46,7 @@ import ( "github.com/ava-labs/avalanchego/vms/platformvm/txs" safemath "github.com/ava-labs/avalanchego/utils/math" + commonfees "github.com/ava-labs/avalanchego/vms/components/fees" ) const ( @@ -100,6 +101,10 @@ type Chain interface { avax.UTXOGetter avax.UTXODeleter + // at this iteration we don't need to reset these, we are just metering + GetUnitFees() (commonfees.Dimensions, error) + GetBlockUnitCaps() (commonfees.Dimensions, error) + GetTimestamp() time.Time SetTimestamp(tm time.Time) @@ -141,6 +146,10 @@ type State interface { GetSubnets() ([]*txs.Tx, error) GetChains(subnetID ids.ID) ([]*txs.Tx, error) + // At this iteration these getters are helpful for UTs only + SetUnitFees(uf commonfees.Dimensions) error + SetBlockUnitCaps(caps commonfees.Dimensions) error + // ApplyValidatorWeightDiffs iterates from [startHeight] towards the genesis // block until it has applied all of the diffs up to and including // [endHeight]. Applying the diffs modifies [validators]. @@ -375,6 +384,11 @@ type state struct { lastAccepted, persistedLastAccepted ids.ID indexedHeights *heightRange singletonDB database.Database + + // multifees data are not persisted at this stage. We just meter for now, + // we'll revisit when we'll introduce dynamic fees + unitFees commonfees.Dimensions + blockUnitCaps commonfees.Dimensions } // heightRange is used to track which heights are safe to use the native DB @@ -1078,6 +1092,24 @@ func (s *state) GetStartTime(nodeID ids.NodeID, subnetID ids.ID) (time.Time, err return staker.StartTime, nil } +func (s *state) GetUnitFees() (commonfees.Dimensions, error) { + return s.unitFees, nil +} + +func (s *state) SetUnitFees(uf commonfees.Dimensions) error { + s.unitFees = uf + return nil +} + +func (s *state) GetBlockUnitCaps() (commonfees.Dimensions, error) { + return s.blockUnitCaps, nil +} + +func (s *state) SetBlockUnitCaps(caps commonfees.Dimensions) error { + s.blockUnitCaps = caps + return nil +} + func (s *state) GetTimestamp() time.Time { return s.timestamp } diff --git a/vms/platformvm/txs/builder/builder.go b/vms/platformvm/txs/builder/builder.go index b45e250572c2..649cb0e3b18c 100644 --- a/vms/platformvm/txs/builder/builder.go +++ b/vms/platformvm/txs/builder/builder.go @@ -315,12 +315,26 @@ func (b *builder) NewImportTx( isEForkActive = b.cfg.IsEForkActivated(chainTime) ) if isEForkActive { + var ( + unitFees commonfees.Dimensions + unitCaps commonfees.Dimensions + ) + unitFees, err = b.state.GetUnitFees() + if err != nil { + return nil, err + } + + unitCaps, err = b.state.GetBlockUnitCaps() + if err != nil { + return nil, err + } + // while outs are not ordered we add them to get current fees. We'll fix ordering later on utx.BaseTx.Outs = outs feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, - FeeManager: commonfees.NewManager(b.cfg.DefaultUnitFees), - ConsumedUnitsCap: b.cfg.DefaultBlockMaxConsumedUnits, + FeeManager: commonfees.NewManager(unitFees), + ConsumedUnitsCap: unitCaps, Credentials: txs.EmptyCredentials(signers), } @@ -468,10 +482,24 @@ func (b *builder) NewExportTx( err error ) if isEForkActive { + var ( + unitFees commonfees.Dimensions + unitCaps commonfees.Dimensions + ) + unitFees, err = b.state.GetUnitFees() + if err != nil { + return nil, err + } + + unitCaps, err = b.state.GetBlockUnitCaps() + if err != nil { + return nil, err + } + feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, - FeeManager: commonfees.NewManager(b.cfg.DefaultUnitFees), - ConsumedUnitsCap: b.cfg.DefaultBlockMaxConsumedUnits, + FeeManager: commonfees.NewManager(unitFees), + ConsumedUnitsCap: unitCaps, Credentials: txs.EmptyCredentials(signers), } @@ -549,10 +577,24 @@ func (b *builder) NewCreateChainTx( signers [][]*secp256k1.PrivateKey ) if isEForkActive { + var ( + unitFees commonfees.Dimensions + unitCaps commonfees.Dimensions + ) + unitFees, err = b.state.GetUnitFees() + if err != nil { + return nil, err + } + + unitCaps, err = b.state.GetBlockUnitCaps() + if err != nil { + return nil, err + } + feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, - FeeManager: commonfees.NewManager(b.cfg.DefaultUnitFees), - ConsumedUnitsCap: b.cfg.DefaultBlockMaxConsumedUnits, + FeeManager: commonfees.NewManager(unitFees), + ConsumedUnitsCap: unitCaps, Credentials: txs.EmptyCredentials(signers), } @@ -619,10 +661,24 @@ func (b *builder) NewCreateSubnetTx( err error ) if isEForkActive { + var ( + unitFees commonfees.Dimensions + unitCaps commonfees.Dimensions + ) + unitFees, err = b.state.GetUnitFees() + if err != nil { + return nil, err + } + + unitCaps, err = b.state.GetBlockUnitCaps() + if err != nil { + return nil, err + } + feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, - FeeManager: commonfees.NewManager(b.cfg.DefaultUnitFees), - ConsumedUnitsCap: b.cfg.DefaultBlockMaxConsumedUnits, + FeeManager: commonfees.NewManager(unitFees), + ConsumedUnitsCap: unitCaps, Credentials: txs.EmptyCredentials(signers), } @@ -698,10 +754,24 @@ func (b *builder) NewAddValidatorTx( err error ) if isEForkActive { + var ( + unitFees commonfees.Dimensions + unitCaps commonfees.Dimensions + ) + unitFees, err = b.state.GetUnitFees() + if err != nil { + return nil, err + } + + unitCaps, err = b.state.GetBlockUnitCaps() + if err != nil { + return nil, err + } + feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, - FeeManager: commonfees.NewManager(b.cfg.DefaultUnitFees), - ConsumedUnitsCap: b.cfg.DefaultBlockMaxConsumedUnits, + FeeManager: commonfees.NewManager(unitFees), + ConsumedUnitsCap: unitCaps, Credentials: txs.EmptyCredentials(signers), } @@ -775,10 +845,24 @@ func (b *builder) NewAddDelegatorTx( err error ) if isEForkActive { + var ( + unitFees commonfees.Dimensions + unitCaps commonfees.Dimensions + ) + unitFees, err = b.state.GetUnitFees() + if err != nil { + return nil, err + } + + unitCaps, err = b.state.GetBlockUnitCaps() + if err != nil { + return nil, err + } + feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, - FeeManager: commonfees.NewManager(b.cfg.DefaultUnitFees), - ConsumedUnitsCap: b.cfg.DefaultBlockMaxConsumedUnits, + FeeManager: commonfees.NewManager(unitFees), + ConsumedUnitsCap: unitCaps, Credentials: txs.EmptyCredentials(signers), } @@ -853,10 +937,24 @@ func (b *builder) NewAddSubnetValidatorTx( signers [][]*secp256k1.PrivateKey ) if isEForkActive { + var ( + unitFees commonfees.Dimensions + unitCaps commonfees.Dimensions + ) + unitFees, err = b.state.GetUnitFees() + if err != nil { + return nil, err + } + + unitCaps, err = b.state.GetBlockUnitCaps() + if err != nil { + return nil, err + } + feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, - FeeManager: commonfees.NewManager(b.cfg.DefaultUnitFees), - ConsumedUnitsCap: b.cfg.DefaultBlockMaxConsumedUnits, + FeeManager: commonfees.NewManager(unitFees), + ConsumedUnitsCap: unitCaps, Credentials: txs.EmptyCredentials(signers), } @@ -921,10 +1019,24 @@ func (b *builder) NewRemoveSubnetValidatorTx( signers [][]*secp256k1.PrivateKey ) if isEForkActive { + var ( + unitFees commonfees.Dimensions + unitCaps commonfees.Dimensions + ) + unitFees, err = b.state.GetUnitFees() + if err != nil { + return nil, err + } + + unitCaps, err = b.state.GetBlockUnitCaps() + if err != nil { + return nil, err + } + feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, - FeeManager: commonfees.NewManager(b.cfg.DefaultUnitFees), - ConsumedUnitsCap: b.cfg.DefaultBlockMaxConsumedUnits, + FeeManager: commonfees.NewManager(unitFees), + ConsumedUnitsCap: unitCaps, Credentials: txs.EmptyCredentials(signers), } @@ -1012,10 +1124,24 @@ func (b *builder) NewTransferSubnetOwnershipTx( signers [][]*secp256k1.PrivateKey ) if isEForkActive { + var ( + unitFees commonfees.Dimensions + unitCaps commonfees.Dimensions + ) + unitFees, err = b.state.GetUnitFees() + if err != nil { + return nil, err + } + + unitCaps, err = b.state.GetBlockUnitCaps() + if err != nil { + return nil, err + } + feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, - FeeManager: commonfees.NewManager(b.cfg.DefaultUnitFees), - ConsumedUnitsCap: b.cfg.DefaultBlockMaxConsumedUnits, + FeeManager: commonfees.NewManager(unitFees), + ConsumedUnitsCap: unitCaps, Credentials: txs.EmptyCredentials(signers), } @@ -1074,10 +1200,24 @@ func (b *builder) NewBaseTx( err error ) if isEForkActive { + var ( + unitFees commonfees.Dimensions + unitCaps commonfees.Dimensions + ) + unitFees, err = b.state.GetUnitFees() + if err != nil { + return nil, err + } + + unitCaps, err = b.state.GetBlockUnitCaps() + if err != nil { + return nil, err + } + feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, - FeeManager: commonfees.NewManager(b.cfg.DefaultUnitFees), - ConsumedUnitsCap: b.cfg.DefaultBlockMaxConsumedUnits, + FeeManager: commonfees.NewManager(unitFees), + ConsumedUnitsCap: unitCaps, Credentials: txs.EmptyCredentials(signers), } diff --git a/vms/platformvm/txs/executor/atomic_tx_executor.go b/vms/platformvm/txs/executor/atomic_tx_executor.go index 987ff4cf51d7..86c63051e194 100644 --- a/vms/platformvm/txs/executor/atomic_tx_executor.go +++ b/vms/platformvm/txs/executor/atomic_tx_executor.go @@ -7,9 +7,11 @@ import ( "github.com/ava-labs/avalanchego/chains/atomic" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils/set" - "github.com/ava-labs/avalanchego/vms/components/fees" "github.com/ava-labs/avalanchego/vms/platformvm/state" "github.com/ava-labs/avalanchego/vms/platformvm/txs" + "github.com/ava-labs/avalanchego/vms/platformvm/txs/fees" + + commonfees "github.com/ava-labs/avalanchego/vms/components/fees" ) var _ txs.Visitor = (*AtomicTxExecutor)(nil) @@ -101,7 +103,7 @@ func (e *AtomicTxExecutor) atomicTx(tx txs.UnsignedTx) error { executor := StandardTxExecutor{ Backend: e.Backend, - BlkFeeManager: fees.NewManager(e.Backend.Config.DefaultUnitFees), + BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), State: e.OnAccept, Tx: e.Tx, } diff --git a/vms/platformvm/txs/executor/create_chain_test.go b/vms/platformvm/txs/executor/create_chain_test.go index 18a8fb86eab1..693c70bc16f9 100644 --- a/vms/platformvm/txs/executor/create_chain_test.go +++ b/vms/platformvm/txs/executor/create_chain_test.go @@ -16,11 +16,13 @@ import ( "github.com/ava-labs/avalanchego/utils/hashing" "github.com/ava-labs/avalanchego/utils/units" "github.com/ava-labs/avalanchego/vms/components/avax" - "github.com/ava-labs/avalanchego/vms/components/fees" "github.com/ava-labs/avalanchego/vms/platformvm/state" "github.com/ava-labs/avalanchego/vms/platformvm/txs" + "github.com/ava-labs/avalanchego/vms/platformvm/txs/fees" "github.com/ava-labs/avalanchego/vms/platformvm/utxo" "github.com/ava-labs/avalanchego/vms/secp256k1fx" + + commonfees "github.com/ava-labs/avalanchego/vms/components/fees" ) // Ensure Execute fails when there are not enough control sigs @@ -51,7 +53,7 @@ func TestCreateChainTxInsufficientControlSigs(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitFees), + BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), State: stateDiff, Tx: tx, } @@ -93,7 +95,7 @@ func TestCreateChainTxWrongControlSig(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitFees), + BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), State: stateDiff, Tx: tx, } @@ -129,7 +131,7 @@ func TestCreateChainTxNoSuchSubnet(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitFees), + BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), State: stateDiff, Tx: tx, } @@ -162,7 +164,7 @@ func TestCreateChainTxValid(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitFees), + BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), State: stateDiff, Tx: tx, } @@ -237,7 +239,7 @@ func TestCreateChainTxAP3FeeChange(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitFees), + BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), State: stateDiff, Tx: tx, } diff --git a/vms/platformvm/txs/executor/create_subnet_test.go b/vms/platformvm/txs/executor/create_subnet_test.go index 666fa32f6e08..1628ee11c6fe 100644 --- a/vms/platformvm/txs/executor/create_subnet_test.go +++ b/vms/platformvm/txs/executor/create_subnet_test.go @@ -12,11 +12,13 @@ import ( "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils/units" "github.com/ava-labs/avalanchego/vms/components/avax" - "github.com/ava-labs/avalanchego/vms/components/fees" "github.com/ava-labs/avalanchego/vms/platformvm/state" "github.com/ava-labs/avalanchego/vms/platformvm/txs" + "github.com/ava-labs/avalanchego/vms/platformvm/txs/fees" "github.com/ava-labs/avalanchego/vms/platformvm/utxo" "github.com/ava-labs/avalanchego/vms/secp256k1fx" + + commonfees "github.com/ava-labs/avalanchego/vms/components/fees" ) func TestCreateSubnetTxAP3FeeChange(t *testing.T) { @@ -80,7 +82,7 @@ func TestCreateSubnetTxAP3FeeChange(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitFees), + BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), State: stateDiff, Tx: tx, } diff --git a/vms/platformvm/txs/executor/helpers_test.go b/vms/platformvm/txs/executor/helpers_test.go index bf72c1faaba4..fb9759b42aa8 100644 --- a/vms/platformvm/txs/executor/helpers_test.go +++ b/vms/platformvm/txs/executor/helpers_test.go @@ -205,9 +205,12 @@ func addSubnet( stateDiff, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) + unitFees, err := env.state.GetUnitFees() + require.NoError(err) + executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitFees), + BlkFeeManager: fees.NewManager(unitFees), State: stateDiff, Tx: testSubnet1, } diff --git a/vms/platformvm/txs/executor/proposal_tx_executor.go b/vms/platformvm/txs/executor/proposal_tx_executor.go index 18e5aa5b8675..2b4c279d3e07 100644 --- a/vms/platformvm/txs/executor/proposal_tx_executor.go +++ b/vms/platformvm/txs/executor/proposal_tx_executor.go @@ -13,11 +13,13 @@ import ( "github.com/ava-labs/avalanchego/utils/constants" "github.com/ava-labs/avalanchego/utils/math" "github.com/ava-labs/avalanchego/vms/components/avax" - "github.com/ava-labs/avalanchego/vms/components/fees" "github.com/ava-labs/avalanchego/vms/components/verify" "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/fees" + + commonfees "github.com/ava-labs/avalanchego/vms/components/fees" ) const ( @@ -47,7 +49,7 @@ var ( type ProposalTxExecutor struct { // inputs, to be filled before visitor methods are called *Backend - BlkFeeManager *fees.Manager + BlkFeeManager *commonfees.Manager Tx *txs.Tx // [OnCommitState] is the state used for validation. // [OnCommitState] is modified by this struct's methods to @@ -124,6 +126,7 @@ func (e *ProposalTxExecutor) AddValidatorTx(tx *txs.AddValidatorTx) error { onAbortOuts, err := verifyAddValidatorTx( e.Backend, e.BlkFeeManager, + fees.EmptyUnitCaps, e.OnCommitState, e.Tx, tx, @@ -174,6 +177,7 @@ func (e *ProposalTxExecutor) AddSubnetValidatorTx(tx *txs.AddSubnetValidatorTx) if err := verifyAddSubnetValidatorTx( e.Backend, e.BlkFeeManager, + fees.EmptyUnitCaps, e.OnCommitState, e.Tx, tx, @@ -223,6 +227,7 @@ func (e *ProposalTxExecutor) AddDelegatorTx(tx *txs.AddDelegatorTx) error { onAbortOuts, err := verifyAddDelegatorTx( e.Backend, e.BlkFeeManager, + fees.EmptyUnitCaps, e.OnCommitState, e.Tx, tx, diff --git a/vms/platformvm/txs/executor/staker_tx_verification.go b/vms/platformvm/txs/executor/staker_tx_verification.go index f7c8de5f97f7..3a384bb83f40 100644 --- a/vms/platformvm/txs/executor/staker_tx_verification.go +++ b/vms/platformvm/txs/executor/staker_tx_verification.go @@ -91,6 +91,7 @@ func verifySubnetValidatorPrimaryNetworkRequirements( func verifyAddValidatorTx( backend *Backend, feeManager *commonFees.Manager, + unitCaps commonFees.Dimensions, chainState state.Chain, sTx *txs.Tx, tx *txs.AddValidatorTx, @@ -168,7 +169,7 @@ func verifyAddValidatorTx( Config: backend.Config, ChainTime: currentTimestamp, FeeManager: feeManager, - ConsumedUnitsCap: backend.Config.DefaultBlockMaxConsumedUnits, + ConsumedUnitsCap: unitCaps, Credentials: sTx.Creds, } if err := tx.Visit(&feeCalculator); err != nil { @@ -198,6 +199,7 @@ func verifyAddValidatorTx( func verifyAddSubnetValidatorTx( backend *Backend, feeManager *commonFees.Manager, + unitCaps commonFees.Dimensions, chainState state.Chain, sTx *txs.Tx, tx *txs.AddSubnetValidatorTx, @@ -267,7 +269,7 @@ func verifyAddSubnetValidatorTx( Config: backend.Config, ChainTime: currentTimestamp, FeeManager: feeManager, - ConsumedUnitsCap: backend.Config.DefaultBlockMaxConsumedUnits, + ConsumedUnitsCap: unitCaps, Credentials: sTx.Creds, } if err := tx.Visit(&feeCalculator); err != nil { @@ -303,6 +305,7 @@ func verifyAddSubnetValidatorTx( func verifyRemoveSubnetValidatorTx( backend *Backend, feeManager *commonFees.Manager, + unitCaps commonFees.Dimensions, chainState state.Chain, sTx *txs.Tx, tx *txs.RemoveSubnetValidatorTx, @@ -350,7 +353,7 @@ func verifyRemoveSubnetValidatorTx( Config: backend.Config, ChainTime: currentTimestamp, FeeManager: feeManager, - ConsumedUnitsCap: backend.Config.DefaultBlockMaxConsumedUnits, + ConsumedUnitsCap: unitCaps, Credentials: sTx.Creds, } if err := tx.Visit(&feeCalculator); err != nil { @@ -379,6 +382,7 @@ func verifyRemoveSubnetValidatorTx( func verifyAddDelegatorTx( backend *Backend, feeManager *commonFees.Manager, + unitCaps commonFees.Dimensions, chainState state.Chain, sTx *txs.Tx, tx *txs.AddDelegatorTx, @@ -475,7 +479,7 @@ func verifyAddDelegatorTx( Config: backend.Config, ChainTime: currentTimestamp, FeeManager: feeManager, - ConsumedUnitsCap: backend.Config.DefaultBlockMaxConsumedUnits, + ConsumedUnitsCap: unitCaps, Credentials: sTx.Creds, } if err := tx.Visit(&feeCalculator); err != nil { @@ -505,6 +509,7 @@ func verifyAddDelegatorTx( func verifyAddPermissionlessValidatorTx( backend *Backend, feeManager *commonFees.Manager, + unitCaps commonFees.Dimensions, chainState state.Chain, sTx *txs.Tx, tx *txs.AddPermissionlessValidatorTx, @@ -603,7 +608,7 @@ func verifyAddPermissionlessValidatorTx( Config: backend.Config, ChainTime: currentTimestamp, FeeManager: feeManager, - ConsumedUnitsCap: backend.Config.DefaultBlockMaxConsumedUnits, + ConsumedUnitsCap: unitCaps, Credentials: sTx.Creds, } if err := tx.Visit(&feeCalculator); err != nil { @@ -633,6 +638,7 @@ func verifyAddPermissionlessValidatorTx( func verifyAddPermissionlessDelegatorTx( backend *Backend, feeManager *commonFees.Manager, + unitCaps commonFees.Dimensions, chainState state.Chain, sTx *txs.Tx, tx *txs.AddPermissionlessDelegatorTx, @@ -754,7 +760,7 @@ func verifyAddPermissionlessDelegatorTx( Config: backend.Config, ChainTime: currentTimestamp, FeeManager: feeManager, - ConsumedUnitsCap: backend.Config.DefaultBlockMaxConsumedUnits, + ConsumedUnitsCap: unitCaps, Credentials: sTx.Creds, } if err := tx.Visit(&feeCalculator); err != nil { @@ -787,6 +793,7 @@ func verifyAddPermissionlessDelegatorTx( func verifyTransferSubnetOwnershipTx( backend *Backend, feeManager *commonFees.Manager, + unitCaps commonFees.Dimensions, chainState state.Chain, sTx *txs.Tx, tx *txs.TransferSubnetOwnershipTx, @@ -817,7 +824,7 @@ func verifyTransferSubnetOwnershipTx( Config: backend.Config, ChainTime: currentTimestamp, FeeManager: feeManager, - ConsumedUnitsCap: backend.Config.DefaultBlockMaxConsumedUnits, + ConsumedUnitsCap: unitCaps, Credentials: sTx.Creds, } diff --git a/vms/platformvm/txs/executor/staker_tx_verification_test.go b/vms/platformvm/txs/executor/staker_tx_verification_test.go index 27f44ed08714..caa60e968196 100644 --- a/vms/platformvm/txs/executor/staker_tx_verification_test.go +++ b/vms/platformvm/txs/executor/staker_tx_verification_test.go @@ -19,13 +19,15 @@ import ( "github.com/ava-labs/avalanchego/utils/constants" "github.com/ava-labs/avalanchego/utils/timer/mockable" "github.com/ava-labs/avalanchego/vms/components/avax" - "github.com/ava-labs/avalanchego/vms/components/fees" "github.com/ava-labs/avalanchego/vms/components/verify" "github.com/ava-labs/avalanchego/vms/platformvm/config" "github.com/ava-labs/avalanchego/vms/platformvm/state" "github.com/ava-labs/avalanchego/vms/platformvm/txs" + "github.com/ava-labs/avalanchego/vms/platformvm/txs/fees" "github.com/ava-labs/avalanchego/vms/platformvm/utxo" "github.com/ava-labs/avalanchego/vms/secp256k1fx" + + commonfees "github.com/ava-labs/avalanchego/vms/components/fees" ) func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { @@ -599,13 +601,13 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { var ( backend = tt.backendF(ctrl) - feeManager = fees.NewManager(backend.Config.DefaultUnitFees) + feeManager = commonfees.NewManager(fees.EmptyUnitFees) state = tt.stateF(ctrl) sTx = tt.sTxF() tx = tt.txF() ) - err := verifyAddPermissionlessValidatorTx(backend, feeManager, state, sTx, tx) + err := verifyAddPermissionlessValidatorTx(backend, feeManager, fees.EmptyUnitCaps, state, sTx, tx) require.ErrorIs(t, err, tt.expectedErr) }) } diff --git a/vms/platformvm/txs/executor/standard_tx_executor.go b/vms/platformvm/txs/executor/standard_tx_executor.go index b6ed02f3852b..875901956fa2 100644 --- a/vms/platformvm/txs/executor/standard_tx_executor.go +++ b/vms/platformvm/txs/executor/standard_tx_executor.go @@ -36,6 +36,7 @@ type StandardTxExecutor struct { // inputs, to be filled before visitor methods are called *Backend BlkFeeManager *commonFees.Manager + UnitCaps commonFees.Dimensions State state.Diff // state is expected to be modified Tx *txs.Tx @@ -73,7 +74,7 @@ func (e *StandardTxExecutor) CreateChainTx(tx *txs.CreateChainTx) error { Config: cfg, ChainTime: currentTimestamp, FeeManager: e.BlkFeeManager, - ConsumedUnitsCap: cfg.DefaultBlockMaxConsumedUnits, + ConsumedUnitsCap: e.UnitCaps, Credentials: e.Tx.Creds, } if err := tx.Visit(&feeCalculator); err != nil { @@ -126,7 +127,7 @@ func (e *StandardTxExecutor) CreateSubnetTx(tx *txs.CreateSubnetTx) error { Config: cfg, ChainTime: currentTimestamp, FeeManager: e.BlkFeeManager, - ConsumedUnitsCap: cfg.DefaultBlockMaxConsumedUnits, + ConsumedUnitsCap: e.UnitCaps, Credentials: e.Tx.Creds, } if err := tx.Visit(&feeCalculator); err != nil { @@ -214,7 +215,7 @@ func (e *StandardTxExecutor) ImportTx(tx *txs.ImportTx) error { Config: cfg, ChainTime: currentTimestamp, FeeManager: e.BlkFeeManager, - ConsumedUnitsCap: cfg.DefaultBlockMaxConsumedUnits, + ConsumedUnitsCap: e.UnitCaps, Credentials: e.Tx.Creds, } if err := tx.Visit(&feeCalculator); err != nil { @@ -278,7 +279,7 @@ func (e *StandardTxExecutor) ExportTx(tx *txs.ExportTx) error { Config: cfg, ChainTime: currentTimestamp, FeeManager: e.BlkFeeManager, - ConsumedUnitsCap: cfg.DefaultBlockMaxConsumedUnits, + ConsumedUnitsCap: e.UnitCaps, Credentials: e.Tx.Creds, } if err := tx.Visit(&feeCalculator); err != nil { @@ -350,6 +351,7 @@ func (e *StandardTxExecutor) AddValidatorTx(tx *txs.AddValidatorTx) error { if _, err := verifyAddValidatorTx( e.Backend, e.BlkFeeManager, + e.UnitCaps, e.State, e.Tx, tx, @@ -380,6 +382,7 @@ func (e *StandardTxExecutor) AddSubnetValidatorTx(tx *txs.AddSubnetValidatorTx) if err := verifyAddSubnetValidatorTx( e.Backend, e.BlkFeeManager, + e.UnitCaps, e.State, e.Tx, tx, @@ -401,6 +404,7 @@ func (e *StandardTxExecutor) AddDelegatorTx(tx *txs.AddDelegatorTx) error { if _, err := verifyAddDelegatorTx( e.Backend, e.BlkFeeManager, + e.UnitCaps, e.State, e.Tx, tx, @@ -427,6 +431,7 @@ func (e *StandardTxExecutor) RemoveSubnetValidatorTx(tx *txs.RemoveSubnetValidat staker, isCurrentValidator, err := verifyRemoveSubnetValidatorTx( e.Backend, e.BlkFeeManager, + e.UnitCaps, e.State, e.Tx, tx, @@ -500,6 +505,7 @@ func (e *StandardTxExecutor) AddPermissionlessValidatorTx(tx *txs.AddPermissionl if err := verifyAddPermissionlessValidatorTx( e.Backend, e.BlkFeeManager, + e.UnitCaps, e.State, e.Tx, tx, @@ -533,6 +539,7 @@ func (e *StandardTxExecutor) AddPermissionlessDelegatorTx(tx *txs.AddPermissionl if err := verifyAddPermissionlessDelegatorTx( e.Backend, e.BlkFeeManager, + e.UnitCaps, e.State, e.Tx, tx, @@ -558,6 +565,7 @@ func (e *StandardTxExecutor) TransferSubnetOwnershipTx(tx *txs.TransferSubnetOwn err := verifyTransferSubnetOwnershipTx( e.Backend, e.BlkFeeManager, + e.UnitCaps, e.State, e.Tx, tx, @@ -594,7 +602,7 @@ func (e *StandardTxExecutor) BaseTx(tx *txs.BaseTx) error { Config: cfg, ChainTime: currentTimestamp, FeeManager: e.BlkFeeManager, - ConsumedUnitsCap: cfg.DefaultBlockMaxConsumedUnits, + ConsumedUnitsCap: e.UnitCaps, Credentials: e.Tx.Creds, } if err := tx.Visit(&feeCalculator); err != nil { diff --git a/vms/platformvm/txs/executor/standard_tx_executor_test.go b/vms/platformvm/txs/executor/standard_tx_executor_test.go index c7e089f17fe0..1cd598adfeab 100644 --- a/vms/platformvm/txs/executor/standard_tx_executor_test.go +++ b/vms/platformvm/txs/executor/standard_tx_executor_test.go @@ -23,7 +23,6 @@ import ( "github.com/ava-labs/avalanchego/utils/hashing" "github.com/ava-labs/avalanchego/utils/timer/mockable" "github.com/ava-labs/avalanchego/vms/components/avax" - "github.com/ava-labs/avalanchego/vms/components/fees" "github.com/ava-labs/avalanchego/vms/components/verify" "github.com/ava-labs/avalanchego/vms/platformvm/config" "github.com/ava-labs/avalanchego/vms/platformvm/fx" @@ -31,8 +30,11 @@ 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/fees" "github.com/ava-labs/avalanchego/vms/platformvm/utxo" "github.com/ava-labs/avalanchego/vms/secp256k1fx" + + commonfees "github.com/ava-labs/avalanchego/vms/components/fees" ) // This tests that the math performed during TransformSubnetTx execution can @@ -90,7 +92,7 @@ func TestStandardTxExecutorAddValidatorTxEmptyID(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitFees), + BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), State: stateDiff, Tx: tx, } @@ -361,7 +363,7 @@ func TestStandardTxExecutorAddDelegator(t *testing.T) { executor := StandardTxExecutor{ Backend: &freshTH.backend, - BlkFeeManager: fees.NewManager(freshTH.backend.Config.DefaultUnitFees), + BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), State: onAcceptState, Tx: tx, } @@ -411,7 +413,7 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitFees), + BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), State: onAcceptState, Tx: tx, } @@ -440,7 +442,7 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitFees), + BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), State: onAcceptState, Tx: tx, } @@ -483,7 +485,7 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitFees), + BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), State: onAcceptState, Tx: tx, } @@ -527,7 +529,7 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitFees), + BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), State: onAcceptState, Tx: tx, } @@ -554,7 +556,7 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitFees), + BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), State: onAcceptState, Tx: tx, } @@ -580,7 +582,7 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { require.NoError(err) executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitFees), + BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), State: onAcceptState, Tx: tx, } @@ -609,7 +611,7 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitFees), + BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), State: onAcceptState, Tx: tx, } @@ -666,7 +668,7 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitFees), + BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), State: onAcceptState, Tx: duplicateSubnetTx, } @@ -704,7 +706,7 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitFees), + BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), State: onAcceptState, Tx: tx, } @@ -738,7 +740,7 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitFees), + BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), State: onAcceptState, Tx: tx, } @@ -770,7 +772,7 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitFees), + BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), State: onAcceptState, Tx: tx, } @@ -812,7 +814,7 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitFees), + BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), State: onAcceptState, Tx: tx, } @@ -850,7 +852,7 @@ func TestStandardTxExecutorBanffAddValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitFees), + BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), State: onAcceptState, Tx: tx, } @@ -877,7 +879,7 @@ func TestStandardTxExecutorBanffAddValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitFees), + BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), State: onAcceptState, Tx: tx, } @@ -917,7 +919,7 @@ func TestStandardTxExecutorBanffAddValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitFees), + BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), State: onAcceptState, Tx: tx, } @@ -954,7 +956,7 @@ func TestStandardTxExecutorBanffAddValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitFees), + BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), State: onAcceptState, Tx: tx, } @@ -990,7 +992,7 @@ func TestStandardTxExecutorBanffAddValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(env.backend.Config.DefaultUnitFees), + BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), State: onAcceptState, Tx: tx, } @@ -1181,7 +1183,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(cfg.DefaultUnitFees), + BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), Tx: env.tx, State: env.state, } @@ -1212,7 +1214,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(cfg.DefaultUnitFees), + BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), Tx: env.tx, State: env.state, } @@ -1243,7 +1245,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(cfg.DefaultUnitFees), + BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), Tx: env.tx, State: env.state, } @@ -1277,7 +1279,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(cfg.DefaultUnitFees), + BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), Tx: env.tx, State: env.state, } @@ -1309,7 +1311,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(cfg.DefaultUnitFees), + BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), Tx: env.tx, State: env.state, } @@ -1340,7 +1342,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(cfg.DefaultUnitFees), + BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), Tx: env.tx, State: env.state, } @@ -1373,7 +1375,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(cfg.DefaultUnitFees), + BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), Tx: env.tx, State: env.state, } @@ -1410,7 +1412,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(cfg.DefaultUnitFees), + BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), Tx: env.tx, State: env.state, } @@ -1571,7 +1573,7 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(cfg.DefaultUnitFees), + BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), Tx: env.tx, State: env.state, } @@ -1601,7 +1603,7 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(cfg.DefaultUnitFees), + BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), Tx: env.tx, State: env.state, } @@ -1633,7 +1635,7 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(cfg.DefaultUnitFees), + BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), Tx: env.tx, State: env.state, } @@ -1670,7 +1672,7 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(cfg.DefaultUnitFees), + BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), Tx: env.tx, State: env.state, } @@ -1712,7 +1714,7 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(cfg.DefaultUnitFees), + BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), Tx: env.tx, State: env.state, } diff --git a/vms/platformvm/txs/executor/tx_mempool_verifier.go b/vms/platformvm/txs/executor/tx_mempool_verifier.go index 83a13c86ff66..f1f2248e8454 100644 --- a/vms/platformvm/txs/executor/tx_mempool_verifier.go +++ b/vms/platformvm/txs/executor/tx_mempool_verifier.go @@ -90,9 +90,14 @@ func (v *MempoolTxVerifier) standardTx(tx txs.UnsignedTx) error { return err } + unitFees, err := baseState.GetUnitFees() + if err != nil { + return err + } + executor := StandardTxExecutor{ Backend: v.Backend, - BlkFeeManager: fees.NewManager(v.Backend.Config.DefaultUnitFees), + BlkFeeManager: fees.NewManager(unitFees), State: baseState, Tx: v.Tx, } diff --git a/vms/platformvm/txs/fees/calculator.go b/vms/platformvm/txs/fees/calculator.go index 139b04d58132..39fbbf425da2 100644 --- a/vms/platformvm/txs/fees/calculator.go +++ b/vms/platformvm/txs/fees/calculator.go @@ -19,6 +19,25 @@ import ( var ( _ txs.Visitor = (*Calculator)(nil) + EmptyUnitFees = fees.Dimensions{} // helps avoiding reading unit fees from db for some pre E fork processing + EmptyUnitCaps = fees.Dimensions{} // helps avoiding reading unit fees from db for some pre E fork processing + + // These are the default unit fees, used upon E-fork activation + DefaultUnitFees = fees.Dimensions{ + 1, + 2, + 3, + 4, + } + + // These are the default caps for units consumed in a block, used upon E-fork activation + DefaultBlockMaxConsumedUnits = fees.Dimensions{ + 1, + 2, + 3, + 4, + } + errFailedFeeCalculation = errors.New("failed fee calculation") errFailedConsumedUnitsCumulation = errors.New("failed cumulating consumed units") ) diff --git a/vms/platformvm/txs/fees/calculator_test.go b/vms/platformvm/txs/fees/calculator_test.go index e2ce019d0798..524b944c329b 100644 --- a/vms/platformvm/txs/fees/calculator_test.go +++ b/vms/platformvm/txs/fees/calculator_test.go @@ -29,20 +29,20 @@ import ( ) var ( - feeTestsDefaultCfg = config.Config{ - DefaultUnitFees: fees.Dimensions{ - 1 * units.MicroAvax, - 2 * units.MicroAvax, - 3 * units.MicroAvax, - 4 * units.MicroAvax, - }, - DefaultBlockMaxConsumedUnits: fees.Dimensions{ - 3000, - 3500, - 1000, - 1000, - }, + testUnitFees = fees.Dimensions{ + 1 * units.MicroAvax, + 2 * units.MicroAvax, + 3 * units.MicroAvax, + 4 * units.MicroAvax, + } + testBlockMaxConsumedUnits = fees.Dimensions{ + 3000, + 3500, + 1000, + 1000, + } + feeTestsDefaultCfg = config.Config{ TxFee: 1 * units.Avax, CreateAssetTxFee: 2 * units.Avax, CreateSubnetTxFee: 3 * units.Avax, @@ -61,10 +61,11 @@ var ( ) type feeTests struct { - description string - cfgAndChainTimeF func() (*config.Config, time.Time) - expectedError error - checksF func(*testing.T, *Calculator) + description string + cfgAndChainTimeF func() (*config.Config, time.Time) + consumedUnitCapsF func() fees.Dimensions + expectedError error + checksF func(*testing.T, *Calculator) } func TestPartiallyFulledTransactionsSizes(t *testing.T) { @@ -122,8 +123,8 @@ func TestAddAndRemoveFees(t *testing.T) { fc := &Calculator{ IsEForkActive: true, - FeeManager: fees.NewManager(feeTestsDefaultCfg.DefaultUnitFees), - ConsumedUnitsCap: feeTestsDefaultCfg.DefaultBlockMaxConsumedUnits, + FeeManager: fees.NewManager(testUnitFees), + ConsumedUnitsCap: testBlockMaxConsumedUnits, } units := fees.Dimensions{ @@ -296,10 +297,14 @@ func TestAddValidatorTxFees(t *testing.T) { cfg := feeTestsDefaultCfg cfg.DurangoTime = durangoTime cfg.EForkTime = eForkTime - cfg.DefaultBlockMaxConsumedUnits[0] = 741 - 1 return &cfg, chainTime }, + consumedUnitCapsF: func() fees.Dimensions { + caps := testBlockMaxConsumedUnits + caps[fees.Bandwidth] = 741 - 1 + return caps + }, expectedError: errFailedConsumedUnitsCumulation, checksF: func(t *testing.T, fc *Calculator) {}, }, @@ -309,12 +314,17 @@ func TestAddValidatorTxFees(t *testing.T) { t.Run(tt.description, func(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() + consumedUnitCaps := testBlockMaxConsumedUnits + if tt.consumedUnitCapsF != nil { + consumedUnitCaps = tt.consumedUnitCapsF() + } + fc := &Calculator{ IsEForkActive: cfg.IsEForkActivated(chainTime), Config: cfg, ChainTime: chainTime, - FeeManager: fees.NewManager(cfg.DefaultUnitFees), - ConsumedUnitsCap: cfg.DefaultBlockMaxConsumedUnits, + FeeManager: fees.NewManager(testUnitFees), + ConsumedUnitsCap: consumedUnitCaps, Credentials: sTx.Creds, } err := uTx.Visit(fc) @@ -400,10 +410,14 @@ func TestAddSubnetValidatorTxFees(t *testing.T) { cfg := feeTestsDefaultCfg cfg.DurangoTime = durangoTime cfg.EForkTime = eForkTime - cfg.DefaultBlockMaxConsumedUnits[1] = 1090 - 1 return &cfg, chainTime }, + consumedUnitCapsF: func() fees.Dimensions { + caps := testBlockMaxConsumedUnits + caps[fees.UTXORead] = 1090 - 1 + return caps + }, expectedError: errFailedConsumedUnitsCumulation, checksF: func(t *testing.T, fc *Calculator) {}, }, @@ -413,12 +427,17 @@ func TestAddSubnetValidatorTxFees(t *testing.T) { t.Run(tt.description, func(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() + consumedUnitCaps := testBlockMaxConsumedUnits + if tt.consumedUnitCapsF != nil { + consumedUnitCaps = tt.consumedUnitCapsF() + } + fc := &Calculator{ IsEForkActive: cfg.IsEForkActivated(chainTime), Config: cfg, ChainTime: chainTime, - FeeManager: fees.NewManager(cfg.DefaultUnitFees), - ConsumedUnitsCap: cfg.DefaultBlockMaxConsumedUnits, + FeeManager: fees.NewManager(testUnitFees), + ConsumedUnitsCap: consumedUnitCaps, Credentials: sTx.Creds, } err := uTx.Visit(fc) @@ -505,10 +524,14 @@ func TestAddDelegatorTxFees(t *testing.T) { cfg := feeTestsDefaultCfg cfg.DurangoTime = durangoTime cfg.EForkTime = eForkTime - cfg.DefaultBlockMaxConsumedUnits[1] = 1090 - 1 return &cfg, chainTime }, + consumedUnitCapsF: func() fees.Dimensions { + caps := testBlockMaxConsumedUnits + caps[fees.UTXORead] = 1090 - 1 + return caps + }, expectedError: errFailedConsumedUnitsCumulation, checksF: func(t *testing.T, fc *Calculator) {}, }, @@ -518,12 +541,17 @@ func TestAddDelegatorTxFees(t *testing.T) { t.Run(tt.description, func(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() + consumedUnitCaps := testBlockMaxConsumedUnits + if tt.consumedUnitCapsF != nil { + consumedUnitCaps = tt.consumedUnitCapsF() + } + fc := &Calculator{ IsEForkActive: cfg.IsEForkActivated(chainTime), Config: cfg, ChainTime: chainTime, - FeeManager: fees.NewManager(cfg.DefaultUnitFees), - ConsumedUnitsCap: cfg.DefaultBlockMaxConsumedUnits, + FeeManager: fees.NewManager(testUnitFees), + ConsumedUnitsCap: consumedUnitCaps, Credentials: sTx.Creds, } err := uTx.Visit(fc) @@ -604,10 +632,14 @@ func TestCreateChainTxFees(t *testing.T) { cfg := feeTestsDefaultCfg cfg.DurangoTime = durangoTime cfg.EForkTime = eForkTime - cfg.DefaultBlockMaxConsumedUnits[1] = 1090 - 1 return &cfg, chainTime }, + consumedUnitCapsF: func() fees.Dimensions { + caps := testBlockMaxConsumedUnits + caps[fees.UTXORead] = 1090 - 1 + return caps + }, expectedError: errFailedConsumedUnitsCumulation, checksF: func(t *testing.T, fc *Calculator) {}, }, @@ -617,12 +649,17 @@ func TestCreateChainTxFees(t *testing.T) { t.Run(tt.description, func(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() + consumedUnitCaps := testBlockMaxConsumedUnits + if tt.consumedUnitCapsF != nil { + consumedUnitCaps = tt.consumedUnitCapsF() + } + fc := &Calculator{ IsEForkActive: cfg.IsEForkActivated(chainTime), Config: cfg, ChainTime: chainTime, - FeeManager: fees.NewManager(cfg.DefaultUnitFees), - ConsumedUnitsCap: cfg.DefaultBlockMaxConsumedUnits, + FeeManager: fees.NewManager(testUnitFees), + ConsumedUnitsCap: consumedUnitCaps, Credentials: sTx.Creds, } err := uTx.Visit(fc) @@ -701,10 +738,14 @@ func TestCreateSubnetTxFees(t *testing.T) { cfg := feeTestsDefaultCfg cfg.DurangoTime = durangoTime cfg.EForkTime = eForkTime - cfg.DefaultBlockMaxConsumedUnits[1] = 1090 - 1 return &cfg, chainTime }, + consumedUnitCapsF: func() fees.Dimensions { + caps := testBlockMaxConsumedUnits + caps[fees.UTXORead] = 1090 - 1 + return caps + }, expectedError: errFailedConsumedUnitsCumulation, checksF: func(t *testing.T, fc *Calculator) {}, }, @@ -714,12 +755,17 @@ func TestCreateSubnetTxFees(t *testing.T) { t.Run(tt.description, func(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() + consumedUnitCaps := testBlockMaxConsumedUnits + if tt.consumedUnitCapsF != nil { + consumedUnitCaps = tt.consumedUnitCapsF() + } + fc := &Calculator{ IsEForkActive: cfg.IsEForkActivated(chainTime), Config: cfg, ChainTime: chainTime, - FeeManager: fees.NewManager(cfg.DefaultUnitFees), - ConsumedUnitsCap: cfg.DefaultBlockMaxConsumedUnits, + FeeManager: fees.NewManager(testUnitFees), + ConsumedUnitsCap: consumedUnitCaps, Credentials: sTx.Creds, } err := uTx.Visit(fc) @@ -797,10 +843,14 @@ func TestRemoveSubnetValidatorTxFees(t *testing.T) { cfg := feeTestsDefaultCfg cfg.DurangoTime = durangoTime cfg.EForkTime = eForkTime - cfg.DefaultBlockMaxConsumedUnits[1] = 1090 - 1 return &cfg, chainTime }, + consumedUnitCapsF: func() fees.Dimensions { + caps := testBlockMaxConsumedUnits + caps[fees.UTXORead] = 1090 - 1 + return caps + }, expectedError: errFailedConsumedUnitsCumulation, checksF: func(t *testing.T, fc *Calculator) {}, }, @@ -810,12 +860,17 @@ func TestRemoveSubnetValidatorTxFees(t *testing.T) { t.Run(tt.description, func(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() + consumedUnitCaps := testBlockMaxConsumedUnits + if tt.consumedUnitCapsF != nil { + consumedUnitCaps = tt.consumedUnitCapsF() + } + fc := &Calculator{ IsEForkActive: cfg.IsEForkActivated(chainTime), Config: cfg, ChainTime: chainTime, - FeeManager: fees.NewManager(cfg.DefaultUnitFees), - ConsumedUnitsCap: cfg.DefaultBlockMaxConsumedUnits, + FeeManager: fees.NewManager(testUnitFees), + ConsumedUnitsCap: consumedUnitCaps, Credentials: sTx.Creds, } err := uTx.Visit(fc) @@ -905,10 +960,14 @@ func TestTransformSubnetTxFees(t *testing.T) { cfg := feeTestsDefaultCfg cfg.DurangoTime = durangoTime cfg.EForkTime = eForkTime - cfg.DefaultBlockMaxConsumedUnits[1] = 1090 - 1 return &cfg, chainTime }, + consumedUnitCapsF: func() fees.Dimensions { + caps := testBlockMaxConsumedUnits + caps[fees.UTXORead] = 1090 - 1 + return caps + }, expectedError: errFailedConsumedUnitsCumulation, checksF: func(t *testing.T, fc *Calculator) {}, }, @@ -918,12 +977,17 @@ func TestTransformSubnetTxFees(t *testing.T) { t.Run(tt.description, func(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() + consumedUnitCaps := testBlockMaxConsumedUnits + if tt.consumedUnitCapsF != nil { + consumedUnitCaps = tt.consumedUnitCapsF() + } + fc := &Calculator{ IsEForkActive: cfg.IsEForkActivated(chainTime), Config: cfg, ChainTime: chainTime, - FeeManager: fees.NewManager(cfg.DefaultUnitFees), - ConsumedUnitsCap: cfg.DefaultBlockMaxConsumedUnits, + FeeManager: fees.NewManager(testUnitFees), + ConsumedUnitsCap: consumedUnitCaps, Credentials: sTx.Creds, } err := uTx.Visit(fc) @@ -1009,10 +1073,14 @@ func TestTransferSubnetOwnershipTxFees(t *testing.T) { cfg := feeTestsDefaultCfg cfg.DurangoTime = durangoTime cfg.EForkTime = eForkTime - cfg.DefaultBlockMaxConsumedUnits[1] = 1090 - 1 return &cfg, chainTime }, + consumedUnitCapsF: func() fees.Dimensions { + caps := testBlockMaxConsumedUnits + caps[fees.UTXORead] = 1090 - 1 + return caps + }, expectedError: errFailedConsumedUnitsCumulation, checksF: func(t *testing.T, fc *Calculator) {}, }, @@ -1022,12 +1090,17 @@ func TestTransferSubnetOwnershipTxFees(t *testing.T) { t.Run(tt.description, func(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() + consumedUnitCaps := testBlockMaxConsumedUnits + if tt.consumedUnitCapsF != nil { + consumedUnitCaps = tt.consumedUnitCapsF() + } + fc := &Calculator{ IsEForkActive: cfg.IsEForkActivated(chainTime), Config: cfg, ChainTime: chainTime, - FeeManager: fees.NewManager(cfg.DefaultUnitFees), - ConsumedUnitsCap: cfg.DefaultBlockMaxConsumedUnits, + FeeManager: fees.NewManager(testUnitFees), + ConsumedUnitsCap: consumedUnitCaps, Credentials: sTx.Creds, } err := uTx.Visit(fc) @@ -1122,10 +1195,14 @@ func TestAddPermissionlessValidatorTxFees(t *testing.T) { cfg := feeTestsDefaultCfg cfg.DurangoTime = durangoTime cfg.EForkTime = eForkTime - cfg.DefaultBlockMaxConsumedUnits[1] = 1090 - 1 return &cfg, chainTime }, + consumedUnitCapsF: func() fees.Dimensions { + caps := testBlockMaxConsumedUnits + caps[fees.UTXORead] = 1090 - 1 + return caps + }, expectedError: errFailedConsumedUnitsCumulation, checksF: func(t *testing.T, fc *Calculator) {}, }, @@ -1135,12 +1212,17 @@ func TestAddPermissionlessValidatorTxFees(t *testing.T) { t.Run(tt.description, func(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() + consumedUnitCaps := testBlockMaxConsumedUnits + if tt.consumedUnitCapsF != nil { + consumedUnitCaps = tt.consumedUnitCapsF() + } + fc := &Calculator{ IsEForkActive: cfg.IsEForkActivated(chainTime), Config: cfg, ChainTime: chainTime, - FeeManager: fees.NewManager(cfg.DefaultUnitFees), - ConsumedUnitsCap: cfg.DefaultBlockMaxConsumedUnits, + FeeManager: fees.NewManager(testUnitFees), + ConsumedUnitsCap: consumedUnitCaps, Credentials: sTx.Creds, } err := uTx.Visit(fc) @@ -1230,10 +1312,14 @@ func TestAddPermissionlessDelegatorTxFees(t *testing.T) { cfg := feeTestsDefaultCfg cfg.DurangoTime = durangoTime cfg.EForkTime = eForkTime - cfg.DefaultBlockMaxConsumedUnits[1] = 1090 - 1 return &cfg, chainTime }, + consumedUnitCapsF: func() fees.Dimensions { + caps := testBlockMaxConsumedUnits + caps[fees.UTXORead] = 1090 - 1 + return caps + }, expectedError: errFailedConsumedUnitsCumulation, checksF: func(t *testing.T, fc *Calculator) {}, }, @@ -1243,12 +1329,17 @@ func TestAddPermissionlessDelegatorTxFees(t *testing.T) { t.Run(tt.description, func(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() + consumedUnitCaps := testBlockMaxConsumedUnits + if tt.consumedUnitCapsF != nil { + consumedUnitCaps = tt.consumedUnitCapsF() + } + fc := &Calculator{ IsEForkActive: cfg.IsEForkActivated(chainTime), Config: cfg, ChainTime: chainTime, - FeeManager: fees.NewManager(cfg.DefaultUnitFees), - ConsumedUnitsCap: cfg.DefaultBlockMaxConsumedUnits, + FeeManager: fees.NewManager(testUnitFees), + ConsumedUnitsCap: consumedUnitCaps, Credentials: sTx.Creds, } err := uTx.Visit(fc) @@ -1321,10 +1412,14 @@ func TestBaseTxFees(t *testing.T) { cfg := feeTestsDefaultCfg cfg.DurangoTime = durangoTime cfg.EForkTime = eForkTime - cfg.DefaultBlockMaxConsumedUnits[1] = 1090 - 1 return &cfg, chainTime }, + consumedUnitCapsF: func() fees.Dimensions { + caps := testBlockMaxConsumedUnits + caps[fees.UTXORead] = 1090 - 1 + return caps + }, expectedError: errFailedConsumedUnitsCumulation, checksF: func(t *testing.T, fc *Calculator) {}, }, @@ -1334,12 +1429,17 @@ func TestBaseTxFees(t *testing.T) { t.Run(tt.description, func(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() + consumedUnitCaps := testBlockMaxConsumedUnits + if tt.consumedUnitCapsF != nil { + consumedUnitCaps = tt.consumedUnitCapsF() + } + fc := &Calculator{ IsEForkActive: cfg.IsEForkActivated(chainTime), Config: cfg, ChainTime: chainTime, - FeeManager: fees.NewManager(cfg.DefaultUnitFees), - ConsumedUnitsCap: cfg.DefaultBlockMaxConsumedUnits, + FeeManager: fees.NewManager(testUnitFees), + ConsumedUnitsCap: consumedUnitCaps, Credentials: sTx.Creds, } err := uTx.Visit(fc) @@ -1426,10 +1526,14 @@ func TestImportTxFees(t *testing.T) { cfg := feeTestsDefaultCfg cfg.DurangoTime = durangoTime cfg.EForkTime = eForkTime - cfg.DefaultBlockMaxConsumedUnits[1] = 1090 - 1 return &cfg, chainTime }, + consumedUnitCapsF: func() fees.Dimensions { + caps := testBlockMaxConsumedUnits + caps[fees.UTXORead] = 1090 - 1 + return caps + }, expectedError: errFailedConsumedUnitsCumulation, checksF: func(t *testing.T, fc *Calculator) {}, }, @@ -1439,12 +1543,17 @@ func TestImportTxFees(t *testing.T) { t.Run(tt.description, func(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() + consumedUnitCaps := testBlockMaxConsumedUnits + if tt.consumedUnitCapsF != nil { + consumedUnitCaps = tt.consumedUnitCapsF() + } + fc := &Calculator{ IsEForkActive: cfg.IsEForkActivated(chainTime), Config: cfg, ChainTime: chainTime, - FeeManager: fees.NewManager(cfg.DefaultUnitFees), - ConsumedUnitsCap: cfg.DefaultBlockMaxConsumedUnits, + FeeManager: fees.NewManager(testUnitFees), + ConsumedUnitsCap: consumedUnitCaps, Credentials: sTx.Creds, } err := uTx.Visit(fc) @@ -1521,10 +1630,14 @@ func TestExportTxFees(t *testing.T) { cfg := feeTestsDefaultCfg cfg.DurangoTime = durangoTime cfg.EForkTime = eForkTime - cfg.DefaultBlockMaxConsumedUnits[1] = 1090 - 1 return &cfg, chainTime }, + consumedUnitCapsF: func() fees.Dimensions { + caps := testBlockMaxConsumedUnits + caps[fees.UTXORead] = 1090 - 1 + return caps + }, expectedError: errFailedConsumedUnitsCumulation, checksF: func(t *testing.T, fc *Calculator) {}, }, @@ -1534,12 +1647,17 @@ func TestExportTxFees(t *testing.T) { t.Run(tt.description, func(t *testing.T) { cfg, chainTime := tt.cfgAndChainTimeF() + consumedUnitCaps := testBlockMaxConsumedUnits + if tt.consumedUnitCapsF != nil { + consumedUnitCaps = tt.consumedUnitCapsF() + } + fc := &Calculator{ IsEForkActive: cfg.IsEForkActivated(chainTime), Config: cfg, ChainTime: chainTime, - FeeManager: fees.NewManager(cfg.DefaultUnitFees), - ConsumedUnitsCap: cfg.DefaultBlockMaxConsumedUnits, + FeeManager: fees.NewManager(testUnitFees), + ConsumedUnitsCap: consumedUnitCaps, Credentials: sTx.Creds, } err := uTx.Visit(fc) diff --git a/vms/platformvm/utxo/handler_test.go b/vms/platformvm/utxo/handler_test.go index 1c8168f1689a..91d9ee609fa3 100644 --- a/vms/platformvm/utxo/handler_test.go +++ b/vms/platformvm/utxo/handler_test.go @@ -18,7 +18,6 @@ import ( "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/config" "github.com/ava-labs/avalanchego/vms/platformvm/reward" "github.com/ava-labs/avalanchego/vms/platformvm/stakeable" "github.com/ava-labs/avalanchego/vms/platformvm/state" @@ -54,19 +53,17 @@ func TestVerifyFinanceTx(t *testing.T) { fx: fx, } - cfg := &config.Config{ - DefaultUnitFees: commonfees.Dimensions{ - 1 * units.MicroAvax, - 2 * units.MicroAvax, - 3 * units.MicroAvax, - 4 * units.MicroAvax, - }, - DefaultBlockMaxConsumedUnits: commonfees.Dimensions{ - math.MaxUint64, - math.MaxUint64, - math.MaxUint64, - math.MaxUint64, - }, + testUnitFees := commonfees.Dimensions{ + 1 * units.MicroAvax, + 2 * units.MicroAvax, + 3 * units.MicroAvax, + 4 * units.MicroAvax, + } + testBlockMaxConsumedUnits := commonfees.Dimensions{ + math.MaxUint64, + math.MaxUint64, + math.MaxUint64, + math.MaxUint64, } var ( @@ -630,11 +627,11 @@ func TestVerifyFinanceTx(t *testing.T) { uTx := test.uTxF(t) - fm := commonfees.NewManager(cfg.DefaultUnitFees) + fm := commonfees.NewManager(testUnitFees) feeCalc := &fees.Calculator{ IsEForkActive: true, FeeManager: fm, - ConsumedUnitsCap: cfg.DefaultBlockMaxConsumedUnits, + ConsumedUnitsCap: testBlockMaxConsumedUnits, Credentials: []verify.Verifiable{}, } From 02c608472e66e4eccec80f5cfd5040629fb51894 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 22 Jan 2024 21:35:51 +0100 Subject: [PATCH 057/190] cleanup --- vms/platformvm/block/builder/builder.go | 5 +++ vms/platformvm/block/builder/helpers_test.go | 4 +++ vms/platformvm/block/executor/helpers_test.go | 5 +++ .../block/executor/proposal_block_test.go | 1 + .../block/executor/standard_block_test.go | 4 ++- vms/platformvm/block/executor/verifier.go | 6 ++++ .../block/executor/verifier_test.go | 2 ++ .../txs/executor/atomic_tx_executor.go | 1 + .../txs/executor/create_chain_test.go | 5 +++ .../txs/executor/create_subnet_test.go | 1 + vms/platformvm/txs/executor/helpers_test.go | 4 +++ .../txs/executor/standard_tx_executor_test.go | 32 +++++++++++++++++++ .../txs/executor/tx_mempool_verifier.go | 6 ++++ 13 files changed, 75 insertions(+), 1 deletion(-) diff --git a/vms/platformvm/block/builder/builder.go b/vms/platformvm/block/builder/builder.go index daafbf296b68..a7af5b49d0d6 100644 --- a/vms/platformvm/block/builder/builder.go +++ b/vms/platformvm/block/builder/builder.go @@ -382,10 +382,15 @@ func packBlockTxs( if err != nil { return nil, err } + unitCaps, err := txDiff.GetBlockUnitCaps() + if err != nil { + return nil, err + } executor := &txexecutor.StandardTxExecutor{ Backend: backend, BlkFeeManager: fees.NewManager(unitFees), + UnitCaps: unitCaps, State: txDiff, Tx: tx, } diff --git a/vms/platformvm/block/builder/helpers_test.go b/vms/platformvm/block/builder/helpers_test.go index f7d56b9e1f20..c479b5875063 100644 --- a/vms/platformvm/block/builder/helpers_test.go +++ b/vms/platformvm/block/builder/helpers_test.go @@ -240,9 +240,13 @@ func addSubnet(t *testing.T, env *environment) { unitFees, err := env.state.GetUnitFees() require.NoError(err) + unitCaps, err := env.state.GetBlockUnitCaps() + require.NoError(err) + executor := txexecutor.StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: fees.NewManager(unitFees), + UnitCaps: unitCaps, State: stateDiff, Tx: testSubnet1, } diff --git a/vms/platformvm/block/executor/helpers_test.go b/vms/platformvm/block/executor/helpers_test.go index 3195dee9083f..f96c33357345 100644 --- a/vms/platformvm/block/executor/helpers_test.go +++ b/vms/platformvm/block/executor/helpers_test.go @@ -252,10 +252,15 @@ func addSubnet(env *environment) { if err != nil { panic(err) } + unitCaps, err := env.state.GetBlockUnitCaps() + if err != nil { + panic(err) + } executor := executor.StandardTxExecutor{ Backend: env.backend, BlkFeeManager: fees.NewManager(unitFees), + UnitCaps: unitCaps, State: stateDiff, Tx: testSubnet1, } diff --git a/vms/platformvm/block/executor/proposal_block_test.go b/vms/platformvm/block/executor/proposal_block_test.go index f6b9570da4a9..564d66a001c5 100644 --- a/vms/platformvm/block/executor/proposal_block_test.go +++ b/vms/platformvm/block/executor/proposal_block_test.go @@ -175,6 +175,7 @@ func TestBanffProposalBlockTimeVerification(t *testing.T) { onParentAccept := state.NewMockDiff(ctrl) onParentAccept.EXPECT().GetTimestamp().Return(parentTime).AnyTimes() onParentAccept.EXPECT().GetUnitFees().Return(fees.EmptyUnitFees, nil).AnyTimes() + onParentAccept.EXPECT().GetBlockUnitCaps().Return(fees.EmptyUnitCaps, 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 1c5f62524492..314a8189144e 100644 --- a/vms/platformvm/block/executor/standard_block_test.go +++ b/vms/platformvm/block/executor/standard_block_test.go @@ -60,7 +60,8 @@ 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().GetUnitFees().Return(fees.EmptyUnitFees, nil).AnyTimes() + onParentAccept.EXPECT().GetUnitFees().Return(fees.EmptyUnitFees, nil) + onParentAccept.EXPECT().GetBlockUnitCaps().Return(fees.EmptyUnitCaps, nil) // wrong height apricotChildBlk, err := block.NewApricotStandardBlock( apricotParentBlk.ID(), @@ -158,6 +159,7 @@ func TestBanffStandardBlockTimeVerification(t *testing.T) { utxoID := utxo.InputID() onParentAccept.EXPECT().GetUTXO(utxoID).Return(utxo, nil).AnyTimes() onParentAccept.EXPECT().GetUnitFees().Return(fees.EmptyUnitFees, nil).AnyTimes() + onParentAccept.EXPECT().GetBlockUnitCaps().Return(fees.EmptyUnitCaps, 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 003bfd1ba80a..eb66460ad2d8 100644 --- a/vms/platformvm/block/executor/verifier.go +++ b/vms/platformvm/block/executor/verifier.go @@ -464,10 +464,16 @@ func (v *verifier) processStandardTxs(txs []*txs.Tx, state state.Diff, parentID } feeManager := fees.NewManager(unitFees) + unitCaps, err := state.GetBlockUnitCaps() + if err != nil { + return nil, nil, nil, err + } + for _, tx := range txs { txExecutor := executor.StandardTxExecutor{ Backend: v.txExecutorBackend, BlkFeeManager: feeManager, + UnitCaps: unitCaps, State: state, Tx: tx, } diff --git a/vms/platformvm/block/executor/verifier_test.go b/vms/platformvm/block/executor/verifier_test.go index 7a4fab27d81e..b77c54ac90ba 100644 --- a/vms/platformvm/block/executor/verifier_test.go +++ b/vms/platformvm/block/executor/verifier_test.go @@ -287,6 +287,7 @@ func TestVerifierVisitStandardBlock(t *testing.T) { timestamp := time.Now() parentState.EXPECT().GetTimestamp().Return(timestamp).Times(1) parentState.EXPECT().GetUnitFees().Return(fees.EmptyUnitFees, nil) + parentState.EXPECT().GetBlockUnitCaps().Return(fees.EmptyUnitCaps, nil) parentStatelessBlk.EXPECT().Height().Return(uint64(1)).Times(1) mempool.EXPECT().Remove(apricotBlk.Txs()).Times(1) @@ -767,6 +768,7 @@ func TestVerifierVisitStandardBlockWithDuplicateInputs(t *testing.T) { parentStatelessBlk.EXPECT().Height().Return(uint64(1)).Times(1) parentState.EXPECT().GetTimestamp().Return(timestamp).Times(1) parentState.EXPECT().GetUnitFees().Return(fees.EmptyUnitFees, nil) + parentState.EXPECT().GetBlockUnitCaps().Return(fees.EmptyUnitCaps, nil) parentStatelessBlk.EXPECT().Parent().Return(grandParentID).Times(1) err = verifier.ApricotStandardBlock(blk) diff --git a/vms/platformvm/txs/executor/atomic_tx_executor.go b/vms/platformvm/txs/executor/atomic_tx_executor.go index 86c63051e194..fc266f1b040a 100644 --- a/vms/platformvm/txs/executor/atomic_tx_executor.go +++ b/vms/platformvm/txs/executor/atomic_tx_executor.go @@ -104,6 +104,7 @@ func (e *AtomicTxExecutor) atomicTx(tx txs.UnsignedTx) error { executor := StandardTxExecutor{ Backend: e.Backend, BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), + UnitCaps: fees.EmptyUnitCaps, State: e.OnAccept, Tx: e.Tx, } diff --git a/vms/platformvm/txs/executor/create_chain_test.go b/vms/platformvm/txs/executor/create_chain_test.go index 693c70bc16f9..717f4af09f73 100644 --- a/vms/platformvm/txs/executor/create_chain_test.go +++ b/vms/platformvm/txs/executor/create_chain_test.go @@ -54,6 +54,7 @@ func TestCreateChainTxInsufficientControlSigs(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), + UnitCaps: fees.EmptyUnitCaps, State: stateDiff, Tx: tx, } @@ -96,6 +97,7 @@ func TestCreateChainTxWrongControlSig(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), + UnitCaps: fees.EmptyUnitCaps, State: stateDiff, Tx: tx, } @@ -132,6 +134,7 @@ func TestCreateChainTxNoSuchSubnet(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), + UnitCaps: fees.EmptyUnitCaps, State: stateDiff, Tx: tx, } @@ -165,6 +168,7 @@ func TestCreateChainTxValid(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), + UnitCaps: fees.EmptyUnitCaps, State: stateDiff, Tx: tx, } @@ -240,6 +244,7 @@ func TestCreateChainTxAP3FeeChange(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), + UnitCaps: fees.EmptyUnitCaps, State: stateDiff, Tx: tx, } diff --git a/vms/platformvm/txs/executor/create_subnet_test.go b/vms/platformvm/txs/executor/create_subnet_test.go index 1628ee11c6fe..1d104c4361c0 100644 --- a/vms/platformvm/txs/executor/create_subnet_test.go +++ b/vms/platformvm/txs/executor/create_subnet_test.go @@ -83,6 +83,7 @@ func TestCreateSubnetTxAP3FeeChange(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), + UnitCaps: fees.EmptyUnitCaps, State: stateDiff, Tx: tx, } diff --git a/vms/platformvm/txs/executor/helpers_test.go b/vms/platformvm/txs/executor/helpers_test.go index fb9759b42aa8..afdd90523694 100644 --- a/vms/platformvm/txs/executor/helpers_test.go +++ b/vms/platformvm/txs/executor/helpers_test.go @@ -208,9 +208,13 @@ func addSubnet( unitFees, err := env.state.GetUnitFees() require.NoError(err) + unitCaps, err := env.state.GetBlockUnitCaps() + require.NoError(err) + executor := StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: fees.NewManager(unitFees), + UnitCaps: unitCaps, State: stateDiff, Tx: testSubnet1, } diff --git a/vms/platformvm/txs/executor/standard_tx_executor_test.go b/vms/platformvm/txs/executor/standard_tx_executor_test.go index 1cd598adfeab..22ee8a9d2069 100644 --- a/vms/platformvm/txs/executor/standard_tx_executor_test.go +++ b/vms/platformvm/txs/executor/standard_tx_executor_test.go @@ -93,6 +93,7 @@ func TestStandardTxExecutorAddValidatorTxEmptyID(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), + UnitCaps: fees.EmptyUnitCaps, State: stateDiff, Tx: tx, } @@ -364,6 +365,7 @@ func TestStandardTxExecutorAddDelegator(t *testing.T) { executor := StandardTxExecutor{ Backend: &freshTH.backend, BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), + UnitCaps: fees.EmptyUnitCaps, State: onAcceptState, Tx: tx, } @@ -414,6 +416,7 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), + UnitCaps: fees.EmptyUnitCaps, State: onAcceptState, Tx: tx, } @@ -443,6 +446,7 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), + UnitCaps: fees.EmptyUnitCaps, State: onAcceptState, Tx: tx, } @@ -486,6 +490,7 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), + UnitCaps: fees.EmptyUnitCaps, State: onAcceptState, Tx: tx, } @@ -530,6 +535,7 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), + UnitCaps: fees.EmptyUnitCaps, State: onAcceptState, Tx: tx, } @@ -557,6 +563,7 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), + UnitCaps: fees.EmptyUnitCaps, State: onAcceptState, Tx: tx, } @@ -583,6 +590,7 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), + UnitCaps: fees.EmptyUnitCaps, State: onAcceptState, Tx: tx, } @@ -612,6 +620,7 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), + UnitCaps: fees.EmptyUnitCaps, State: onAcceptState, Tx: tx, } @@ -669,6 +678,7 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), + UnitCaps: fees.EmptyUnitCaps, State: onAcceptState, Tx: duplicateSubnetTx, } @@ -707,6 +717,7 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), + UnitCaps: fees.EmptyUnitCaps, State: onAcceptState, Tx: tx, } @@ -741,6 +752,7 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), + UnitCaps: fees.EmptyUnitCaps, State: onAcceptState, Tx: tx, } @@ -773,6 +785,7 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), + UnitCaps: fees.EmptyUnitCaps, State: onAcceptState, Tx: tx, } @@ -815,6 +828,7 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), + UnitCaps: fees.EmptyUnitCaps, State: onAcceptState, Tx: tx, } @@ -853,6 +867,7 @@ func TestStandardTxExecutorBanffAddValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), + UnitCaps: fees.EmptyUnitCaps, State: onAcceptState, Tx: tx, } @@ -880,6 +895,7 @@ func TestStandardTxExecutorBanffAddValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), + UnitCaps: fees.EmptyUnitCaps, State: onAcceptState, Tx: tx, } @@ -920,6 +936,7 @@ func TestStandardTxExecutorBanffAddValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), + UnitCaps: fees.EmptyUnitCaps, State: onAcceptState, Tx: tx, } @@ -957,6 +974,7 @@ func TestStandardTxExecutorBanffAddValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), + UnitCaps: fees.EmptyUnitCaps, State: onAcceptState, Tx: tx, } @@ -993,6 +1011,7 @@ func TestStandardTxExecutorBanffAddValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), + UnitCaps: fees.EmptyUnitCaps, State: onAcceptState, Tx: tx, } @@ -1184,6 +1203,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { Ctx: &snow.Context{}, }, BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), + UnitCaps: fees.EmptyUnitCaps, Tx: env.tx, State: env.state, } @@ -1215,6 +1235,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { Ctx: &snow.Context{}, }, BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), + UnitCaps: fees.EmptyUnitCaps, Tx: env.tx, State: env.state, } @@ -1246,6 +1267,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { Ctx: &snow.Context{}, }, BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), + UnitCaps: fees.EmptyUnitCaps, Tx: env.tx, State: env.state, } @@ -1280,6 +1302,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { Ctx: &snow.Context{}, }, BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), + UnitCaps: fees.EmptyUnitCaps, Tx: env.tx, State: env.state, } @@ -1312,6 +1335,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { Ctx: &snow.Context{}, }, BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), + UnitCaps: fees.EmptyUnitCaps, Tx: env.tx, State: env.state, } @@ -1343,6 +1367,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { Ctx: &snow.Context{}, }, BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), + UnitCaps: fees.EmptyUnitCaps, Tx: env.tx, State: env.state, } @@ -1376,6 +1401,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { Ctx: &snow.Context{}, }, BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), + UnitCaps: fees.EmptyUnitCaps, Tx: env.tx, State: env.state, } @@ -1413,6 +1439,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { Ctx: &snow.Context{}, }, BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), + UnitCaps: fees.EmptyUnitCaps, Tx: env.tx, State: env.state, } @@ -1574,6 +1601,7 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { Ctx: &snow.Context{}, }, BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), + UnitCaps: fees.EmptyUnitCaps, Tx: env.tx, State: env.state, } @@ -1604,6 +1632,7 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { Ctx: &snow.Context{}, }, BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), + UnitCaps: fees.EmptyUnitCaps, Tx: env.tx, State: env.state, } @@ -1636,6 +1665,7 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { Ctx: &snow.Context{}, }, BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), + UnitCaps: fees.EmptyUnitCaps, Tx: env.tx, State: env.state, } @@ -1673,6 +1703,7 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { Ctx: &snow.Context{}, }, BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), + UnitCaps: fees.EmptyUnitCaps, Tx: env.tx, State: env.state, } @@ -1715,6 +1746,7 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { Ctx: &snow.Context{}, }, BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), + UnitCaps: fees.EmptyUnitCaps, Tx: env.tx, State: env.state, } diff --git a/vms/platformvm/txs/executor/tx_mempool_verifier.go b/vms/platformvm/txs/executor/tx_mempool_verifier.go index f1f2248e8454..fa1fe9493642 100644 --- a/vms/platformvm/txs/executor/tx_mempool_verifier.go +++ b/vms/platformvm/txs/executor/tx_mempool_verifier.go @@ -95,9 +95,15 @@ func (v *MempoolTxVerifier) standardTx(tx txs.UnsignedTx) error { return err } + unitCaps, err := baseState.GetBlockUnitCaps() + if err != nil { + return err + } + executor := StandardTxExecutor{ Backend: v.Backend, BlkFeeManager: fees.NewManager(unitFees), + UnitCaps: unitCaps, State: baseState, Tx: v.Tx, } From 9ed258d58fd31505b2020cc731889abd11eeb317 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 22 Jan 2024 22:05:26 +0100 Subject: [PATCH 058/190] wip: multifee tx construction in wallet --- wallet/chain/p/builder_dynamic_fees.go | 424 +++++++++++++++++++++++++ 1 file changed, 424 insertions(+) create mode 100644 wallet/chain/p/builder_dynamic_fees.go diff --git a/wallet/chain/p/builder_dynamic_fees.go b/wallet/chain/p/builder_dynamic_fees.go new file mode 100644 index 000000000000..faab16747660 --- /dev/null +++ b/wallet/chain/p/builder_dynamic_fees.go @@ -0,0 +1,424 @@ +// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package p + +import ( + "fmt" + + "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/utils" + "github.com/ava-labs/avalanchego/utils/constants" + "github.com/ava-labs/avalanchego/utils/math" + "github.com/ava-labs/avalanchego/utils/set" + "github.com/ava-labs/avalanchego/vms/components/avax" + "github.com/ava-labs/avalanchego/vms/platformvm/stakeable" + "github.com/ava-labs/avalanchego/vms/platformvm/txs" + "github.com/ava-labs/avalanchego/vms/platformvm/txs/fees" + "github.com/ava-labs/avalanchego/vms/secp256k1fx" + "github.com/ava-labs/avalanchego/wallet/subnet/primary/common" + + commonfees "github.com/ava-labs/avalanchego/vms/components/fees" +) + +type DynamicFeesBuilder struct { + addrs set.Set[ids.ShortID] + backend BuilderBackend +} + +func (b *DynamicFeesBuilder) NewCreateChainTx( + subnetID ids.ID, + genesis []byte, + vmID ids.ID, + fxIDs []ids.ID, + chainName string, + unitFees, unitCaps commonfees.Dimensions, + options ...common.Option, +) (*txs.CreateChainTx, error) { + // 1. Build core transaction without utxos + ops := common.NewOptions(options) + subnetAuth, err := b.authorizeSubnet(subnetID, ops) + if err != nil { + return nil, err + } + + utils.Sort(fxIDs) + + uTx := &txs.CreateChainTx{ + BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ + NetworkID: b.backend.NetworkID(), + BlockchainID: constants.PlatformChainID, + Memo: ops.Memo(), + }}, + SubnetID: subnetID, + ChainName: chainName, + VMID: vmID, + FxIDs: fxIDs, + GenesisData: genesis, + SubnetAuth: subnetAuth, + } + + // 2. Finance the tx by building the utxos (inputs, outputs and stakes) + feesMan := commonfees.NewManager(unitFees) + feeCalc := &fees.Calculator{ + IsEForkActive: true, + FeeManager: feesMan, + ConsumedUnitsCap: unitCaps, + } + + // feesMan cumulates consumed units. Let's init it with utx filled so far + if err = feeCalc.CreateChainTx(uTx); err != nil { + return nil, err + } + + toStake := map[ids.ID]uint64{} + toBurn := map[ids.ID]uint64{} // fees are calculated in financeTx + inputs, outputs, _, err := b.financeTx(toBurn, toStake, feeCalc, ops) + if err != nil { + return nil, err + } + + uTx.Ins = inputs + uTx.Outs = outputs + + // 3. Sign the tx. Maybe not needed + return uTx, b.initCtx(uTx) +} + +func (b *DynamicFeesBuilder) financeTx( + amountsToBurn map[ids.ID]uint64, + amountsToStake map[ids.ID]uint64, + feeCalc *fees.Calculator, + options *common.Options, +) ( + inputs []*avax.TransferableInput, + changeOutputs []*avax.TransferableOutput, + stakeOutputs []*avax.TransferableOutput, + err error, +) { + utxos, err := b.backend.UTXOs(options.Context(), constants.PlatformChainID) + if err != nil { + return nil, nil, nil, err + } + + addrs := options.Addresses(b.addrs) + minIssuanceTime := options.MinIssuanceTime() + + addr, ok := addrs.Peek() + if !ok { + return nil, nil, nil, errNoChangeAddress + } + changeOwner := options.ChangeOwner(&secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{addr}, + }) + + amountsToBurn[b.backend.AVAXAssetID()] += feeCalc.Fee + + // Iterate over the locked UTXOs + for _, utxo := range utxos { + assetID := utxo.AssetID() + + // If we have staked enough of the asset, then we have no need burn + // more. + if amountsToStake[assetID] == 0 { + continue + } + + outIntf := utxo.Out + lockedOut, ok := outIntf.(*stakeable.LockOut) + if !ok { + // This output isn't locked, so it will be handled during the next + // iteration of the UTXO set + continue + } + if minIssuanceTime >= lockedOut.Locktime { + // This output isn't locked, so it will be handled during the next + // iteration of the UTXO set + continue + } + + out, ok := lockedOut.TransferableOut.(*secp256k1fx.TransferOutput) + if !ok { + return nil, nil, nil, errUnknownOutputType + } + + inputSigIndices, ok := common.MatchOwners(&out.OutputOwners, addrs, minIssuanceTime) + if !ok { + // We couldn't spend this UTXO, so we skip to the next one + continue + } + + input := &avax.TransferableInput{ + UTXOID: utxo.UTXOID, + Asset: utxo.Asset, + In: &stakeable.LockIn{ + Locktime: lockedOut.Locktime, + TransferableIn: &secp256k1fx.TransferInput{ + Amt: out.Amt, + Input: secp256k1fx.Input{ + SigIndices: inputSigIndices, + }, + }, + }, + } + + // update fees to account for the input added + insDimensions, err := commonfees.GetInputsDimensions(txs.Codec, txs.CodecVersion, []*avax.TransferableInput{input}) + if err != nil { + return nil, nil, nil, fmt.Errorf("failed calculating input size: %w", err) + } + if err := feeCalc.AddFeesFor(insDimensions); err != nil { + return nil, nil, nil, fmt.Errorf("account for input fees: %w", err) + } + amountsToBurn[b.backend.AVAXAssetID()] += feeCalc.Fee + + inputs = append(inputs, input) + + // Stake any value that should be staked + amountToStake := math.Min( + amountsToStake[assetID], // Amount we still need to stake + out.Amt, // Amount available to stake + ) + + // Add the output to the staked outputs + stakeOut := &avax.TransferableOutput{ + Asset: utxo.Asset, + Out: &stakeable.LockOut{ + Locktime: lockedOut.Locktime, + TransferableOut: &secp256k1fx.TransferOutput{ + Amt: amountToStake, + OutputOwners: out.OutputOwners, + }, + }, + } + + // update fees to account for the staked output + outDimensions, err := commonfees.GetOutputsDimensions(txs.Codec, txs.CodecVersion, []*avax.TransferableOutput{stakeOut}) + if err != nil { + return nil, nil, nil, fmt.Errorf("failed calculating stakedOut size: %w", err) + } + if err := feeCalc.AddFeesFor(outDimensions); err != nil { + return nil, nil, nil, fmt.Errorf("account for stakedOut fees: %w", err) + } + amountsToBurn[b.backend.AVAXAssetID()] += feeCalc.Fee + + stakeOutputs = append(stakeOutputs, stakeOut) + + amountsToStake[assetID] -= amountToStake + if remainingAmount := out.Amt - amountToStake; remainingAmount > 0 { + // This input had extra value, so some of it must be returned + changeOut := &avax.TransferableOutput{ + Asset: utxo.Asset, + Out: &stakeable.LockOut{ + Locktime: lockedOut.Locktime, + TransferableOut: &secp256k1fx.TransferOutput{ + Amt: remainingAmount, + OutputOwners: out.OutputOwners, + }, + }, + } + + // update fees to account for the change output + outDimensions, err := commonfees.GetOutputsDimensions(txs.Codec, txs.CodecVersion, []*avax.TransferableOutput{changeOut}) + if err != nil { + return nil, nil, nil, fmt.Errorf("failed calculating changeOut size: %w", err) + } + if err := feeCalc.AddFeesFor(outDimensions); err != nil { + return nil, nil, nil, fmt.Errorf("account for stakedOut fees: %w", err) + } + amountsToBurn[b.backend.AVAXAssetID()] += feeCalc.Fee + + changeOutputs = append(changeOutputs, changeOut) + } + } + + // Iterate over the unlocked UTXOs + for _, utxo := range utxos { + assetID := utxo.AssetID() + + // If we have consumed enough of the asset, then we have no need burn + // more. + if amountsToStake[assetID] == 0 && amountsToBurn[assetID] == 0 { + continue + } + + outIntf := utxo.Out + if lockedOut, ok := outIntf.(*stakeable.LockOut); ok { + if lockedOut.Locktime > minIssuanceTime { + // This output is currently locked, so this output can't be + // burned. + continue + } + outIntf = lockedOut.TransferableOut + } + + out, ok := outIntf.(*secp256k1fx.TransferOutput) + if !ok { + return nil, nil, nil, errUnknownOutputType + } + + inputSigIndices, ok := common.MatchOwners(&out.OutputOwners, addrs, minIssuanceTime) + if !ok { + // We couldn't spend this UTXO, so we skip to the next one + continue + } + + input := &avax.TransferableInput{ + UTXOID: utxo.UTXOID, + Asset: utxo.Asset, + In: &secp256k1fx.TransferInput{ + Amt: out.Amt, + Input: secp256k1fx.Input{ + SigIndices: inputSigIndices, + }, + }, + } + + // update fees to account for the input added + insDimensions, err := commonfees.GetInputsDimensions(txs.Codec, txs.CodecVersion, []*avax.TransferableInput{input}) + if err != nil { + return nil, nil, nil, fmt.Errorf("failed calculating input size: %w", err) + } + if err := feeCalc.AddFeesFor(insDimensions); err != nil { + return nil, nil, nil, fmt.Errorf("account for input fees: %w", err) + } + amountsToBurn[b.backend.AVAXAssetID()] += feeCalc.Fee + + inputs = append(inputs, input) + + // Burn any value that should be burned + amountToBurn := math.Min( + amountsToBurn[assetID], // Amount we still need to burn + out.Amt, // Amount available to burn + ) + amountsToBurn[assetID] -= amountToBurn + + amountAvalibleToStake := out.Amt - amountToBurn + // Burn any value that should be burned + amountToStake := math.Min( + amountsToStake[assetID], // Amount we still need to stake + amountAvalibleToStake, // Amount available to stake + ) + amountsToStake[assetID] -= amountToStake + if amountToStake > 0 { + // Some of this input was put for staking + stakeOut := &avax.TransferableOutput{ + Asset: utxo.Asset, + Out: &secp256k1fx.TransferOutput{ + Amt: amountToStake, + OutputOwners: *changeOwner, + }, + } + + stakeOutputs = append(stakeOutputs, stakeOut) + + // update fees to account for the staked output + outDimensions, err := commonfees.GetOutputsDimensions(txs.Codec, txs.CodecVersion, []*avax.TransferableOutput{stakeOut}) + if err != nil { + return nil, nil, nil, fmt.Errorf("failed calculating stakedOut size: %w", err) + } + if err := feeCalc.AddFeesFor(outDimensions); err != nil { + return nil, nil, nil, fmt.Errorf("account for stakedOut fees: %w", err) + } + amountsToBurn[b.backend.AVAXAssetID()] += feeCalc.Fee + } + + if remainingAmount := amountAvalibleToStake - amountToStake; remainingAmount > 0 { + // This input had extra value, so some of it must be returned, once fees are removed + changeOut := &avax.TransferableOutput{ + Asset: utxo.Asset, + Out: &secp256k1fx.TransferOutput{ + OutputOwners: *changeOwner, + }, + } + + // update fees to account for the change output + outDimensions, err := commonfees.GetOutputsDimensions(txs.Codec, txs.CodecVersion, []*avax.TransferableOutput{changeOut}) + if err != nil { + return nil, nil, nil, fmt.Errorf("failed calculating changeOut size: %w", err) + } + if err := feeCalc.AddFeesFor(outDimensions); err != nil { + return nil, nil, nil, fmt.Errorf("account for stakedOut fees: %w", err) + } + + switch { + case feeCalc.Fee < remainingAmount: + changeOut.Out.(*secp256k1fx.TransferOutput).Amt = remainingAmount - feeCalc.Fee + changeOutputs = append(changeOutputs, changeOut) + case feeCalc.Fee == remainingAmount: + // fees wholly consume remaining amount. We don't add the change + case feeCalc.Fee > remainingAmount: + amountsToBurn[b.backend.AVAXAssetID()] += feeCalc.Fee - remainingAmount + } + } + } + + for assetID, amount := range amountsToStake { + if amount != 0 { + return nil, nil, nil, fmt.Errorf( + "%w: provided UTXOs need %d more units of asset %q to stake", + errInsufficientFunds, + amount, + assetID, + ) + } + } + for assetID, amount := range amountsToBurn { + if amount != 0 { + return nil, nil, nil, fmt.Errorf( + "%w: provided UTXOs need %d more units of asset %q", + errInsufficientFunds, + amount, + assetID, + ) + } + } + + utils.Sort(inputs) // sort inputs + avax.SortTransferableOutputs(changeOutputs, txs.Codec) // sort the change outputs + avax.SortTransferableOutputs(stakeOutputs, txs.Codec) // sort stake outputs + return inputs, changeOutputs, stakeOutputs, nil +} + +// TODO ABENEGIA: remove duplication with builder method +func (b *DynamicFeesBuilder) authorizeSubnet(subnetID ids.ID, options *common.Options) (*secp256k1fx.Input, error) { + subnetTx, err := b.backend.GetTx(options.Context(), subnetID) + if err != nil { + return nil, fmt.Errorf( + "failed to fetch subnet %q: %w", + subnetID, + err, + ) + } + subnet, ok := subnetTx.Unsigned.(*txs.CreateSubnetTx) + if !ok { + return nil, errWrongTxType + } + + owner, ok := subnet.Owner.(*secp256k1fx.OutputOwners) + if !ok { + return nil, errUnknownOwnerType + } + + addrs := options.Addresses(b.addrs) + minIssuanceTime := options.MinIssuanceTime() + inputSigIndices, ok := common.MatchOwners(owner, addrs, minIssuanceTime) + if !ok { + // We can't authorize the subnet + return nil, errInsufficientAuthorization + } + return &secp256k1fx.Input{ + SigIndices: inputSigIndices, + }, nil +} + +func (b *DynamicFeesBuilder) initCtx(tx txs.UnsignedTx) error { + ctx, err := newSnowContext(b.backend) + if err != nil { + return err + } + + tx.InitCtx(ctx) + return nil +} From 9c123f0c9b2b911f8a2d719632bfbf98f5ff50fb Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 22 Jan 2024 22:05:26 +0100 Subject: [PATCH 059/190] wip: multifee tx construction in wallet --- vms/components/fees/helpers.go | 17 + wallet/chain/p/builder_dynamic_fees.go | 443 +++++++++++++++++++++++++ 2 files changed, 460 insertions(+) create mode 100644 wallet/chain/p/builder_dynamic_fees.go diff --git a/vms/components/fees/helpers.go b/vms/components/fees/helpers.go index 3fe2d427706d..fa3108d1e390 100644 --- a/vms/components/fees/helpers.go +++ b/vms/components/fees/helpers.go @@ -7,7 +7,9 @@ import ( "fmt" "github.com/ava-labs/avalanchego/codec" + "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" "github.com/ava-labs/avalanchego/vms/components/avax" + "github.com/ava-labs/avalanchego/vms/secp256k1fx" ) func GetInputsDimensions(c codec.Manager, v uint16, ins []*avax.TransferableInput) (Dimensions, error) { @@ -45,3 +47,18 @@ func GetOutputsDimensions(c codec.Manager, v uint16, outs []*avax.TransferableOu } return consumedUnits, nil } + +func GetCredentialsDimensions(c codec.Manager, v uint16, inputSigIndices []uint32) (Dimensions, error) { + var consumedUnits Dimensions + + cred := &secp256k1fx.Credential{ + Sigs: make([][secp256k1.SignatureLen]byte, len(inputSigIndices)), + } + + credSize, err := c.Size(v, cred) + if err != nil { + return consumedUnits, fmt.Errorf("failed retrieving size of credentials: %w", err) + } + consumedUnits[Bandwidth] += uint64(credSize) - codec.CodecVersionSize + return consumedUnits, nil +} diff --git a/wallet/chain/p/builder_dynamic_fees.go b/wallet/chain/p/builder_dynamic_fees.go new file mode 100644 index 000000000000..9754c6662309 --- /dev/null +++ b/wallet/chain/p/builder_dynamic_fees.go @@ -0,0 +1,443 @@ +// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package p + +import ( + "fmt" + + "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/utils" + "github.com/ava-labs/avalanchego/utils/constants" + "github.com/ava-labs/avalanchego/utils/math" + "github.com/ava-labs/avalanchego/utils/set" + "github.com/ava-labs/avalanchego/vms/components/avax" + "github.com/ava-labs/avalanchego/vms/platformvm/stakeable" + "github.com/ava-labs/avalanchego/vms/platformvm/txs" + "github.com/ava-labs/avalanchego/vms/platformvm/txs/fees" + "github.com/ava-labs/avalanchego/vms/secp256k1fx" + "github.com/ava-labs/avalanchego/wallet/subnet/primary/common" + + commonfees "github.com/ava-labs/avalanchego/vms/components/fees" +) + +type DynamicFeesBuilder struct { + addrs set.Set[ids.ShortID] + backend BuilderBackend +} + +func (b *DynamicFeesBuilder) NewCreateChainTx( + subnetID ids.ID, + genesis []byte, + vmID ids.ID, + fxIDs []ids.ID, + chainName string, + unitFees, unitCaps commonfees.Dimensions, + options ...common.Option, +) (*txs.CreateChainTx, error) { + // 1. Build core transaction without utxos + ops := common.NewOptions(options) + subnetAuth, err := b.authorizeSubnet(subnetID, ops) + if err != nil { + return nil, err + } + + utils.Sort(fxIDs) + + uTx := &txs.CreateChainTx{ + BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ + NetworkID: b.backend.NetworkID(), + BlockchainID: constants.PlatformChainID, + Memo: ops.Memo(), + }}, + SubnetID: subnetID, + ChainName: chainName, + VMID: vmID, + FxIDs: fxIDs, + GenesisData: genesis, + SubnetAuth: subnetAuth, + } + + // 2. Finance the tx by building the utxos (inputs, outputs and stakes) + feesMan := commonfees.NewManager(unitFees) + feeCalc := &fees.Calculator{ + IsEForkActive: true, + FeeManager: feesMan, + ConsumedUnitsCap: unitCaps, + } + + // feesMan cumulates consumed units. Let's init it with utx filled so far + if err = feeCalc.CreateChainTx(uTx); err != nil { + return nil, err + } + + toStake := map[ids.ID]uint64{} + toBurn := map[ids.ID]uint64{} // fees are calculated in financeTx + inputs, outputs, _, err := b.financeTx(toBurn, toStake, feeCalc, ops) + if err != nil { + return nil, err + } + + uTx.Ins = inputs + uTx.Outs = outputs + + return uTx, b.initCtx(uTx) +} + +func (b *DynamicFeesBuilder) financeTx( + amountsToBurn map[ids.ID]uint64, + amountsToStake map[ids.ID]uint64, + feeCalc *fees.Calculator, + options *common.Options, +) ( + inputs []*avax.TransferableInput, + changeOutputs []*avax.TransferableOutput, + stakeOutputs []*avax.TransferableOutput, + err error, +) { + utxos, err := b.backend.UTXOs(options.Context(), constants.PlatformChainID) + if err != nil { + return nil, nil, nil, err + } + + addrs := options.Addresses(b.addrs) + minIssuanceTime := options.MinIssuanceTime() + + addr, ok := addrs.Peek() + if !ok { + return nil, nil, nil, errNoChangeAddress + } + changeOwner := options.ChangeOwner(&secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{addr}, + }) + + amountsToBurn[b.backend.AVAXAssetID()] += feeCalc.Fee + + // Iterate over the locked UTXOs + for _, utxo := range utxos { + assetID := utxo.AssetID() + + // If we have staked enough of the asset, then we have no need burn + // more. + if amountsToStake[assetID] == 0 { + continue + } + + outIntf := utxo.Out + lockedOut, ok := outIntf.(*stakeable.LockOut) + if !ok { + // This output isn't locked, so it will be handled during the next + // iteration of the UTXO set + continue + } + if minIssuanceTime >= lockedOut.Locktime { + // This output isn't locked, so it will be handled during the next + // iteration of the UTXO set + continue + } + + out, ok := lockedOut.TransferableOut.(*secp256k1fx.TransferOutput) + if !ok { + return nil, nil, nil, errUnknownOutputType + } + + inputSigIndices, ok := common.MatchOwners(&out.OutputOwners, addrs, minIssuanceTime) + if !ok { + // We couldn't spend this UTXO, so we skip to the next one + continue + } + + input := &avax.TransferableInput{ + UTXOID: utxo.UTXOID, + Asset: utxo.Asset, + In: &stakeable.LockIn{ + Locktime: lockedOut.Locktime, + TransferableIn: &secp256k1fx.TransferInput{ + Amt: out.Amt, + Input: secp256k1fx.Input{ + SigIndices: inputSigIndices, + }, + }, + }, + } + + // update fees to account for the input added + insDimensions, err := commonfees.GetInputsDimensions(txs.Codec, txs.CodecVersion, []*avax.TransferableInput{input}) + if err != nil { + return nil, nil, nil, fmt.Errorf("failed calculating input size: %w", err) + } + if err := feeCalc.AddFeesFor(insDimensions); err != nil { + return nil, nil, nil, fmt.Errorf("account for input fees: %w", err) + } + amountsToBurn[b.backend.AVAXAssetID()] += feeCalc.Fee + + // update fees to account for the credentials to be added with inputs upon tx signing + credsDimensions, err := commonfees.GetCredentialsDimensions(txs.Codec, txs.CodecVersion, inputSigIndices) + if err != nil { + return nil, nil, nil, fmt.Errorf("failed calculating input size: %w", err) + } + if err := feeCalc.AddFeesFor(credsDimensions); err != nil { + return nil, nil, nil, fmt.Errorf("account for input fees: %w", err) + } + amountsToBurn[b.backend.AVAXAssetID()] += feeCalc.Fee + + inputs = append(inputs, input) + + // Stake any value that should be staked + amountToStake := math.Min( + amountsToStake[assetID], // Amount we still need to stake + out.Amt, // Amount available to stake + ) + + // Add the output to the staked outputs + stakeOut := &avax.TransferableOutput{ + Asset: utxo.Asset, + Out: &stakeable.LockOut{ + Locktime: lockedOut.Locktime, + TransferableOut: &secp256k1fx.TransferOutput{ + Amt: amountToStake, + OutputOwners: out.OutputOwners, + }, + }, + } + + // update fees to account for the staked output + outDimensions, err := commonfees.GetOutputsDimensions(txs.Codec, txs.CodecVersion, []*avax.TransferableOutput{stakeOut}) + if err != nil { + return nil, nil, nil, fmt.Errorf("failed calculating stakedOut size: %w", err) + } + if err := feeCalc.AddFeesFor(outDimensions); err != nil { + return nil, nil, nil, fmt.Errorf("account for stakedOut fees: %w", err) + } + amountsToBurn[b.backend.AVAXAssetID()] += feeCalc.Fee + + stakeOutputs = append(stakeOutputs, stakeOut) + + amountsToStake[assetID] -= amountToStake + if remainingAmount := out.Amt - amountToStake; remainingAmount > 0 { + // This input had extra value, so some of it must be returned + changeOut := &avax.TransferableOutput{ + Asset: utxo.Asset, + Out: &stakeable.LockOut{ + Locktime: lockedOut.Locktime, + TransferableOut: &secp256k1fx.TransferOutput{ + Amt: remainingAmount, + OutputOwners: out.OutputOwners, + }, + }, + } + + // update fees to account for the change output + outDimensions, err := commonfees.GetOutputsDimensions(txs.Codec, txs.CodecVersion, []*avax.TransferableOutput{changeOut}) + if err != nil { + return nil, nil, nil, fmt.Errorf("failed calculating changeOut size: %w", err) + } + if err := feeCalc.AddFeesFor(outDimensions); err != nil { + return nil, nil, nil, fmt.Errorf("account for stakedOut fees: %w", err) + } + amountsToBurn[b.backend.AVAXAssetID()] += feeCalc.Fee + + changeOutputs = append(changeOutputs, changeOut) + } + } + + // Iterate over the unlocked UTXOs + for _, utxo := range utxos { + assetID := utxo.AssetID() + + // If we have consumed enough of the asset, then we have no need burn + // more. + if amountsToStake[assetID] == 0 && amountsToBurn[assetID] == 0 { + continue + } + + outIntf := utxo.Out + if lockedOut, ok := outIntf.(*stakeable.LockOut); ok { + if lockedOut.Locktime > minIssuanceTime { + // This output is currently locked, so this output can't be + // burned. + continue + } + outIntf = lockedOut.TransferableOut + } + + out, ok := outIntf.(*secp256k1fx.TransferOutput) + if !ok { + return nil, nil, nil, errUnknownOutputType + } + + inputSigIndices, ok := common.MatchOwners(&out.OutputOwners, addrs, minIssuanceTime) + if !ok { + // We couldn't spend this UTXO, so we skip to the next one + continue + } + + input := &avax.TransferableInput{ + UTXOID: utxo.UTXOID, + Asset: utxo.Asset, + In: &secp256k1fx.TransferInput{ + Amt: out.Amt, + Input: secp256k1fx.Input{ + SigIndices: inputSigIndices, + }, + }, + } + + // update fees to account for the input added + insDimensions, err := commonfees.GetInputsDimensions(txs.Codec, txs.CodecVersion, []*avax.TransferableInput{input}) + if err != nil { + return nil, nil, nil, fmt.Errorf("failed calculating input size: %w", err) + } + if err := feeCalc.AddFeesFor(insDimensions); err != nil { + return nil, nil, nil, fmt.Errorf("account for input fees: %w", err) + } + amountsToBurn[b.backend.AVAXAssetID()] += feeCalc.Fee + + // update fees to account for the credentials to be added with inputs upon tx signing + credsDimensions, err := commonfees.GetCredentialsDimensions(txs.Codec, txs.CodecVersion, inputSigIndices) + if err != nil { + return nil, nil, nil, fmt.Errorf("failed calculating input size: %w", err) + } + if err := feeCalc.AddFeesFor(credsDimensions); err != nil { + return nil, nil, nil, fmt.Errorf("account for input fees: %w", err) + } + amountsToBurn[b.backend.AVAXAssetID()] += feeCalc.Fee + + inputs = append(inputs, input) + + // Burn any value that should be burned + amountToBurn := math.Min( + amountsToBurn[assetID], // Amount we still need to burn + out.Amt, // Amount available to burn + ) + amountsToBurn[assetID] -= amountToBurn + + amountAvalibleToStake := out.Amt - amountToBurn + // Burn any value that should be burned + amountToStake := math.Min( + amountsToStake[assetID], // Amount we still need to stake + amountAvalibleToStake, // Amount available to stake + ) + amountsToStake[assetID] -= amountToStake + if amountToStake > 0 { + // Some of this input was put for staking + stakeOut := &avax.TransferableOutput{ + Asset: utxo.Asset, + Out: &secp256k1fx.TransferOutput{ + Amt: amountToStake, + OutputOwners: *changeOwner, + }, + } + + stakeOutputs = append(stakeOutputs, stakeOut) + + // update fees to account for the staked output + outDimensions, err := commonfees.GetOutputsDimensions(txs.Codec, txs.CodecVersion, []*avax.TransferableOutput{stakeOut}) + if err != nil { + return nil, nil, nil, fmt.Errorf("failed calculating stakedOut size: %w", err) + } + if err := feeCalc.AddFeesFor(outDimensions); err != nil { + return nil, nil, nil, fmt.Errorf("account for stakedOut fees: %w", err) + } + amountsToBurn[b.backend.AVAXAssetID()] += feeCalc.Fee + } + + if remainingAmount := amountAvalibleToStake - amountToStake; remainingAmount > 0 { + // This input had extra value, so some of it must be returned, once fees are removed + changeOut := &avax.TransferableOutput{ + Asset: utxo.Asset, + Out: &secp256k1fx.TransferOutput{ + OutputOwners: *changeOwner, + }, + } + + // update fees to account for the change output + outDimensions, err := commonfees.GetOutputsDimensions(txs.Codec, txs.CodecVersion, []*avax.TransferableOutput{changeOut}) + if err != nil { + return nil, nil, nil, fmt.Errorf("failed calculating changeOut size: %w", err) + } + if err := feeCalc.AddFeesFor(outDimensions); err != nil { + return nil, nil, nil, fmt.Errorf("account for stakedOut fees: %w", err) + } + + switch { + case feeCalc.Fee < remainingAmount: + changeOut.Out.(*secp256k1fx.TransferOutput).Amt = remainingAmount - feeCalc.Fee + changeOutputs = append(changeOutputs, changeOut) + case feeCalc.Fee == remainingAmount: + // fees wholly consume remaining amount. We don't add the change + case feeCalc.Fee > remainingAmount: + amountsToBurn[b.backend.AVAXAssetID()] += feeCalc.Fee - remainingAmount + } + } + } + + for assetID, amount := range amountsToStake { + if amount != 0 { + return nil, nil, nil, fmt.Errorf( + "%w: provided UTXOs need %d more units of asset %q to stake", + errInsufficientFunds, + amount, + assetID, + ) + } + } + for assetID, amount := range amountsToBurn { + if amount != 0 { + return nil, nil, nil, fmt.Errorf( + "%w: provided UTXOs need %d more units of asset %q", + errInsufficientFunds, + amount, + assetID, + ) + } + } + + utils.Sort(inputs) // sort inputs + avax.SortTransferableOutputs(changeOutputs, txs.Codec) // sort the change outputs + avax.SortTransferableOutputs(stakeOutputs, txs.Codec) // sort stake outputs + return inputs, changeOutputs, stakeOutputs, nil +} + +// TODO ABENEGIA: remove duplication with builder method +func (b *DynamicFeesBuilder) authorizeSubnet(subnetID ids.ID, options *common.Options) (*secp256k1fx.Input, error) { + subnetTx, err := b.backend.GetTx(options.Context(), subnetID) + if err != nil { + return nil, fmt.Errorf( + "failed to fetch subnet %q: %w", + subnetID, + err, + ) + } + subnet, ok := subnetTx.Unsigned.(*txs.CreateSubnetTx) + if !ok { + return nil, errWrongTxType + } + + owner, ok := subnet.Owner.(*secp256k1fx.OutputOwners) + if !ok { + return nil, errUnknownOwnerType + } + + addrs := options.Addresses(b.addrs) + minIssuanceTime := options.MinIssuanceTime() + inputSigIndices, ok := common.MatchOwners(owner, addrs, minIssuanceTime) + if !ok { + // We can't authorize the subnet + return nil, errInsufficientAuthorization + } + return &secp256k1fx.Input{ + SigIndices: inputSigIndices, + }, nil +} + +func (b *DynamicFeesBuilder) initCtx(tx txs.UnsignedTx) error { + ctx, err := newSnowContext(b.backend) + if err != nil { + return err + } + + tx.InitCtx(ctx) + return nil +} From cbe4b04bd3a9d6634b46e1eab4bbe7ab2113fbb1 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Tue, 23 Jan 2024 22:53:25 +0100 Subject: [PATCH 060/190] added builder backend mock --- scripts/mocks.mockgen.txt | 1 + wallet/chain/p/mock_builderbackend.go | 213 ++++++++++++++++++++++++++ 2 files changed, 214 insertions(+) create mode 100644 wallet/chain/p/mock_builderbackend.go diff --git a/scripts/mocks.mockgen.txt b/scripts/mocks.mockgen.txt index ba2be886b0b6..4b5381b02f41 100644 --- a/scripts/mocks.mockgen.txt +++ b/scripts/mocks.mockgen.txt @@ -40,5 +40,6 @@ github.com/ava-labs/avalanchego/vms/proposervm=PostForkBlock=vms/proposervm/mock github.com/ava-labs/avalanchego/vms/registry=VMGetter=vms/registry/mock_vm_getter.go github.com/ava-labs/avalanchego/vms/registry=VMRegistry=vms/registry/mock_vm_registry.go github.com/ava-labs/avalanchego/vms=Factory,Manager=vms/mock_manager.go +github.com/ava-labs/avalanchego/wallet/chain/p=BuilderBackend=wallet/chain/p/mock_builderbackend.go github.com/ava-labs/avalanchego/x/sync=Client=x/sync/mock_client.go github.com/ava-labs/avalanchego/x/sync=NetworkClient=x/sync/mock_network_client.go diff --git a/wallet/chain/p/mock_builderbackend.go b/wallet/chain/p/mock_builderbackend.go new file mode 100644 index 000000000000..d46923be788b --- /dev/null +++ b/wallet/chain/p/mock_builderbackend.go @@ -0,0 +1,213 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/ava-labs/avalanchego/wallet/chain/p (interfaces: BuilderBackend) +// +// Generated by this command: +// +// mockgen -package=p -destination=wallet/chain/p/mock_builderbackend.go github.com/ava-labs/avalanchego/wallet/chain/p BuilderBackend +// + +// Package p is a generated GoMock package. +package p + +import ( + ctx "context" + reflect "reflect" + + ids "github.com/ava-labs/avalanchego/ids" + avax "github.com/ava-labs/avalanchego/vms/components/avax" + txs "github.com/ava-labs/avalanchego/vms/platformvm/txs" + gomock "go.uber.org/mock/gomock" +) + +// MockBuilderBackend is a mock of BuilderBackend interface. +type MockBuilderBackend struct { + ctrl *gomock.Controller + recorder *MockBuilderBackendMockRecorder +} + +// MockBuilderBackendMockRecorder is the mock recorder for MockBuilderBackend. +type MockBuilderBackendMockRecorder struct { + mock *MockBuilderBackend +} + +// NewMockBuilderBackend creates a new mock instance. +func NewMockBuilderBackend(ctrl *gomock.Controller) *MockBuilderBackend { + mock := &MockBuilderBackend{ctrl: ctrl} + mock.recorder = &MockBuilderBackendMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockBuilderBackend) EXPECT() *MockBuilderBackendMockRecorder { + return m.recorder +} + +// AVAXAssetID mocks base method. +func (m *MockBuilderBackend) AVAXAssetID() ids.ID { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AVAXAssetID") + ret0, _ := ret[0].(ids.ID) + return ret0 +} + +// AVAXAssetID indicates an expected call of AVAXAssetID. +func (mr *MockBuilderBackendMockRecorder) AVAXAssetID() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AVAXAssetID", reflect.TypeOf((*MockBuilderBackend)(nil).AVAXAssetID)) +} + +// AddPrimaryNetworkDelegatorFee mocks base method. +func (m *MockBuilderBackend) AddPrimaryNetworkDelegatorFee() uint64 { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AddPrimaryNetworkDelegatorFee") + ret0, _ := ret[0].(uint64) + return ret0 +} + +// AddPrimaryNetworkDelegatorFee indicates an expected call of AddPrimaryNetworkDelegatorFee. +func (mr *MockBuilderBackendMockRecorder) AddPrimaryNetworkDelegatorFee() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddPrimaryNetworkDelegatorFee", reflect.TypeOf((*MockBuilderBackend)(nil).AddPrimaryNetworkDelegatorFee)) +} + +// AddPrimaryNetworkValidatorFee mocks base method. +func (m *MockBuilderBackend) AddPrimaryNetworkValidatorFee() uint64 { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AddPrimaryNetworkValidatorFee") + ret0, _ := ret[0].(uint64) + return ret0 +} + +// AddPrimaryNetworkValidatorFee indicates an expected call of AddPrimaryNetworkValidatorFee. +func (mr *MockBuilderBackendMockRecorder) AddPrimaryNetworkValidatorFee() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddPrimaryNetworkValidatorFee", reflect.TypeOf((*MockBuilderBackend)(nil).AddPrimaryNetworkValidatorFee)) +} + +// AddSubnetDelegatorFee mocks base method. +func (m *MockBuilderBackend) AddSubnetDelegatorFee() uint64 { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AddSubnetDelegatorFee") + ret0, _ := ret[0].(uint64) + return ret0 +} + +// AddSubnetDelegatorFee indicates an expected call of AddSubnetDelegatorFee. +func (mr *MockBuilderBackendMockRecorder) AddSubnetDelegatorFee() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddSubnetDelegatorFee", reflect.TypeOf((*MockBuilderBackend)(nil).AddSubnetDelegatorFee)) +} + +// AddSubnetValidatorFee mocks base method. +func (m *MockBuilderBackend) AddSubnetValidatorFee() uint64 { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AddSubnetValidatorFee") + ret0, _ := ret[0].(uint64) + return ret0 +} + +// AddSubnetValidatorFee indicates an expected call of AddSubnetValidatorFee. +func (mr *MockBuilderBackendMockRecorder) AddSubnetValidatorFee() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddSubnetValidatorFee", reflect.TypeOf((*MockBuilderBackend)(nil).AddSubnetValidatorFee)) +} + +// BaseTxFee mocks base method. +func (m *MockBuilderBackend) BaseTxFee() uint64 { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BaseTxFee") + ret0, _ := ret[0].(uint64) + return ret0 +} + +// BaseTxFee indicates an expected call of BaseTxFee. +func (mr *MockBuilderBackendMockRecorder) BaseTxFee() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BaseTxFee", reflect.TypeOf((*MockBuilderBackend)(nil).BaseTxFee)) +} + +// CreateBlockchainTxFee mocks base method. +func (m *MockBuilderBackend) CreateBlockchainTxFee() uint64 { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateBlockchainTxFee") + ret0, _ := ret[0].(uint64) + return ret0 +} + +// CreateBlockchainTxFee indicates an expected call of CreateBlockchainTxFee. +func (mr *MockBuilderBackendMockRecorder) CreateBlockchainTxFee() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateBlockchainTxFee", reflect.TypeOf((*MockBuilderBackend)(nil).CreateBlockchainTxFee)) +} + +// CreateSubnetTxFee mocks base method. +func (m *MockBuilderBackend) CreateSubnetTxFee() uint64 { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateSubnetTxFee") + ret0, _ := ret[0].(uint64) + return ret0 +} + +// CreateSubnetTxFee indicates an expected call of CreateSubnetTxFee. +func (mr *MockBuilderBackendMockRecorder) CreateSubnetTxFee() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateSubnetTxFee", reflect.TypeOf((*MockBuilderBackend)(nil).CreateSubnetTxFee)) +} + +// GetTx mocks base method. +func (m *MockBuilderBackend) GetTx(arg0 ctx.Context, arg1 ids.ID) (*txs.Tx, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetTx", arg0, arg1) + ret0, _ := ret[0].(*txs.Tx) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetTx indicates an expected call of GetTx. +func (mr *MockBuilderBackendMockRecorder) GetTx(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTx", reflect.TypeOf((*MockBuilderBackend)(nil).GetTx), arg0, arg1) +} + +// NetworkID mocks base method. +func (m *MockBuilderBackend) NetworkID() uint32 { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NetworkID") + ret0, _ := ret[0].(uint32) + return ret0 +} + +// NetworkID indicates an expected call of NetworkID. +func (mr *MockBuilderBackendMockRecorder) NetworkID() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NetworkID", reflect.TypeOf((*MockBuilderBackend)(nil).NetworkID)) +} + +// TransformSubnetTxFee mocks base method. +func (m *MockBuilderBackend) TransformSubnetTxFee() uint64 { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TransformSubnetTxFee") + ret0, _ := ret[0].(uint64) + return ret0 +} + +// TransformSubnetTxFee indicates an expected call of TransformSubnetTxFee. +func (mr *MockBuilderBackendMockRecorder) TransformSubnetTxFee() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TransformSubnetTxFee", reflect.TypeOf((*MockBuilderBackend)(nil).TransformSubnetTxFee)) +} + +// UTXOs mocks base method. +func (m *MockBuilderBackend) UTXOs(arg0 ctx.Context, arg1 ids.ID) ([]*avax.UTXO, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UTXOs", arg0, arg1) + ret0, _ := ret[0].([]*avax.UTXO) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UTXOs indicates an expected call of UTXOs. +func (mr *MockBuilderBackendMockRecorder) UTXOs(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UTXOs", reflect.TypeOf((*MockBuilderBackend)(nil).UTXOs), arg0, arg1) +} From 456cde99e6dd2ffdf56dae4d373dd37796f07bd1 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Tue, 23 Jan 2024 23:17:18 +0100 Subject: [PATCH 061/190] wip adding UTs for dynamic fees builder --- wallet/chain/p/builder_dynamic_fees_test.go | 114 ++++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 wallet/chain/p/builder_dynamic_fees_test.go diff --git a/wallet/chain/p/builder_dynamic_fees_test.go b/wallet/chain/p/builder_dynamic_fees_test.go new file mode 100644 index 000000000000..42c7745bb1d1 --- /dev/null +++ b/wallet/chain/p/builder_dynamic_fees_test.go @@ -0,0 +1,114 @@ +// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package p + +import ( + "math" + "math/rand" + "testing" + + "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" + + "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/utils/constants" + "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" + "github.com/ava-labs/avalanchego/utils/set" + "github.com/ava-labs/avalanchego/utils/units" + "github.com/ava-labs/avalanchego/vms/platformvm/txs" + "github.com/ava-labs/avalanchego/vms/secp256k1fx" + + "github.com/ava-labs/avalanchego/vms/components/avax" + commonfees "github.com/ava-labs/avalanchego/vms/components/fees" +) + +var testKeys = secp256k1.TestKeys() + +func TestCreateChainTx(t *testing.T) { + require := require.New(t) + ctrl := gomock.NewController(t) + + be := NewMockBuilderBackend(ctrl) + + var ( + utxoKey = testKeys[0] + utxoAddr = utxoKey.PublicKey().Address() + ) + + b := &DynamicFeesBuilder{ + addrs: set.Of(utxoAddr), + backend: be, + } + + var ( + subnetID = ids.GenerateTestID() + genesisBytes = []byte{'a', 'b', 'c'} + vmID = ids.GenerateTestID() + fxIDs = []ids.ID{ids.GenerateTestID()} + chainName = "dummyChain" + ) + + var ( + testUnitFees = commonfees.Dimensions{ + 1 * units.MicroAvax, + 2 * units.MicroAvax, + 3 * units.MicroAvax, + 4 * units.MicroAvax, + } + testBlockMaxConsumedUnits = commonfees.Dimensions{ + math.MaxUint64, + math.MaxUint64, + math.MaxUint64, + math.MaxUint64, + } + ) + + be.EXPECT().GetTx(gomock.Any(), subnetID).Return( + &txs.Tx{ + Unsigned: &txs.CreateSubnetTx{ + Owner: &secp256k1fx.OutputOwners{}, + }, + }, + nil, + ) + + amount := 10 * units.Avax + avaxAssetID := ids.GenerateTestID() + be.EXPECT().AVAXAssetID().Return(avaxAssetID).AnyTimes() + be.EXPECT().NetworkID().Return(constants.MainnetID).AnyTimes() + + be.EXPECT().UTXOs(gomock.Any(), constants.PlatformChainID).Return( + []*avax.UTXO{ + &avax.UTXO{ + UTXOID: avax.UTXOID{ + TxID: ids.GenerateTestID(), + OutputIndex: rand.Uint32(), + }, + Asset: avax.Asset{ID: avaxAssetID}, + Out: &secp256k1fx.TransferOutput{ + Amt: uint64(amount), + OutputOwners: secp256k1fx.OutputOwners{ + Locktime: 0, + Addrs: []ids.ShortID{testKeys[0].PublicKey().Address()}, + Threshold: 1, + }, + }, + }, + }, + nil, + ) + + _, err := b.NewCreateChainTx( + subnetID, + genesisBytes, + vmID, + fxIDs, + chainName, + testUnitFees, + testBlockMaxConsumedUnits, + ) + require.NoError(err) + + // TODO: sign and verify fees can be paid +} From 4170845593ade3a9a4f417ed1891cdba8390e8e2 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Tue, 23 Jan 2024 23:40:19 +0100 Subject: [PATCH 062/190] wip: adding UTs for dynamic fees builder --- scripts/mocks.mockgen.txt | 3 +- wallet/chain/p/builder_dynamic_fees_test.go | 73 +++++++++++++------ ...lderbackend.go => mock_builder_backend.go} | 2 +- wallet/chain/p/mock_signer_backend.go | 73 +++++++++++++++++++ 4 files changed, 126 insertions(+), 25 deletions(-) rename wallet/chain/p/{mock_builderbackend.go => mock_builder_backend.go} (98%) create mode 100644 wallet/chain/p/mock_signer_backend.go diff --git a/scripts/mocks.mockgen.txt b/scripts/mocks.mockgen.txt index 4b5381b02f41..d338d08ba04f 100644 --- a/scripts/mocks.mockgen.txt +++ b/scripts/mocks.mockgen.txt @@ -40,6 +40,7 @@ github.com/ava-labs/avalanchego/vms/proposervm=PostForkBlock=vms/proposervm/mock github.com/ava-labs/avalanchego/vms/registry=VMGetter=vms/registry/mock_vm_getter.go github.com/ava-labs/avalanchego/vms/registry=VMRegistry=vms/registry/mock_vm_registry.go github.com/ava-labs/avalanchego/vms=Factory,Manager=vms/mock_manager.go -github.com/ava-labs/avalanchego/wallet/chain/p=BuilderBackend=wallet/chain/p/mock_builderbackend.go +github.com/ava-labs/avalanchego/wallet/chain/p=BuilderBackend=wallet/chain/p/mock_builder_backend.go +github.com/ava-labs/avalanchego/wallet/chain/p=SignerBackend=wallet/chain/p/mock_signer_backend.go github.com/ava-labs/avalanchego/x/sync=Client=x/sync/mock_client.go github.com/ava-labs/avalanchego/x/sync=NetworkClient=x/sync/mock_network_client.go diff --git a/wallet/chain/p/builder_dynamic_fees_test.go b/wallet/chain/p/builder_dynamic_fees_test.go index 42c7745bb1d1..5410a2184dc4 100644 --- a/wallet/chain/p/builder_dynamic_fees_test.go +++ b/wallet/chain/p/builder_dynamic_fees_test.go @@ -4,6 +4,7 @@ package p import ( + stdcontext "context" "math" "math/rand" "testing" @@ -16,15 +17,18 @@ import ( "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" "github.com/ava-labs/avalanchego/utils/set" "github.com/ava-labs/avalanchego/utils/units" + "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/platformvm/txs" + "github.com/ava-labs/avalanchego/vms/platformvm/txs/fees" "github.com/ava-labs/avalanchego/vms/secp256k1fx" - "github.com/ava-labs/avalanchego/vms/components/avax" commonfees "github.com/ava-labs/avalanchego/vms/components/fees" ) var testKeys = secp256k1.TestKeys() +// Create and sign the tx, then verify that utxos included +// in the tx are exactly necessary to pay fees for it func TestCreateChainTx(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) @@ -64,42 +68,40 @@ func TestCreateChainTx(t *testing.T) { } ) - be.EXPECT().GetTx(gomock.Any(), subnetID).Return( - &txs.Tx{ - Unsigned: &txs.CreateSubnetTx{ - Owner: &secp256k1fx.OutputOwners{}, - }, + subnetTx := &txs.Tx{ + Unsigned: &txs.CreateSubnetTx{ + Owner: &secp256k1fx.OutputOwners{}, }, - nil, - ) - - amount := 10 * units.Avax - avaxAssetID := ids.GenerateTestID() - be.EXPECT().AVAXAssetID().Return(avaxAssetID).AnyTimes() - be.EXPECT().NetworkID().Return(constants.MainnetID).AnyTimes() + } + be.EXPECT().GetTx(gomock.Any(), subnetID).Return(subnetTx, nil) - be.EXPECT().UTXOs(gomock.Any(), constants.PlatformChainID).Return( - []*avax.UTXO{ - &avax.UTXO{ + var ( + amount = 10 * units.Avax + avaxAssetID = ids.GenerateTestID() + utxos = []*avax.UTXO{ + { UTXOID: avax.UTXOID{ TxID: ids.GenerateTestID(), - OutputIndex: rand.Uint32(), + OutputIndex: rand.Uint32(), // #nosec G404 }, Asset: avax.Asset{ID: avaxAssetID}, Out: &secp256k1fx.TransferOutput{ - Amt: uint64(amount), + Amt: amount, OutputOwners: secp256k1fx.OutputOwners{ Locktime: 0, - Addrs: []ids.ShortID{testKeys[0].PublicKey().Address()}, + Addrs: []ids.ShortID{utxoKey.PublicKey().Address()}, Threshold: 1, }, }, }, - }, - nil, + } ) - _, err := b.NewCreateChainTx( + be.EXPECT().AVAXAssetID().Return(avaxAssetID).AnyTimes() + be.EXPECT().NetworkID().Return(constants.MainnetID).AnyTimes() + be.EXPECT().UTXOs(gomock.Any(), constants.PlatformChainID).Return(utxos, nil) + + utx, err := b.NewCreateChainTx( subnetID, genesisBytes, vmID, @@ -110,5 +112,30 @@ func TestCreateChainTx(t *testing.T) { ) require.NoError(err) - // TODO: sign and verify fees can be paid + var ( + kc = secp256k1fx.NewKeychain(utxoKey) + sbe = NewMockSignerBackend(ctrl) + s = NewSigner(kc, sbe) + ) + + sbe.EXPECT().GetUTXO(gomock.Any(), gomock.Any(), gomock.Any()).Return(utxos[0], nil) + sbe.EXPECT().GetTx(gomock.Any(), subnetID).Return(subnetTx, nil) + + tx, err := s.SignUnsigned(stdcontext.Background(), utx) + require.NoError(err) + + fc := &fees.Calculator{ + IsEForkActive: true, + FeeManager: commonfees.NewManager(testUnitFees), + ConsumedUnitsCap: testBlockMaxConsumedUnits, + Credentials: tx.Creds, + } + require.NoError(utx.Visit(fc)) + require.Equal(3128*units.MicroAvax, fc.Fee) + + ins := utx.Ins + outs := utx.Outs + require.Len(ins, 1) + require.Len(outs, 1) + require.Equal(fc.Fee, utx.Ins[0].In.Amount()-utx.Outs[0].Out.Amount()) } diff --git a/wallet/chain/p/mock_builderbackend.go b/wallet/chain/p/mock_builder_backend.go similarity index 98% rename from wallet/chain/p/mock_builderbackend.go rename to wallet/chain/p/mock_builder_backend.go index d46923be788b..db8b7bae39f7 100644 --- a/wallet/chain/p/mock_builderbackend.go +++ b/wallet/chain/p/mock_builder_backend.go @@ -3,7 +3,7 @@ // // Generated by this command: // -// mockgen -package=p -destination=wallet/chain/p/mock_builderbackend.go github.com/ava-labs/avalanchego/wallet/chain/p BuilderBackend +// mockgen -package=p -destination=wallet/chain/p/mock_builder_backend.go github.com/ava-labs/avalanchego/wallet/chain/p BuilderBackend // // Package p is a generated GoMock package. diff --git a/wallet/chain/p/mock_signer_backend.go b/wallet/chain/p/mock_signer_backend.go new file mode 100644 index 000000000000..32d4101e5897 --- /dev/null +++ b/wallet/chain/p/mock_signer_backend.go @@ -0,0 +1,73 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/ava-labs/avalanchego/wallet/chain/p (interfaces: SignerBackend) +// +// Generated by this command: +// +// mockgen -package=p -destination=wallet/chain/p/mock_signer_backend.go github.com/ava-labs/avalanchego/wallet/chain/p SignerBackend +// + +// Package p is a generated GoMock package. +package p + +import ( + ctx "context" + reflect "reflect" + + ids "github.com/ava-labs/avalanchego/ids" + avax "github.com/ava-labs/avalanchego/vms/components/avax" + txs "github.com/ava-labs/avalanchego/vms/platformvm/txs" + gomock "go.uber.org/mock/gomock" +) + +// MockSignerBackend is a mock of SignerBackend interface. +type MockSignerBackend struct { + ctrl *gomock.Controller + recorder *MockSignerBackendMockRecorder +} + +// MockSignerBackendMockRecorder is the mock recorder for MockSignerBackend. +type MockSignerBackendMockRecorder struct { + mock *MockSignerBackend +} + +// NewMockSignerBackend creates a new mock instance. +func NewMockSignerBackend(ctrl *gomock.Controller) *MockSignerBackend { + mock := &MockSignerBackend{ctrl: ctrl} + mock.recorder = &MockSignerBackendMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockSignerBackend) EXPECT() *MockSignerBackendMockRecorder { + return m.recorder +} + +// GetTx mocks base method. +func (m *MockSignerBackend) GetTx(arg0 ctx.Context, arg1 ids.ID) (*txs.Tx, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetTx", arg0, arg1) + ret0, _ := ret[0].(*txs.Tx) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetTx indicates an expected call of GetTx. +func (mr *MockSignerBackendMockRecorder) GetTx(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTx", reflect.TypeOf((*MockSignerBackend)(nil).GetTx), arg0, arg1) +} + +// GetUTXO mocks base method. +func (m *MockSignerBackend) GetUTXO(arg0 ctx.Context, arg1, arg2 ids.ID) (*avax.UTXO, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetUTXO", arg0, arg1, arg2) + ret0, _ := ret[0].(*avax.UTXO) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetUTXO indicates an expected call of GetUTXO. +func (mr *MockSignerBackendMockRecorder) GetUTXO(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUTXO", reflect.TypeOf((*MockSignerBackend)(nil).GetUTXO), arg0, arg1, arg2) +} From 5b32e725a30142edbd17f6ac27c239c1b2883127 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Wed, 24 Jan 2024 09:32:07 +0100 Subject: [PATCH 063/190] wip: fixing UTs --- vms/components/fees/helpers.go | 13 ++++-- wallet/chain/p/builder_dynamic_fees.go | 15 ++++++- wallet/chain/p/builder_dynamic_fees_test.go | 48 +++++++++++---------- 3 files changed, 49 insertions(+), 27 deletions(-) diff --git a/vms/components/fees/helpers.go b/vms/components/fees/helpers.go index fa3108d1e390..dfdee15325eb 100644 --- a/vms/components/fees/helpers.go +++ b/vms/components/fees/helpers.go @@ -8,7 +8,9 @@ import ( "github.com/ava-labs/avalanchego/codec" "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" + "github.com/ava-labs/avalanchego/utils/wrappers" "github.com/ava-labs/avalanchego/vms/components/avax" + "github.com/ava-labs/avalanchego/vms/components/verify" "github.com/ava-labs/avalanchego/vms/secp256k1fx" ) @@ -51,14 +53,19 @@ func GetOutputsDimensions(c codec.Manager, v uint16, outs []*avax.TransferableOu func GetCredentialsDimensions(c codec.Manager, v uint16, inputSigIndices []uint32) (Dimensions, error) { var consumedUnits Dimensions - cred := &secp256k1fx.Credential{ + // Workaround to ensure that codec picks interface instead of the pointer to evaluate size. + // TODO ABENEGIA: fix this + creds := make([]verify.Verifiable, 0, 1) + creds = append(creds, &secp256k1fx.Credential{ Sigs: make([][secp256k1.SignatureLen]byte, len(inputSigIndices)), - } + }) - credSize, err := c.Size(v, cred) + credSize, err := c.Size(v, creds) if err != nil { return consumedUnits, fmt.Errorf("failed retrieving size of credentials: %w", err) } + credSize -= wrappers.IntLen // length of the slice, we want the single credential + consumedUnits[Bandwidth] += uint64(credSize) - codec.CodecVersionSize return consumedUnits, nil } diff --git a/wallet/chain/p/builder_dynamic_fees.go b/wallet/chain/p/builder_dynamic_fees.go index 9754c6662309..831adc306981 100644 --- a/wallet/chain/p/builder_dynamic_fees.go +++ b/wallet/chain/p/builder_dynamic_fees.go @@ -59,6 +59,9 @@ func (b *DynamicFeesBuilder) NewCreateChainTx( } // 2. Finance the tx by building the utxos (inputs, outputs and stakes) + toStake := map[ids.ID]uint64{} + toBurn := map[ids.ID]uint64{} // fees are calculated in financeTx + feesMan := commonfees.NewManager(unitFees) feeCalc := &fees.Calculator{ IsEForkActive: true, @@ -66,13 +69,21 @@ func (b *DynamicFeesBuilder) NewCreateChainTx( ConsumedUnitsCap: unitCaps, } + // update fees to account for the auth credentials to be added upon tx signing + credsDimensions, err := commonfees.GetCredentialsDimensions(txs.Codec, txs.CodecVersion, subnetAuth.SigIndices) + if err != nil { + return nil, fmt.Errorf("failed calculating input size: %w", err) + } + if err := feeCalc.AddFeesFor(credsDimensions); err != nil { + return nil, fmt.Errorf("account for input fees: %w", err) + } + toBurn[b.backend.AVAXAssetID()] += feeCalc.Fee + // feesMan cumulates consumed units. Let's init it with utx filled so far if err = feeCalc.CreateChainTx(uTx); err != nil { return nil, err } - toStake := map[ids.ID]uint64{} - toBurn := map[ids.ID]uint64{} // fees are calculated in financeTx inputs, outputs, _, err := b.financeTx(toBurn, toStake, feeCalc, ops) if err != nil { return nil, err diff --git a/wallet/chain/p/builder_dynamic_fees_test.go b/wallet/chain/p/builder_dynamic_fees_test.go index 5410a2184dc4..68d4ec543f81 100644 --- a/wallet/chain/p/builder_dynamic_fees_test.go +++ b/wallet/chain/p/builder_dynamic_fees_test.go @@ -25,7 +25,21 @@ import ( commonfees "github.com/ava-labs/avalanchego/vms/components/fees" ) -var testKeys = secp256k1.TestKeys() +var ( + testKeys = secp256k1.TestKeys() + testUnitFees = commonfees.Dimensions{ + 1 * units.MicroAvax, + 2 * units.MicroAvax, + 3 * units.MicroAvax, + 4 * units.MicroAvax, + } + testBlockMaxConsumedUnits = commonfees.Dimensions{ + math.MaxUint64, + math.MaxUint64, + math.MaxUint64, + math.MaxUint64, + } +) // Create and sign the tx, then verify that utxos included // in the tx are exactly necessary to pay fees for it @@ -36,12 +50,14 @@ func TestCreateChainTx(t *testing.T) { be := NewMockBuilderBackend(ctrl) var ( - utxoKey = testKeys[0] - utxoAddr = utxoKey.PublicKey().Address() + subnetAuthKey = testKeys[0] + utxoKey = testKeys[1] + subnetAuthAddr = subnetAuthKey.PublicKey().Address() + utxoAddr = utxoKey.PublicKey().Address() ) b := &DynamicFeesBuilder{ - addrs: set.Of(utxoAddr), + addrs: set.Of(utxoAddr, subnetAuthAddr), backend: be, } @@ -53,24 +69,12 @@ func TestCreateChainTx(t *testing.T) { chainName = "dummyChain" ) - var ( - testUnitFees = commonfees.Dimensions{ - 1 * units.MicroAvax, - 2 * units.MicroAvax, - 3 * units.MicroAvax, - 4 * units.MicroAvax, - } - testBlockMaxConsumedUnits = commonfees.Dimensions{ - math.MaxUint64, - math.MaxUint64, - math.MaxUint64, - math.MaxUint64, - } - ) - subnetTx := &txs.Tx{ Unsigned: &txs.CreateSubnetTx{ - Owner: &secp256k1fx.OutputOwners{}, + Owner: &secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{subnetAuthKey.PublicKey().Address()}, + }, }, } be.EXPECT().GetTx(gomock.Any(), subnetID).Return(subnetTx, nil) @@ -131,11 +135,11 @@ func TestCreateChainTx(t *testing.T) { Credentials: tx.Creds, } require.NoError(utx.Visit(fc)) - require.Equal(3128*units.MicroAvax, fc.Fee) + require.Equal(3197*units.MicroAvax, fc.Fee) ins := utx.Ins outs := utx.Outs require.Len(ins, 1) require.Len(outs, 1) - require.Equal(fc.Fee, utx.Ins[0].In.Amount()-utx.Outs[0].Out.Amount()) + require.Equal(fc.Fee, ins[0].In.Amount()-outs[0].Out.Amount()) } From 03d1829a3e6635f7d8e41f8b27ae922fb3cbb6da Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Wed, 24 Jan 2024 12:32:07 +0100 Subject: [PATCH 064/190] moved wallet mocks --- scripts/mocks.mockgen.txt | 4 ++-- wallet/chain/p/builder_dynamic_fees_test.go | 5 +++-- wallet/chain/p/{ => mocks}/mock_builder_backend.go | 12 ++++++------ wallet/chain/p/{ => mocks}/mock_signer_backend.go | 12 ++++++------ 4 files changed, 17 insertions(+), 16 deletions(-) rename wallet/chain/p/{ => mocks}/mock_builder_backend.go (94%) rename wallet/chain/p/{ => mocks}/mock_signer_backend.go (83%) diff --git a/scripts/mocks.mockgen.txt b/scripts/mocks.mockgen.txt index d338d08ba04f..701da0a02ac9 100644 --- a/scripts/mocks.mockgen.txt +++ b/scripts/mocks.mockgen.txt @@ -40,7 +40,7 @@ github.com/ava-labs/avalanchego/vms/proposervm=PostForkBlock=vms/proposervm/mock github.com/ava-labs/avalanchego/vms/registry=VMGetter=vms/registry/mock_vm_getter.go github.com/ava-labs/avalanchego/vms/registry=VMRegistry=vms/registry/mock_vm_registry.go github.com/ava-labs/avalanchego/vms=Factory,Manager=vms/mock_manager.go -github.com/ava-labs/avalanchego/wallet/chain/p=BuilderBackend=wallet/chain/p/mock_builder_backend.go -github.com/ava-labs/avalanchego/wallet/chain/p=SignerBackend=wallet/chain/p/mock_signer_backend.go +github.com/ava-labs/avalanchego/wallet/chain/p=BuilderBackend=wallet/chain/p/mocks/mock_builder_backend.go +github.com/ava-labs/avalanchego/wallet/chain/p=SignerBackend=wallet/chain/p/mocks/mock_signer_backend.go github.com/ava-labs/avalanchego/x/sync=Client=x/sync/mock_client.go github.com/ava-labs/avalanchego/x/sync=NetworkClient=x/sync/mock_network_client.go diff --git a/wallet/chain/p/builder_dynamic_fees_test.go b/wallet/chain/p/builder_dynamic_fees_test.go index 68d4ec543f81..dee4d621b1c0 100644 --- a/wallet/chain/p/builder_dynamic_fees_test.go +++ b/wallet/chain/p/builder_dynamic_fees_test.go @@ -21,6 +21,7 @@ import ( "github.com/ava-labs/avalanchego/vms/platformvm/txs" "github.com/ava-labs/avalanchego/vms/platformvm/txs/fees" "github.com/ava-labs/avalanchego/vms/secp256k1fx" + "github.com/ava-labs/avalanchego/wallet/chain/p/mocks" commonfees "github.com/ava-labs/avalanchego/vms/components/fees" ) @@ -47,7 +48,7 @@ func TestCreateChainTx(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) - be := NewMockBuilderBackend(ctrl) + be := mocks.NewMockBuilderBackend(ctrl) var ( subnetAuthKey = testKeys[0] @@ -118,7 +119,7 @@ func TestCreateChainTx(t *testing.T) { var ( kc = secp256k1fx.NewKeychain(utxoKey) - sbe = NewMockSignerBackend(ctrl) + sbe = mocks.NewMockSignerBackend(ctrl) s = NewSigner(kc, sbe) ) diff --git a/wallet/chain/p/mock_builder_backend.go b/wallet/chain/p/mocks/mock_builder_backend.go similarity index 94% rename from wallet/chain/p/mock_builder_backend.go rename to wallet/chain/p/mocks/mock_builder_backend.go index db8b7bae39f7..5f838501f8ce 100644 --- a/wallet/chain/p/mock_builder_backend.go +++ b/wallet/chain/p/mocks/mock_builder_backend.go @@ -3,14 +3,14 @@ // // Generated by this command: // -// mockgen -package=p -destination=wallet/chain/p/mock_builder_backend.go github.com/ava-labs/avalanchego/wallet/chain/p BuilderBackend +// mockgen -package=mocks -destination=wallet/chain/p/mocks/mock_builder_backend.go github.com/ava-labs/avalanchego/wallet/chain/p BuilderBackend // -// Package p is a generated GoMock package. -package p +// Package mocks is a generated GoMock package. +package mocks import ( - ctx "context" + context "context" reflect "reflect" ids "github.com/ava-labs/avalanchego/ids" @@ -155,7 +155,7 @@ func (mr *MockBuilderBackendMockRecorder) CreateSubnetTxFee() *gomock.Call { } // GetTx mocks base method. -func (m *MockBuilderBackend) GetTx(arg0 ctx.Context, arg1 ids.ID) (*txs.Tx, error) { +func (m *MockBuilderBackend) GetTx(arg0 context.Context, arg1 ids.ID) (*txs.Tx, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetTx", arg0, arg1) ret0, _ := ret[0].(*txs.Tx) @@ -198,7 +198,7 @@ func (mr *MockBuilderBackendMockRecorder) TransformSubnetTxFee() *gomock.Call { } // UTXOs mocks base method. -func (m *MockBuilderBackend) UTXOs(arg0 ctx.Context, arg1 ids.ID) ([]*avax.UTXO, error) { +func (m *MockBuilderBackend) UTXOs(arg0 context.Context, arg1 ids.ID) ([]*avax.UTXO, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "UTXOs", arg0, arg1) ret0, _ := ret[0].([]*avax.UTXO) diff --git a/wallet/chain/p/mock_signer_backend.go b/wallet/chain/p/mocks/mock_signer_backend.go similarity index 83% rename from wallet/chain/p/mock_signer_backend.go rename to wallet/chain/p/mocks/mock_signer_backend.go index 32d4101e5897..13f3527c4099 100644 --- a/wallet/chain/p/mock_signer_backend.go +++ b/wallet/chain/p/mocks/mock_signer_backend.go @@ -3,14 +3,14 @@ // // Generated by this command: // -// mockgen -package=p -destination=wallet/chain/p/mock_signer_backend.go github.com/ava-labs/avalanchego/wallet/chain/p SignerBackend +// mockgen -package=mocks -destination=wallet/chain/p/mocks/mock_signer_backend.go github.com/ava-labs/avalanchego/wallet/chain/p SignerBackend // -// Package p is a generated GoMock package. -package p +// Package mocks is a generated GoMock package. +package mocks import ( - ctx "context" + context "context" reflect "reflect" ids "github.com/ava-labs/avalanchego/ids" @@ -43,7 +43,7 @@ func (m *MockSignerBackend) EXPECT() *MockSignerBackendMockRecorder { } // GetTx mocks base method. -func (m *MockSignerBackend) GetTx(arg0 ctx.Context, arg1 ids.ID) (*txs.Tx, error) { +func (m *MockSignerBackend) GetTx(arg0 context.Context, arg1 ids.ID) (*txs.Tx, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetTx", arg0, arg1) ret0, _ := ret[0].(*txs.Tx) @@ -58,7 +58,7 @@ func (mr *MockSignerBackendMockRecorder) GetTx(arg0, arg1 any) *gomock.Call { } // GetUTXO mocks base method. -func (m *MockSignerBackend) GetUTXO(arg0 ctx.Context, arg1, arg2 ids.ID) (*avax.UTXO, error) { +func (m *MockSignerBackend) GetUTXO(arg0 context.Context, arg1, arg2 ids.ID) (*avax.UTXO, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetUTXO", arg0, arg1, arg2) ret0, _ := ret[0].(*avax.UTXO) From 58543637cd7a9d2b790ecc8695690634ca8c3fd9 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Wed, 24 Jan 2024 12:46:46 +0100 Subject: [PATCH 065/190] expanded UTXOs list --- wallet/chain/p/builder_dynamic_fees_test.go | 48 +++++++++++++++++---- 1 file changed, 40 insertions(+), 8 deletions(-) diff --git a/wallet/chain/p/builder_dynamic_fees_test.go b/wallet/chain/p/builder_dynamic_fees_test.go index dee4d621b1c0..2dcc2577ed3b 100644 --- a/wallet/chain/p/builder_dynamic_fees_test.go +++ b/wallet/chain/p/builder_dynamic_fees_test.go @@ -8,6 +8,7 @@ import ( "math" "math/rand" "testing" + "time" "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" @@ -81,17 +82,46 @@ func TestCreateChainTx(t *testing.T) { be.EXPECT().GetTx(gomock.Any(), subnetID).Return(subnetTx, nil) var ( - amount = 10 * units.Avax avaxAssetID = ids.GenerateTestID() - utxos = []*avax.UTXO{ - { + utxos = []*avax.UTXO{ // currently, the wallet scans UTXOs in the order provided here + { // a small UTXO first, which should not be enough to pay fees UTXOID: avax.UTXOID{ TxID: ids.GenerateTestID(), OutputIndex: rand.Uint32(), // #nosec G404 }, Asset: avax.Asset{ID: avaxAssetID}, Out: &secp256k1fx.TransferOutput{ - Amt: amount, + Amt: 2 * units.MilliAvax, + OutputOwners: secp256k1fx.OutputOwners{ + Locktime: 0, + Addrs: []ids.ShortID{utxoKey.PublicKey().Address()}, + Threshold: 1, + }, + }, + }, + { // a locked, small UTXO + UTXOID: avax.UTXOID{ + TxID: ids.GenerateTestID(), + OutputIndex: rand.Uint32(), // #nosec G404 + }, + Asset: avax.Asset{ID: avaxAssetID}, + Out: &secp256k1fx.TransferOutput{ + Amt: 99 * units.Avax, + OutputOwners: secp256k1fx.OutputOwners{ + Locktime: uint64(time.Now().Add(time.Hour).Unix()), + Addrs: []ids.ShortID{utxoKey.PublicKey().Address()}, + Threshold: 1, + }, + }, + }, + { // a large UTXO last, which should be enough to pay any fee by itself + UTXOID: avax.UTXOID{ + TxID: ids.GenerateTestID(), + OutputIndex: rand.Uint32(), // #nosec G404 + }, + Asset: avax.Asset{ID: avaxAssetID}, + Out: &secp256k1fx.TransferOutput{ + Amt: 10 * units.Avax, OutputOwners: secp256k1fx.OutputOwners{ Locktime: 0, Addrs: []ids.ShortID{utxoKey.PublicKey().Address()}, @@ -123,7 +153,9 @@ func TestCreateChainTx(t *testing.T) { s = NewSigner(kc, sbe) ) - sbe.EXPECT().GetUTXO(gomock.Any(), gomock.Any(), gomock.Any()).Return(utxos[0], nil) + for _, utxo := range utxos { + sbe.EXPECT().GetUTXO(gomock.Any(), gomock.Any(), utxo.InputID()).Return(utxo, nil).AnyTimes() + } sbe.EXPECT().GetTx(gomock.Any(), subnetID).Return(subnetTx, nil) tx, err := s.SignUnsigned(stdcontext.Background(), utx) @@ -136,11 +168,11 @@ func TestCreateChainTx(t *testing.T) { Credentials: tx.Creds, } require.NoError(utx.Visit(fc)) - require.Equal(3197*units.MicroAvax, fc.Fee) + require.Equal(5808*units.MicroAvax, fc.Fee) ins := utx.Ins outs := utx.Outs - require.Len(ins, 1) + require.Len(ins, 2) require.Len(outs, 1) - require.Equal(fc.Fee, ins[0].In.Amount()-outs[0].Out.Amount()) + require.Equal(fc.Fee, ins[0].In.Amount()+ins[1].In.Amount()-outs[0].Out.Amount()) } From d78aeb3198935306e34f1539013af67a47266321 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Wed, 24 Jan 2024 12:53:57 +0100 Subject: [PATCH 066/190] wip: adding txs to dynamic fees builder --- wallet/chain/p/builder_dynamic_fees.go | 94 +++++++ wallet/chain/p/builder_dynamic_fees_test.go | 279 ++++++++++++++++---- 2 files changed, 322 insertions(+), 51 deletions(-) diff --git a/wallet/chain/p/builder_dynamic_fees.go b/wallet/chain/p/builder_dynamic_fees.go index 831adc306981..7dc92ce648a4 100644 --- a/wallet/chain/p/builder_dynamic_fees.go +++ b/wallet/chain/p/builder_dynamic_fees.go @@ -26,6 +26,56 @@ type DynamicFeesBuilder struct { backend BuilderBackend } +func (b *DynamicFeesBuilder) NewAddValidatorTx( + vdr *txs.Validator, + rewardsOwner *secp256k1fx.OutputOwners, + shares uint32, + unitFees, unitCaps commonfees.Dimensions, + options ...common.Option, +) (*txs.AddValidatorTx, error) { + ops := common.NewOptions(options) + utils.Sort(rewardsOwner.Addrs) + utx := &txs.AddValidatorTx{ + BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ + NetworkID: b.backend.NetworkID(), + BlockchainID: constants.PlatformChainID, + Memo: ops.Memo(), + }}, + Validator: *vdr, + RewardsOwner: rewardsOwner, + DelegationShares: shares, + } + + // 2. Finance the tx by building the utxos (inputs, outputs and stakes) + toStake := map[ids.ID]uint64{ + b.backend.AVAXAssetID(): vdr.Wght, + } + toBurn := map[ids.ID]uint64{} // fees are calculated in financeTx + + feesMan := commonfees.NewManager(unitFees) + feeCalc := &fees.Calculator{ + IsEForkActive: true, + FeeManager: feesMan, + ConsumedUnitsCap: unitCaps, + } + + // feesMan cumulates consumed units. Let's init it with utx filled so far + if err := feeCalc.AddValidatorTx(utx); err != nil { + return nil, err + } + + inputs, outputs, stakeOutputs, err := b.financeTx(toBurn, toStake, feeCalc, ops) + if err != nil { + return nil, err + } + + utx.Ins = inputs + utx.Outs = outputs + utx.StakeOuts = stakeOutputs + + return utx, b.initCtx(utx) +} + func (b *DynamicFeesBuilder) NewCreateChainTx( subnetID ids.ID, genesis []byte, @@ -95,6 +145,50 @@ func (b *DynamicFeesBuilder) NewCreateChainTx( return uTx, b.initCtx(uTx) } +func (b *DynamicFeesBuilder) NewCreateSubnetTx( + owner *secp256k1fx.OutputOwners, + unitFees, unitCaps commonfees.Dimensions, + options ...common.Option, +) (*txs.CreateSubnetTx, error) { + // 1. Build core transaction without utxos + ops := common.NewOptions(options) + + utx := &txs.CreateSubnetTx{ + BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ + NetworkID: b.backend.NetworkID(), + BlockchainID: constants.PlatformChainID, + Memo: ops.Memo(), + }}, + Owner: owner, + } + + // 2. Finance the tx by building the utxos (inputs, outputs and stakes) + toStake := map[ids.ID]uint64{} + toBurn := map[ids.ID]uint64{} // fees are calculated in financeTx + + feesMan := commonfees.NewManager(unitFees) + feeCalc := &fees.Calculator{ + IsEForkActive: true, + FeeManager: feesMan, + ConsumedUnitsCap: unitCaps, + } + + // feesMan cumulates consumed units. Let's init it with utx filled so far + if err := feeCalc.CreateSubnetTx(utx); err != nil { + return nil, err + } + + inputs, outputs, _, err := b.financeTx(toBurn, toStake, feeCalc, ops) + if err != nil { + return nil, err + } + + utx.Ins = inputs + utx.Outs = outputs + + return utx, b.initCtx(utx) +} + func (b *DynamicFeesBuilder) financeTx( amountsToBurn map[ids.ID]uint64, amountsToStake map[ids.ID]uint64, diff --git a/wallet/chain/p/builder_dynamic_fees_test.go b/wallet/chain/p/builder_dynamic_fees_test.go index 2dcc2577ed3b..a83b468ebcfc 100644 --- a/wallet/chain/p/builder_dynamic_fees_test.go +++ b/wallet/chain/p/builder_dynamic_fees_test.go @@ -6,7 +6,6 @@ package p import ( stdcontext "context" "math" - "math/rand" "testing" "time" @@ -19,6 +18,8 @@ import ( "github.com/ava-labs/avalanchego/utils/set" "github.com/ava-labs/avalanchego/utils/units" "github.com/ava-labs/avalanchego/vms/components/avax" + "github.com/ava-labs/avalanchego/vms/platformvm/reward" + "github.com/ava-labs/avalanchego/vms/platformvm/stakeable" "github.com/ava-labs/avalanchego/vms/platformvm/txs" "github.com/ava-labs/avalanchego/vms/platformvm/txs/fees" "github.com/ava-labs/avalanchego/vms/secp256k1fx" @@ -53,9 +54,9 @@ func TestCreateChainTx(t *testing.T) { var ( subnetAuthKey = testKeys[0] - utxoKey = testKeys[1] + utxosKey = testKeys[1] subnetAuthAddr = subnetAuthKey.PublicKey().Address() - utxoAddr = utxoKey.PublicKey().Address() + utxoAddr = utxosKey.PublicKey().Address() ) b := &DynamicFeesBuilder{ @@ -83,53 +84,7 @@ func TestCreateChainTx(t *testing.T) { var ( avaxAssetID = ids.GenerateTestID() - utxos = []*avax.UTXO{ // currently, the wallet scans UTXOs in the order provided here - { // a small UTXO first, which should not be enough to pay fees - UTXOID: avax.UTXOID{ - TxID: ids.GenerateTestID(), - OutputIndex: rand.Uint32(), // #nosec G404 - }, - Asset: avax.Asset{ID: avaxAssetID}, - Out: &secp256k1fx.TransferOutput{ - Amt: 2 * units.MilliAvax, - OutputOwners: secp256k1fx.OutputOwners{ - Locktime: 0, - Addrs: []ids.ShortID{utxoKey.PublicKey().Address()}, - Threshold: 1, - }, - }, - }, - { // a locked, small UTXO - UTXOID: avax.UTXOID{ - TxID: ids.GenerateTestID(), - OutputIndex: rand.Uint32(), // #nosec G404 - }, - Asset: avax.Asset{ID: avaxAssetID}, - Out: &secp256k1fx.TransferOutput{ - Amt: 99 * units.Avax, - OutputOwners: secp256k1fx.OutputOwners{ - Locktime: uint64(time.Now().Add(time.Hour).Unix()), - Addrs: []ids.ShortID{utxoKey.PublicKey().Address()}, - Threshold: 1, - }, - }, - }, - { // a large UTXO last, which should be enough to pay any fee by itself - UTXOID: avax.UTXOID{ - TxID: ids.GenerateTestID(), - OutputIndex: rand.Uint32(), // #nosec G404 - }, - Asset: avax.Asset{ID: avaxAssetID}, - Out: &secp256k1fx.TransferOutput{ - Amt: 10 * units.Avax, - OutputOwners: secp256k1fx.OutputOwners{ - Locktime: 0, - Addrs: []ids.ShortID{utxoKey.PublicKey().Address()}, - Threshold: 1, - }, - }, - }, - } + utxos = testUTXOsList(avaxAssetID, utxosKey) ) be.EXPECT().AVAXAssetID().Return(avaxAssetID).AnyTimes() @@ -148,7 +103,7 @@ func TestCreateChainTx(t *testing.T) { require.NoError(err) var ( - kc = secp256k1fx.NewKeychain(utxoKey) + kc = secp256k1fx.NewKeychain(utxosKey) sbe = mocks.NewMockSignerBackend(ctrl) s = NewSigner(kc, sbe) ) @@ -176,3 +131,225 @@ func TestCreateChainTx(t *testing.T) { require.Len(outs, 1) require.Equal(fc.Fee, ins[0].In.Amount()+ins[1].In.Amount()-outs[0].Out.Amount()) } + +func TestCreateSubnetTx(t *testing.T) { + require := require.New(t) + ctrl := gomock.NewController(t) + + be := mocks.NewMockBuilderBackend(ctrl) + + var ( + subnetAuthKey = testKeys[0] + utxosKey = testKeys[1] + subnetAuthAddr = subnetAuthKey.PublicKey().Address() + utxoAddr = utxosKey.PublicKey().Address() + ) + + b := &DynamicFeesBuilder{ + addrs: set.Of(utxoAddr, subnetAuthAddr), + backend: be, + } + + var ( + avaxAssetID = ids.GenerateTestID() + utxos = testUTXOsList(avaxAssetID, utxosKey) + + subnetOwner = &secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{ + subnetAuthKey.Address(), + }, + } + ) + + be.EXPECT().AVAXAssetID().Return(avaxAssetID).AnyTimes() + be.EXPECT().NetworkID().Return(constants.MainnetID).AnyTimes() + be.EXPECT().UTXOs(gomock.Any(), constants.PlatformChainID).Return(utxos, nil) + + utx, err := b.NewCreateSubnetTx( + subnetOwner, + testUnitFees, + testBlockMaxConsumedUnits, + ) + require.NoError(err) + + var ( + kc = secp256k1fx.NewKeychain(utxosKey) + sbe = mocks.NewMockSignerBackend(ctrl) + s = NewSigner(kc, sbe) + ) + + for _, utxo := range utxos { + sbe.EXPECT().GetUTXO(gomock.Any(), gomock.Any(), utxo.InputID()).Return(utxo, nil).AnyTimes() + } + + tx, err := s.SignUnsigned(stdcontext.Background(), utx) + require.NoError(err) + + fc := &fees.Calculator{ + IsEForkActive: true, + FeeManager: commonfees.NewManager(testUnitFees), + ConsumedUnitsCap: testBlockMaxConsumedUnits, + Credentials: tx.Creds, + } + require.NoError(utx.Visit(fc)) + require.Equal(5644*units.MicroAvax, fc.Fee) + + ins := utx.Ins + outs := utx.Outs + require.Len(ins, 2) + require.Len(outs, 1) + require.Equal(fc.Fee, ins[0].In.Amount()+ins[1].In.Amount()-outs[0].Out.Amount()) +} + +func TestAddValidatorTx(t *testing.T) { + require := require.New(t) + ctrl := gomock.NewController(t) + + be := mocks.NewMockBuilderBackend(ctrl) + + var ( + rewardKey = testKeys[0] + utxosKey = testKeys[1] + subnetAuthAddr = rewardKey.PublicKey().Address() + utxoAddr = utxosKey.PublicKey().Address() + ) + + b := &DynamicFeesBuilder{ + addrs: set.Of(utxoAddr, subnetAuthAddr), + backend: be, + } + + var ( + avaxAssetID = ids.GenerateTestID() + utxos = testUTXOsList(avaxAssetID, utxosKey) + + rewardOwner = &secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{ + rewardKey.Address(), + }, + } + ) + + be.EXPECT().AVAXAssetID().Return(avaxAssetID).AnyTimes() + be.EXPECT().NetworkID().Return(constants.MainnetID).AnyTimes() + be.EXPECT().UTXOs(gomock.Any(), constants.PlatformChainID).Return(utxos, nil) + + utx, err := b.NewAddValidatorTx( + &txs.Validator{ + NodeID: ids.GenerateTestNodeID(), + End: uint64(time.Now().Add(time.Hour).Unix()), + Wght: 2 * units.Avax, + }, + rewardOwner, + reward.PercentDenominator, + testUnitFees, + testBlockMaxConsumedUnits, + ) + require.NoError(err) + + var ( + kc = secp256k1fx.NewKeychain(utxosKey) + sbe = mocks.NewMockSignerBackend(ctrl) + s = NewSigner(kc, sbe) + ) + + for _, utxo := range utxos { + sbe.EXPECT().GetUTXO(gomock.Any(), gomock.Any(), utxo.InputID()).Return(utxo, nil).AnyTimes() + } + + tx, err := s.SignUnsigned(stdcontext.Background(), utx) + require.NoError(err) + + fc := &fees.Calculator{ + IsEForkActive: true, + FeeManager: commonfees.NewManager(testUnitFees), + ConsumedUnitsCap: testBlockMaxConsumedUnits, + Credentials: tx.Creds, + } + require.NoError(utx.Visit(fc)) + require.Equal(12184*units.MicroAvax, fc.Fee) + + ins := utx.Ins + staked := utx.StakeOuts + outs := utx.Outs + require.Len(ins, 4) + require.Len(staked, 2) + require.Len(outs, 2) + require.Equal(utx.Validator.Weight(), staked[0].Out.Amount()+staked[1].Out.Amount()) + require.Equal(fc.Fee, ins[2].In.Amount()+ins[3].In.Amount()-outs[0].Out.Amount()) +} + +func testUTXOsList(avaxAssetID ids.ID, utxosKey *secp256k1.PrivateKey) []*avax.UTXO { + // Note: we avoid ids.GenerateTestNodeID here to make sure that UTXO IDs won't change + // run by run. This simplifies checking what utxos are included in the built txs. + utxosOffset := uint64(2024) + + return []*avax.UTXO{ // currently, the wallet scans UTXOs in the order provided here + { // a small UTXO first, which should not be enough to pay fees + UTXOID: avax.UTXOID{ + TxID: ids.Empty.Prefix(utxosOffset), + OutputIndex: uint32(utxosOffset), + }, + Asset: avax.Asset{ID: avaxAssetID}, + Out: &secp256k1fx.TransferOutput{ + Amt: 2 * units.MilliAvax, + OutputOwners: secp256k1fx.OutputOwners{ + Locktime: 0, + Addrs: []ids.ShortID{utxosKey.PublicKey().Address()}, + Threshold: 1, + }, + }, + }, + { // a locked, small UTXO + UTXOID: avax.UTXOID{ + TxID: ids.Empty.Prefix(utxosOffset + 1), + OutputIndex: uint32(utxosOffset + 1), + }, + Asset: avax.Asset{ID: avaxAssetID}, + Out: &stakeable.LockOut{ + Locktime: uint64(time.Now().Add(time.Second).Unix()), + TransferableOut: &secp256k1fx.TransferOutput{ + Amt: 3 * units.MilliAvax, + OutputOwners: secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{utxosKey.PublicKey().Address()}, + }, + }, + }, + }, + { // a locked, large UTXO + UTXOID: avax.UTXOID{ + TxID: ids.Empty.Prefix(utxosOffset + 2), + OutputIndex: uint32(utxosOffset + 2), + }, + Asset: avax.Asset{ID: avaxAssetID}, + Out: &stakeable.LockOut{ + Locktime: uint64(time.Now().Add(time.Second).Unix()), + TransferableOut: &secp256k1fx.TransferOutput{ + Amt: 99 * units.Avax, + OutputOwners: secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{utxosKey.PublicKey().Address()}, + }, + }, + }, + }, + { // a large UTXO last, which should be enough to pay any fee by itself + UTXOID: avax.UTXOID{ + TxID: ids.Empty.Prefix(utxosOffset + 3), + OutputIndex: uint32(utxosOffset + 3), + }, + Asset: avax.Asset{ID: avaxAssetID}, + Out: &secp256k1fx.TransferOutput{ + Amt: 10 * units.Avax, + OutputOwners: secp256k1fx.OutputOwners{ + Locktime: 0, + Addrs: []ids.ShortID{utxosKey.PublicKey().Address()}, + Threshold: 1, + }, + }, + }, + } +} From f7a791220576ab8907bf96718d2f8cb7f7e6beb1 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Wed, 24 Jan 2024 13:58:19 +0100 Subject: [PATCH 067/190] wip: adding some more txs to dynamic fees builder --- wallet/chain/p/builder_dynamic_fees.go | 373 ++++++++++- wallet/chain/p/builder_dynamic_fees_test.go | 665 +++++++++++++++++--- 2 files changed, 941 insertions(+), 97 deletions(-) diff --git a/wallet/chain/p/builder_dynamic_fees.go b/wallet/chain/p/builder_dynamic_fees.go index 7dc92ce648a4..ae10214dd0d6 100644 --- a/wallet/chain/p/builder_dynamic_fees.go +++ b/wallet/chain/p/builder_dynamic_fees.go @@ -5,6 +5,7 @@ package p import ( "fmt" + "time" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils" @@ -12,6 +13,7 @@ import ( "github.com/ava-labs/avalanchego/utils/math" "github.com/ava-labs/avalanchego/utils/set" "github.com/ava-labs/avalanchego/vms/components/avax" + "github.com/ava-labs/avalanchego/vms/platformvm/signer" "github.com/ava-labs/avalanchego/vms/platformvm/stakeable" "github.com/ava-labs/avalanchego/vms/platformvm/txs" "github.com/ava-labs/avalanchego/vms/platformvm/txs/fees" @@ -76,6 +78,173 @@ func (b *DynamicFeesBuilder) NewAddValidatorTx( return utx, b.initCtx(utx) } +func (b *DynamicFeesBuilder) NewAddSubnetValidatorTx( + vdr *txs.SubnetValidator, + unitFees, unitCaps commonfees.Dimensions, + options ...common.Option, +) (*txs.AddSubnetValidatorTx, error) { + ops := common.NewOptions(options) + + subnetAuth, err := b.authorizeSubnet(vdr.Subnet, ops) + if err != nil { + return nil, err + } + + utx := &txs.AddSubnetValidatorTx{ + BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ + NetworkID: b.backend.NetworkID(), + BlockchainID: constants.PlatformChainID, + Memo: ops.Memo(), + }}, + SubnetValidator: *vdr, + SubnetAuth: subnetAuth, + } + + // 2. Finance the tx by building the utxos (inputs, outputs and stakes) + toStake := map[ids.ID]uint64{} + toBurn := map[ids.ID]uint64{} // fees are calculated in financeTx + + feesMan := commonfees.NewManager(unitFees) + feeCalc := &fees.Calculator{ + IsEForkActive: true, + FeeManager: feesMan, + ConsumedUnitsCap: unitCaps, + } + + // update fees to account for the auth credentials to be added upon tx signing + credsDimensions, err := commonfees.GetCredentialsDimensions(txs.Codec, txs.CodecVersion, subnetAuth.SigIndices) + if err != nil { + return nil, fmt.Errorf("failed calculating input size: %w", err) + } + if err := feeCalc.AddFeesFor(credsDimensions); err != nil { + return nil, fmt.Errorf("account for input fees: %w", err) + } + toBurn[b.backend.AVAXAssetID()] += feeCalc.Fee + + // feesMan cumulates consumed units. Let's init it with utx filled so far + if err := feeCalc.AddSubnetValidatorTx(utx); err != nil { + return nil, err + } + + inputs, outputs, _, err := b.financeTx(toBurn, toStake, feeCalc, ops) + if err != nil { + return nil, err + } + + utx.Ins = inputs + utx.Outs = outputs + + return utx, b.initCtx(utx) +} + +func (b *DynamicFeesBuilder) NewRemoveSubnetValidatorTx( + nodeID ids.NodeID, + subnetID ids.ID, + unitFees, unitCaps commonfees.Dimensions, + options ...common.Option, +) (*txs.RemoveSubnetValidatorTx, error) { + ops := common.NewOptions(options) + + subnetAuth, err := b.authorizeSubnet(subnetID, ops) + if err != nil { + return nil, err + } + + utx := &txs.RemoveSubnetValidatorTx{ + BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ + NetworkID: b.backend.NetworkID(), + BlockchainID: constants.PlatformChainID, + Memo: ops.Memo(), + }}, + Subnet: subnetID, + NodeID: nodeID, + SubnetAuth: subnetAuth, + } + // 2. Finance the tx by building the utxos (inputs, outputs and stakes) + toStake := map[ids.ID]uint64{} + toBurn := map[ids.ID]uint64{} // fees are calculated in financeTx + + feesMan := commonfees.NewManager(unitFees) + feeCalc := &fees.Calculator{ + IsEForkActive: true, + FeeManager: feesMan, + ConsumedUnitsCap: unitCaps, + } + + // update fees to account for the auth credentials to be added upon tx signing + credsDimensions, err := commonfees.GetCredentialsDimensions(txs.Codec, txs.CodecVersion, subnetAuth.SigIndices) + if err != nil { + return nil, fmt.Errorf("failed calculating input size: %w", err) + } + if err := feeCalc.AddFeesFor(credsDimensions); err != nil { + return nil, fmt.Errorf("account for input fees: %w", err) + } + toBurn[b.backend.AVAXAssetID()] += feeCalc.Fee + + // feesMan cumulates consumed units. Let's init it with utx filled so far + if err := feeCalc.RemoveSubnetValidatorTx(utx); err != nil { + return nil, err + } + + inputs, outputs, _, err := b.financeTx(toBurn, toStake, feeCalc, ops) + if err != nil { + return nil, err + } + + utx.Ins = inputs + utx.Outs = outputs + + return utx, b.initCtx(utx) +} + +func (b *DynamicFeesBuilder) NewAddDelegatorTx( + vdr *txs.Validator, + rewardsOwner *secp256k1fx.OutputOwners, + unitFees, unitCaps commonfees.Dimensions, + options ...common.Option, +) (*txs.AddDelegatorTx, error) { + ops := common.NewOptions(options) + utils.Sort(rewardsOwner.Addrs) + utx := &txs.AddDelegatorTx{ + BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ + NetworkID: b.backend.NetworkID(), + BlockchainID: constants.PlatformChainID, + Memo: ops.Memo(), + }}, + Validator: *vdr, + DelegationRewardsOwner: rewardsOwner, + } + + // 2. Finance the tx by building the utxos (inputs, outputs and stakes) + toStake := map[ids.ID]uint64{ + b.backend.AVAXAssetID(): vdr.Wght, + } + toBurn := map[ids.ID]uint64{} // fees are calculated in financeTx + + feesMan := commonfees.NewManager(unitFees) + feeCalc := &fees.Calculator{ + IsEForkActive: true, + FeeManager: feesMan, + ConsumedUnitsCap: unitCaps, + } + + // feesMan cumulates consumed units. Let's init it with utx filled so far + if err := feeCalc.AddDelegatorTx(utx); err != nil { + return nil, err + } + + inputs, outputs, stakeOutputs, err := b.financeTx(toBurn, toStake, feeCalc, ops) + if err != nil { + return nil, err + } + + utx.Ins = inputs + utx.Outs = outputs + utx.StakeOuts = stakeOutputs + + return utx, b.initCtx(utx) +} + func (b *DynamicFeesBuilder) NewCreateChainTx( subnetID ids.ID, genesis []byte, @@ -189,6 +358,203 @@ func (b *DynamicFeesBuilder) NewCreateSubnetTx( return utx, b.initCtx(utx) } +func (b *DynamicFeesBuilder) NewTransformSubnetTx( + subnetID ids.ID, + assetID ids.ID, + initialSupply uint64, + maxSupply uint64, + minConsumptionRate uint64, + maxConsumptionRate uint64, + minValidatorStake uint64, + maxValidatorStake uint64, + minStakeDuration time.Duration, + maxStakeDuration time.Duration, + minDelegationFee uint32, + minDelegatorStake uint64, + maxValidatorWeightFactor byte, + uptimeRequirement uint32, + unitFees, unitCaps commonfees.Dimensions, + options ...common.Option, +) (*txs.TransformSubnetTx, error) { + // 1. Build core transaction without utxos + ops := common.NewOptions(options) + + subnetAuth, err := b.authorizeSubnet(subnetID, ops) + if err != nil { + return nil, err + } + + utx := &txs.TransformSubnetTx{ + BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ + NetworkID: b.backend.NetworkID(), + BlockchainID: constants.PlatformChainID, + Memo: ops.Memo(), + }}, + Subnet: subnetID, + AssetID: assetID, + InitialSupply: initialSupply, + MaximumSupply: maxSupply, + MinConsumptionRate: minConsumptionRate, + MaxConsumptionRate: maxConsumptionRate, + MinValidatorStake: minValidatorStake, + MaxValidatorStake: maxValidatorStake, + MinStakeDuration: uint32(minStakeDuration / time.Second), + MaxStakeDuration: uint32(maxStakeDuration / time.Second), + MinDelegationFee: minDelegationFee, + MinDelegatorStake: minDelegatorStake, + MaxValidatorWeightFactor: maxValidatorWeightFactor, + UptimeRequirement: uptimeRequirement, + SubnetAuth: subnetAuth, + } + + // 2. Finance the tx by building the utxos (inputs, outputs and stakes) + toStake := map[ids.ID]uint64{} + toBurn := map[ids.ID]uint64{ + assetID: maxSupply - initialSupply, + } // fees are calculated in financeTx + + feesMan := commonfees.NewManager(unitFees) + feeCalc := &fees.Calculator{ + IsEForkActive: true, + FeeManager: feesMan, + ConsumedUnitsCap: unitCaps, + } + + // update fees to account for the auth credentials to be added upon tx signing + credsDimensions, err := commonfees.GetCredentialsDimensions(txs.Codec, txs.CodecVersion, subnetAuth.SigIndices) + if err != nil { + return nil, fmt.Errorf("failed calculating input size: %w", err) + } + if err := feeCalc.AddFeesFor(credsDimensions); err != nil { + return nil, fmt.Errorf("account for input fees: %w", err) + } + toBurn[b.backend.AVAXAssetID()] += feeCalc.Fee + + // feesMan cumulates consumed units. Let's init it with utx filled so far + if err := feeCalc.TransformSubnetTx(utx); err != nil { + return nil, err + } + + inputs, outputs, _, err := b.financeTx(toBurn, toStake, feeCalc, ops) + if err != nil { + return nil, err + } + + utx.Ins = inputs + utx.Outs = outputs + + return utx, b.initCtx(utx) +} + +func (b *DynamicFeesBuilder) NewAddPermissionlessValidatorTx( + vdr *txs.SubnetValidator, + signer signer.Signer, + assetID ids.ID, + validationRewardsOwner *secp256k1fx.OutputOwners, + delegationRewardsOwner *secp256k1fx.OutputOwners, + shares uint32, + unitFees, unitCaps commonfees.Dimensions, + options ...common.Option, +) (*txs.AddPermissionlessValidatorTx, error) { + ops := common.NewOptions(options) + utils.Sort(validationRewardsOwner.Addrs) + utils.Sort(delegationRewardsOwner.Addrs) + + utx := &txs.AddPermissionlessValidatorTx{ + BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ + NetworkID: b.backend.NetworkID(), + BlockchainID: constants.PlatformChainID, + Memo: ops.Memo(), + }}, + Validator: vdr.Validator, + Subnet: vdr.Subnet, + Signer: signer, + ValidatorRewardsOwner: validationRewardsOwner, + DelegatorRewardsOwner: delegationRewardsOwner, + DelegationShares: shares, + } + + // 2. Finance the tx by building the utxos (inputs, outputs and stakes) + toStake := map[ids.ID]uint64{ + assetID: vdr.Wght, + } + toBurn := map[ids.ID]uint64{} // fees are calculated in financeTx + + feesMan := commonfees.NewManager(unitFees) + feeCalc := &fees.Calculator{ + IsEForkActive: true, + FeeManager: feesMan, + ConsumedUnitsCap: unitCaps, + } + + // feesMan cumulates consumed units. Let's init it with utx filled so far + if err := feeCalc.AddPermissionlessValidatorTx(utx); err != nil { + return nil, err + } + + inputs, outputs, stakeOutputs, err := b.financeTx(toBurn, toStake, feeCalc, ops) + if err != nil { + return nil, err + } + + utx.Ins = inputs + utx.Outs = outputs + utx.StakeOuts = stakeOutputs + + return utx, b.initCtx(utx) +} + +func (b *DynamicFeesBuilder) NewAddPermissionlessDelegatorTx( + vdr *txs.SubnetValidator, + assetID ids.ID, + rewardsOwner *secp256k1fx.OutputOwners, + unitFees, unitCaps commonfees.Dimensions, + options ...common.Option, +) (*txs.AddPermissionlessDelegatorTx, error) { + ops := common.NewOptions(options) + utils.Sort(rewardsOwner.Addrs) + + utx := &txs.AddPermissionlessDelegatorTx{ + BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ + NetworkID: b.backend.NetworkID(), + BlockchainID: constants.PlatformChainID, + Memo: ops.Memo(), + }}, + Validator: vdr.Validator, + Subnet: vdr.Subnet, + DelegationRewardsOwner: rewardsOwner, + } + + // 2. Finance the tx by building the utxos (inputs, outputs and stakes) + toStake := map[ids.ID]uint64{ + assetID: vdr.Wght, + } + toBurn := map[ids.ID]uint64{} // fees are calculated in financeTx + + feesMan := commonfees.NewManager(unitFees) + feeCalc := &fees.Calculator{ + IsEForkActive: true, + FeeManager: feesMan, + ConsumedUnitsCap: unitCaps, + } + + // feesMan cumulates consumed units. Let's init it with utx filled so far + if err := feeCalc.AddPermissionlessDelegatorTx(utx); err != nil { + return nil, err + } + + inputs, outputs, stakeOutputs, err := b.financeTx(toBurn, toStake, feeCalc, ops) + if err != nil { + return nil, err + } + + utx.Ins = inputs + utx.Outs = outputs + utx.StakeOuts = stakeOutputs + + return utx, b.initCtx(utx) +} + func (b *DynamicFeesBuilder) financeTx( amountsToBurn map[ids.ID]uint64, amountsToStake map[ids.ID]uint64, @@ -468,7 +834,12 @@ func (b *DynamicFeesBuilder) financeTx( switch { case feeCalc.Fee < remainingAmount: - changeOut.Out.(*secp256k1fx.TransferOutput).Amt = remainingAmount - feeCalc.Fee + if assetID == b.backend.AVAXAssetID() { + changeOut.Out.(*secp256k1fx.TransferOutput).Amt = remainingAmount - feeCalc.Fee + } else { + changeOut.Out.(*secp256k1fx.TransferOutput).Amt = remainingAmount + amountsToBurn[b.backend.AVAXAssetID()] += feeCalc.Fee + } changeOutputs = append(changeOutputs, changeOut) case feeCalc.Fee == remainingAmount: // fees wholly consume remaining amount. We don't add the change diff --git a/wallet/chain/p/builder_dynamic_fees_test.go b/wallet/chain/p/builder_dynamic_fees_test.go index a83b468ebcfc..b1c85e69e7d2 100644 --- a/wallet/chain/p/builder_dynamic_fees_test.go +++ b/wallet/chain/p/builder_dynamic_fees_test.go @@ -14,11 +14,13 @@ import ( "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils/constants" + "github.com/ava-labs/avalanchego/utils/crypto/bls" "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" "github.com/ava-labs/avalanchego/utils/set" "github.com/ava-labs/avalanchego/utils/units" "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/platformvm/reward" + "github.com/ava-labs/avalanchego/vms/platformvm/signer" "github.com/ava-labs/avalanchego/vms/platformvm/stakeable" "github.com/ava-labs/avalanchego/vms/platformvm/txs" "github.com/ava-labs/avalanchego/vms/platformvm/txs/fees" @@ -44,59 +46,192 @@ var ( } ) -// Create and sign the tx, then verify that utxos included +// These tests create and sign a tx, then verify that utxos included // in the tx are exactly necessary to pay fees for it -func TestCreateChainTx(t *testing.T) { + +func TestAddValidatorTx(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) be := mocks.NewMockBuilderBackend(ctrl) var ( - subnetAuthKey = testKeys[0] - utxosKey = testKeys[1] - subnetAuthAddr = subnetAuthKey.PublicKey().Address() - utxoAddr = utxosKey.PublicKey().Address() + rewardKey = testKeys[0] + utxosKey = testKeys[1] + rewardAddr = rewardKey.PublicKey().Address() + utxoAddr = utxosKey.PublicKey().Address() + utxos, avaxAssetID, _ = testUTXOsList(utxosKey) + rewardOwner = &secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{ + rewardKey.Address(), + }, + } ) b := &DynamicFeesBuilder{ - addrs: set.Of(utxoAddr, subnetAuthAddr), + addrs: set.Of(utxoAddr, rewardAddr), backend: be, } + be.EXPECT().AVAXAssetID().Return(avaxAssetID).AnyTimes() + be.EXPECT().NetworkID().Return(constants.MainnetID).AnyTimes() + be.EXPECT().UTXOs(gomock.Any(), constants.PlatformChainID).Return(utxos, nil) + + utx, err := b.NewAddValidatorTx( + &txs.Validator{ + NodeID: ids.GenerateTestNodeID(), + End: uint64(time.Now().Add(time.Hour).Unix()), + Wght: 2 * units.Avax, + }, + rewardOwner, + reward.PercentDenominator, + testUnitFees, + testBlockMaxConsumedUnits, + ) + require.NoError(err) var ( - subnetID = ids.GenerateTestID() - genesisBytes = []byte{'a', 'b', 'c'} - vmID = ids.GenerateTestID() - fxIDs = []ids.ID{ids.GenerateTestID()} - chainName = "dummyChain" + kc = secp256k1fx.NewKeychain(utxosKey) + sbe = mocks.NewMockSignerBackend(ctrl) + s = NewSigner(kc, sbe) ) - subnetTx := &txs.Tx{ - Unsigned: &txs.CreateSubnetTx{ - Owner: &secp256k1fx.OutputOwners{ - Threshold: 1, - Addrs: []ids.ShortID{subnetAuthKey.PublicKey().Address()}, + for _, utxo := range utxos { + sbe.EXPECT().GetUTXO(gomock.Any(), gomock.Any(), utxo.InputID()).Return(utxo, nil).AnyTimes() + } + + tx, err := s.SignUnsigned(stdcontext.Background(), utx) + require.NoError(err) + + fc := &fees.Calculator{ + IsEForkActive: true, + FeeManager: commonfees.NewManager(testUnitFees), + ConsumedUnitsCap: testBlockMaxConsumedUnits, + Credentials: tx.Creds, + } + require.NoError(utx.Visit(fc)) + require.Equal(12184*units.MicroAvax, fc.Fee) + + ins := utx.Ins + staked := utx.StakeOuts + outs := utx.Outs + require.Len(ins, 4) + require.Len(staked, 2) + require.Len(outs, 2) + require.Equal(utx.Validator.Weight(), staked[0].Out.Amount()+staked[1].Out.Amount()) + require.Equal(fc.Fee, ins[1].In.Amount()+ins[3].In.Amount()-outs[0].Out.Amount()) +} + +func TestAddSubnetValidatorTx(t *testing.T) { + require := require.New(t) + ctrl := gomock.NewController(t) + + be := mocks.NewMockBuilderBackend(ctrl) + + var ( + subnetAuthKey = testKeys[0] + utxosKey = testKeys[1] + subnetAuthAddr = subnetAuthKey.PublicKey().Address() + utxoAddr = utxosKey.PublicKey().Address() + utxos, avaxAssetID, _ = testUTXOsList(utxosKey) + subnetID = ids.GenerateTestID() + subnetTx = &txs.Tx{ + Unsigned: &txs.CreateSubnetTx{ + Owner: &secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{subnetAuthKey.PublicKey().Address()}, + }, }, - }, + } + ) + + b := &DynamicFeesBuilder{ + addrs: set.Of(utxoAddr, subnetAuthAddr), + backend: be, } + be.EXPECT().AVAXAssetID().Return(avaxAssetID).AnyTimes() + be.EXPECT().NetworkID().Return(constants.MainnetID).AnyTimes() + be.EXPECT().UTXOs(gomock.Any(), constants.PlatformChainID).Return(utxos, nil) be.EXPECT().GetTx(gomock.Any(), subnetID).Return(subnetTx, nil) + utx, err := b.NewAddSubnetValidatorTx( + &txs.SubnetValidator{ + Validator: txs.Validator{ + NodeID: ids.GenerateTestNodeID(), + End: uint64(time.Now().Add(time.Hour).Unix()), + }, + Subnet: subnetID, + }, + testUnitFees, + testBlockMaxConsumedUnits, + ) + require.NoError(err) + var ( - avaxAssetID = ids.GenerateTestID() - utxos = testUTXOsList(avaxAssetID, utxosKey) + kc = secp256k1fx.NewKeychain(utxosKey) + sbe = mocks.NewMockSignerBackend(ctrl) + s = NewSigner(kc, sbe) ) + for _, utxo := range utxos { + sbe.EXPECT().GetUTXO(gomock.Any(), gomock.Any(), utxo.InputID()).Return(utxo, nil).AnyTimes() + } + sbe.EXPECT().GetTx(gomock.Any(), subnetID).Return(subnetTx, nil) + + tx, err := s.SignUnsigned(stdcontext.Background(), utx) + require.NoError(err) + + fc := &fees.Calculator{ + IsEForkActive: true, + FeeManager: commonfees.NewManager(testUnitFees), + ConsumedUnitsCap: testBlockMaxConsumedUnits, + Credentials: tx.Creds, + } + require.NoError(utx.Visit(fc)) + require.Equal(5765*units.MicroAvax, fc.Fee) + + ins := utx.Ins + outs := utx.Outs + require.Len(ins, 2) + require.Len(outs, 1) + require.Equal(fc.Fee, ins[0].In.Amount()+ins[1].In.Amount()-outs[0].Out.Amount()) +} + +func TestRemoveSubnetValidatorTx(t *testing.T) { + require := require.New(t) + ctrl := gomock.NewController(t) + + be := mocks.NewMockBuilderBackend(ctrl) + + var ( + subnetAuthKey = testKeys[0] + utxosKey = testKeys[1] + subnetAuthAddr = subnetAuthKey.PublicKey().Address() + utxoAddr = utxosKey.PublicKey().Address() + utxos, avaxAssetID, _ = testUTXOsList(utxosKey) + subnetID = ids.GenerateTestID() + subnetTx = &txs.Tx{ + Unsigned: &txs.CreateSubnetTx{ + Owner: &secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{subnetAuthKey.PublicKey().Address()}, + }, + }, + } + ) + + b := &DynamicFeesBuilder{ + addrs: set.Of(utxoAddr, subnetAuthAddr), + backend: be, + } be.EXPECT().AVAXAssetID().Return(avaxAssetID).AnyTimes() be.EXPECT().NetworkID().Return(constants.MainnetID).AnyTimes() be.EXPECT().UTXOs(gomock.Any(), constants.PlatformChainID).Return(utxos, nil) + be.EXPECT().GetTx(gomock.Any(), subnetID).Return(subnetTx, nil) - utx, err := b.NewCreateChainTx( + utx, err := b.NewRemoveSubnetValidatorTx( + ids.GenerateTestNodeID(), subnetID, - genesisBytes, - vmID, - fxIDs, - chainName, testUnitFees, testBlockMaxConsumedUnits, ) @@ -123,7 +258,7 @@ func TestCreateChainTx(t *testing.T) { Credentials: tx.Creds, } require.NoError(utx.Visit(fc)) - require.Equal(5808*units.MicroAvax, fc.Fee) + require.Equal(5741*units.MicroAvax, fc.Fee) ins := utx.Ins outs := utx.Outs @@ -132,7 +267,79 @@ func TestCreateChainTx(t *testing.T) { require.Equal(fc.Fee, ins[0].In.Amount()+ins[1].In.Amount()-outs[0].Out.Amount()) } -func TestCreateSubnetTx(t *testing.T) { +func TestAddDelegatorTx(t *testing.T) { + require := require.New(t) + ctrl := gomock.NewController(t) + + be := mocks.NewMockBuilderBackend(ctrl) + + var ( + rewardKey = testKeys[0] + utxosKey = testKeys[1] + rewardAddr = rewardKey.PublicKey().Address() + utxoAddr = utxosKey.PublicKey().Address() + utxos, avaxAssetID, _ = testUTXOsList(utxosKey) + rewardOwner = &secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{ + rewardKey.Address(), + }, + } + ) + + b := &DynamicFeesBuilder{ + addrs: set.Of(utxoAddr, rewardAddr), + backend: be, + } + be.EXPECT().AVAXAssetID().Return(avaxAssetID).AnyTimes() + be.EXPECT().NetworkID().Return(constants.MainnetID).AnyTimes() + be.EXPECT().UTXOs(gomock.Any(), constants.PlatformChainID).Return(utxos, nil) + + utx, err := b.NewAddDelegatorTx( + &txs.Validator{ + NodeID: ids.GenerateTestNodeID(), + End: uint64(time.Now().Add(time.Hour).Unix()), + Wght: 2 * units.Avax, + }, + rewardOwner, + testUnitFees, + testBlockMaxConsumedUnits, + ) + require.NoError(err) + + var ( + kc = secp256k1fx.NewKeychain(utxosKey) + sbe = mocks.NewMockSignerBackend(ctrl) + s = NewSigner(kc, sbe) + ) + + for _, utxo := range utxos { + sbe.EXPECT().GetUTXO(gomock.Any(), gomock.Any(), utxo.InputID()).Return(utxo, nil).AnyTimes() + } + + tx, err := s.SignUnsigned(stdcontext.Background(), utx) + require.NoError(err) + + fc := &fees.Calculator{ + IsEForkActive: true, + FeeManager: commonfees.NewManager(testUnitFees), + ConsumedUnitsCap: testBlockMaxConsumedUnits, + Credentials: tx.Creds, + } + require.NoError(utx.Visit(fc)) + require.Equal(12180*units.MicroAvax, fc.Fee) + + ins := utx.Ins + staked := utx.StakeOuts + outs := utx.Outs + require.Len(ins, 4) + require.Len(staked, 2) + require.Len(outs, 2) + require.Equal(utx.Validator.Weight(), staked[0].Out.Amount()+staked[1].Out.Amount()) + require.Equal(fc.Fee, ins[1].In.Amount()+ins[3].In.Amount()-outs[0].Out.Amount()) +} + +func TestCreateChainTx(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) @@ -143,6 +350,19 @@ func TestCreateSubnetTx(t *testing.T) { utxosKey = testKeys[1] subnetAuthAddr = subnetAuthKey.PublicKey().Address() utxoAddr = utxosKey.PublicKey().Address() + subnetID = ids.GenerateTestID() + genesisBytes = []byte{'a', 'b', 'c'} + vmID = ids.GenerateTestID() + fxIDs = []ids.ID{ids.GenerateTestID()} + chainName = "dummyChain" + subnetTx = &txs.Tx{ + Unsigned: &txs.CreateSubnetTx{ + Owner: &secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{subnetAuthKey.PublicKey().Address()}, + }, + }, + } ) b := &DynamicFeesBuilder{ @@ -150,11 +370,67 @@ func TestCreateSubnetTx(t *testing.T) { backend: be, } + be.EXPECT().GetTx(gomock.Any(), subnetID).Return(subnetTx, nil) + + utxos, avaxAssetID, _ := testUTXOsList(utxosKey) + be.EXPECT().AVAXAssetID().Return(avaxAssetID).AnyTimes() + be.EXPECT().NetworkID().Return(constants.MainnetID).AnyTimes() + be.EXPECT().UTXOs(gomock.Any(), constants.PlatformChainID).Return(utxos, nil) + + utx, err := b.NewCreateChainTx( + subnetID, + genesisBytes, + vmID, + fxIDs, + chainName, + testUnitFees, + testBlockMaxConsumedUnits, + ) + require.NoError(err) + var ( - avaxAssetID = ids.GenerateTestID() - utxos = testUTXOsList(avaxAssetID, utxosKey) + kc = secp256k1fx.NewKeychain(utxosKey) + sbe = mocks.NewMockSignerBackend(ctrl) + s = NewSigner(kc, sbe) + ) - subnetOwner = &secp256k1fx.OutputOwners{ + for _, utxo := range utxos { + sbe.EXPECT().GetUTXO(gomock.Any(), gomock.Any(), utxo.InputID()).Return(utxo, nil).AnyTimes() + } + sbe.EXPECT().GetTx(gomock.Any(), subnetID).Return(subnetTx, nil) + + tx, err := s.SignUnsigned(stdcontext.Background(), utx) + require.NoError(err) + + fc := &fees.Calculator{ + IsEForkActive: true, + FeeManager: commonfees.NewManager(testUnitFees), + ConsumedUnitsCap: testBlockMaxConsumedUnits, + Credentials: tx.Creds, + } + require.NoError(utx.Visit(fc)) + require.Equal(5808*units.MicroAvax, fc.Fee) + + ins := utx.Ins + outs := utx.Outs + require.Len(ins, 2) + require.Len(outs, 1) + require.Equal(fc.Fee, ins[0].In.Amount()+ins[1].In.Amount()-outs[0].Out.Amount()) +} + +func TestCreateSubnetTx(t *testing.T) { + require := require.New(t) + ctrl := gomock.NewController(t) + + be := mocks.NewMockBuilderBackend(ctrl) + + var ( + subnetAuthKey = testKeys[0] + utxosKey = testKeys[1] + subnetAuthAddr = subnetAuthKey.PublicKey().Address() + utxoAddr = utxosKey.PublicKey().Address() + utxos, avaxAssetID, _ = testUTXOsList(utxosKey) + subnetOwner = &secp256k1fx.OutputOwners{ Threshold: 1, Addrs: []ids.ShortID{ subnetAuthKey.Address(), @@ -162,6 +438,10 @@ func TestCreateSubnetTx(t *testing.T) { } ) + b := &DynamicFeesBuilder{ + addrs: set.Of(utxoAddr, subnetAuthAddr), + backend: be, + } be.EXPECT().AVAXAssetID().Return(avaxAssetID).AnyTimes() be.EXPECT().NetworkID().Return(constants.MainnetID).AnyTimes() be.EXPECT().UTXOs(gomock.Any(), constants.PlatformChainID).Return(utxos, nil) @@ -202,29 +482,107 @@ func TestCreateSubnetTx(t *testing.T) { require.Equal(fc.Fee, ins[0].In.Amount()+ins[1].In.Amount()-outs[0].Out.Amount()) } -func TestAddValidatorTx(t *testing.T) { +func TestTransformSubnetTx(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) be := mocks.NewMockBuilderBackend(ctrl) var ( - rewardKey = testKeys[0] - utxosKey = testKeys[1] - subnetAuthAddr = rewardKey.PublicKey().Address() - utxoAddr = utxosKey.PublicKey().Address() + subnetAuthKey = testKeys[0] + utxosKey = testKeys[1] + subnetAuthAddr = subnetAuthKey.PublicKey().Address() + utxoAddr = utxosKey.PublicKey().Address() + subnetID = ids.GenerateTestID() + utxos, avaxAssetID, subnetAssetID = testUTXOsList(utxosKey) + subnetTx = &txs.Tx{ + Unsigned: &txs.CreateSubnetTx{ + Owner: &secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{subnetAuthKey.PublicKey().Address()}, + }, + }, + } ) b := &DynamicFeesBuilder{ addrs: set.Of(utxoAddr, subnetAuthAddr), backend: be, } + be.EXPECT().GetTx(gomock.Any(), subnetID).Return(subnetTx, nil) + be.EXPECT().AVAXAssetID().Return(avaxAssetID).AnyTimes() + be.EXPECT().NetworkID().Return(constants.MainnetID).AnyTimes() + be.EXPECT().UTXOs(gomock.Any(), constants.PlatformChainID).Return(utxos, nil) + + utx, err := b.NewTransformSubnetTx( + subnetID, + subnetAssetID, + 50*units.MegaAvax, // initial supply + 100*units.MegaAvax, // max supply + reward.PercentDenominator, // min consumption rate + reward.PercentDenominator, // max consumption rate + 1, // min validator stake + 100*units.MegaAvax, // max validator stake + time.Second, // min stake duration + 365*24*time.Hour, // max stake duration + 0, // min delegation fee + 1, // min delegator stake + 5, // max validator weight factor + .80*reward.PercentDenominator, // uptime requirement + testUnitFees, + testBlockMaxConsumedUnits, + ) + require.NoError(err) var ( - avaxAssetID = ids.GenerateTestID() - utxos = testUTXOsList(avaxAssetID, utxosKey) + kc = secp256k1fx.NewKeychain(utxosKey) + sbe = mocks.NewMockSignerBackend(ctrl) + s = NewSigner(kc, sbe) + ) + + for _, utxo := range utxos { + sbe.EXPECT().GetUTXO(gomock.Any(), gomock.Any(), utxo.InputID()).Return(utxo, nil).AnyTimes() + } + sbe.EXPECT().GetTx(gomock.Any(), subnetID).Return(subnetTx, nil) + + tx, err := s.SignUnsigned(stdcontext.Background(), utx) + require.NoError(err) - rewardOwner = &secp256k1fx.OutputOwners{ + fc := &fees.Calculator{ + IsEForkActive: true, + FeeManager: commonfees.NewManager(testUnitFees), + ConsumedUnitsCap: testBlockMaxConsumedUnits, + Credentials: tx.Creds, + } + require.NoError(utx.Visit(fc)) + require.Equal(8763*units.MicroAvax, fc.Fee) + + ins := utx.Ins + outs := utx.Outs + require.Len(ins, 3) + require.Len(outs, 2) + require.Equal(fc.Fee, ins[1].In.Amount()+ins[2].In.Amount()-outs[1].Out.Amount()) +} + +func TestAddPermissionlessValidatorTx(t *testing.T) { + require := require.New(t) + ctrl := gomock.NewController(t) + + be := mocks.NewMockBuilderBackend(ctrl) + + var ( + rewardKey = testKeys[0] + utxosKey = testKeys[1] + rewardAddr = rewardKey.PublicKey().Address() + utxoAddr = utxosKey.PublicKey().Address() + utxos, avaxAssetID, _ = testUTXOsList(utxosKey) + validationRewardsOwner = &secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{ + rewardKey.Address(), + }, + } + delegationRewardsOwner = &secp256k1fx.OutputOwners{ Threshold: 1, Addrs: []ids.ShortID{ rewardKey.Address(), @@ -232,17 +590,30 @@ func TestAddValidatorTx(t *testing.T) { } ) + sk, err := bls.NewSecretKey() + require.NoError(err) + + b := &DynamicFeesBuilder{ + addrs: set.Of(utxoAddr, rewardAddr), + backend: be, + } be.EXPECT().AVAXAssetID().Return(avaxAssetID).AnyTimes() be.EXPECT().NetworkID().Return(constants.MainnetID).AnyTimes() be.EXPECT().UTXOs(gomock.Any(), constants.PlatformChainID).Return(utxos, nil) - utx, err := b.NewAddValidatorTx( - &txs.Validator{ - NodeID: ids.GenerateTestNodeID(), - End: uint64(time.Now().Add(time.Hour).Unix()), - Wght: 2 * units.Avax, + utx, err := b.NewAddPermissionlessValidatorTx( + &txs.SubnetValidator{ + Validator: txs.Validator{ + NodeID: ids.GenerateTestNodeID(), + End: uint64(time.Now().Add(time.Hour).Unix()), + Wght: 2 * units.Avax, + }, + Subnet: constants.PrimaryNetworkID, }, - rewardOwner, + signer.NewProofOfPossession(sk), + avaxAssetID, + validationRewardsOwner, + delegationRewardsOwner, reward.PercentDenominator, testUnitFees, testBlockMaxConsumedUnits, @@ -269,7 +640,7 @@ func TestAddValidatorTx(t *testing.T) { Credentials: tx.Creds, } require.NoError(utx.Visit(fc)) - require.Equal(12184*units.MicroAvax, fc.Fee) + require.Equal(12404*units.MicroAvax, fc.Fee) ins := utx.Ins staked := utx.StakeOuts @@ -278,78 +649,180 @@ func TestAddValidatorTx(t *testing.T) { require.Len(staked, 2) require.Len(outs, 2) require.Equal(utx.Validator.Weight(), staked[0].Out.Amount()+staked[1].Out.Amount()) - require.Equal(fc.Fee, ins[2].In.Amount()+ins[3].In.Amount()-outs[0].Out.Amount()) + require.Equal(fc.Fee, ins[1].In.Amount()+ins[3].In.Amount()-outs[0].Out.Amount()) } -func testUTXOsList(avaxAssetID ids.ID, utxosKey *secp256k1.PrivateKey) []*avax.UTXO { +func TestAddPermissionlessDelegatorTx(t *testing.T) { + require := require.New(t) + ctrl := gomock.NewController(t) + + be := mocks.NewMockBuilderBackend(ctrl) + + var ( + rewardKey = testKeys[0] + utxosKey = testKeys[1] + rewardAddr = rewardKey.PublicKey().Address() + utxoAddr = utxosKey.PublicKey().Address() + utxos, avaxAssetID, _ = testUTXOsList(utxosKey) + rewardsOwner = &secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{ + rewardKey.Address(), + }, + } + ) + + b := &DynamicFeesBuilder{ + addrs: set.Of(utxoAddr, rewardAddr), + backend: be, + } + be.EXPECT().AVAXAssetID().Return(avaxAssetID).AnyTimes() + be.EXPECT().NetworkID().Return(constants.MainnetID).AnyTimes() + be.EXPECT().UTXOs(gomock.Any(), constants.PlatformChainID).Return(utxos, nil) + + utx, err := b.NewAddPermissionlessDelegatorTx( + &txs.SubnetValidator{ + Validator: txs.Validator{ + NodeID: ids.GenerateTestNodeID(), + End: uint64(time.Now().Add(time.Hour).Unix()), + Wght: 2 * units.Avax, + }, + Subnet: constants.PrimaryNetworkID, + }, + avaxAssetID, + rewardsOwner, + testUnitFees, + testBlockMaxConsumedUnits, + ) + require.NoError(err) + + var ( + kc = secp256k1fx.NewKeychain(utxosKey) + sbe = mocks.NewMockSignerBackend(ctrl) + s = NewSigner(kc, sbe) + ) + + for _, utxo := range utxos { + sbe.EXPECT().GetUTXO(gomock.Any(), gomock.Any(), utxo.InputID()).Return(utxo, nil).AnyTimes() + } + + tx, err := s.SignUnsigned(stdcontext.Background(), utx) + require.NoError(err) + + fc := &fees.Calculator{ + IsEForkActive: true, + FeeManager: commonfees.NewManager(testUnitFees), + ConsumedUnitsCap: testBlockMaxConsumedUnits, + Credentials: tx.Creds, + } + require.NoError(utx.Visit(fc)) + require.Equal(12212*units.MicroAvax, fc.Fee) + + ins := utx.Ins + staked := utx.StakeOuts + outs := utx.Outs + require.Len(ins, 4) + require.Len(staked, 2) + require.Len(outs, 2) + require.Equal(utx.Validator.Weight(), staked[0].Out.Amount()+staked[1].Out.Amount()) + require.Equal(fc.Fee, ins[1].In.Amount()+ins[3].In.Amount()-outs[0].Out.Amount()) +} + +func testUTXOsList(utxosKey *secp256k1.PrivateKey) ( + []*avax.UTXO, + ids.ID, // avaxAssetID, + ids.ID, // subnetAssetID +) { // Note: we avoid ids.GenerateTestNodeID here to make sure that UTXO IDs won't change // run by run. This simplifies checking what utxos are included in the built txs. utxosOffset := uint64(2024) + var ( + avaxAssetID = ids.Empty.Prefix(utxosOffset) + subnetAssetID = ids.Empty.Prefix(utxosOffset + 1) + ) + return []*avax.UTXO{ // currently, the wallet scans UTXOs in the order provided here - { // a small UTXO first, which should not be enough to pay fees - UTXOID: avax.UTXOID{ - TxID: ids.Empty.Prefix(utxosOffset), - OutputIndex: uint32(utxosOffset), - }, - Asset: avax.Asset{ID: avaxAssetID}, - Out: &secp256k1fx.TransferOutput{ - Amt: 2 * units.MilliAvax, - OutputOwners: secp256k1fx.OutputOwners{ - Locktime: 0, - Addrs: []ids.ShortID{utxosKey.PublicKey().Address()}, - Threshold: 1, + { // a small UTXO first, which should not be enough to pay fees + UTXOID: avax.UTXOID{ + TxID: ids.Empty.Prefix(utxosOffset), + OutputIndex: uint32(utxosOffset), }, - }, - }, - { // a locked, small UTXO - UTXOID: avax.UTXOID{ - TxID: ids.Empty.Prefix(utxosOffset + 1), - OutputIndex: uint32(utxosOffset + 1), - }, - Asset: avax.Asset{ID: avaxAssetID}, - Out: &stakeable.LockOut{ - Locktime: uint64(time.Now().Add(time.Second).Unix()), - TransferableOut: &secp256k1fx.TransferOutput{ - Amt: 3 * units.MilliAvax, + Asset: avax.Asset{ID: avaxAssetID}, + Out: &secp256k1fx.TransferOutput{ + Amt: 2 * units.MilliAvax, OutputOwners: secp256k1fx.OutputOwners{ - Threshold: 1, + Locktime: 0, Addrs: []ids.ShortID{utxosKey.PublicKey().Address()}, + Threshold: 1, }, }, }, - }, - { // a locked, large UTXO - UTXOID: avax.UTXOID{ - TxID: ids.Empty.Prefix(utxosOffset + 2), - OutputIndex: uint32(utxosOffset + 2), + { // a locked, small UTXO + UTXOID: avax.UTXOID{ + TxID: ids.Empty.Prefix(utxosOffset + 1), + OutputIndex: uint32(utxosOffset + 1), + }, + Asset: avax.Asset{ID: avaxAssetID}, + Out: &stakeable.LockOut{ + Locktime: uint64(time.Now().Add(time.Second).Unix()), + TransferableOut: &secp256k1fx.TransferOutput{ + Amt: 3 * units.MilliAvax, + OutputOwners: secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{utxosKey.PublicKey().Address()}, + }, + }, + }, }, - Asset: avax.Asset{ID: avaxAssetID}, - Out: &stakeable.LockOut{ - Locktime: uint64(time.Now().Add(time.Second).Unix()), - TransferableOut: &secp256k1fx.TransferOutput{ - Amt: 99 * units.Avax, + { // a subnetAssetID denominated UTXO + UTXOID: avax.UTXOID{ + TxID: ids.Empty.Prefix(utxosOffset + 2), + OutputIndex: uint32(utxosOffset + 2), + }, + Asset: avax.Asset{ID: subnetAssetID}, + Out: &secp256k1fx.TransferOutput{ + Amt: 99 * units.MegaAvax, OutputOwners: secp256k1fx.OutputOwners{ - Threshold: 1, + Locktime: 0, Addrs: []ids.ShortID{utxosKey.PublicKey().Address()}, + Threshold: 1, }, }, }, - }, - { // a large UTXO last, which should be enough to pay any fee by itself - UTXOID: avax.UTXOID{ - TxID: ids.Empty.Prefix(utxosOffset + 3), - OutputIndex: uint32(utxosOffset + 3), + { // a locked, large UTXO + UTXOID: avax.UTXOID{ + TxID: ids.Empty.Prefix(utxosOffset + 3), + OutputIndex: uint32(utxosOffset + 3), + }, + Asset: avax.Asset{ID: avaxAssetID}, + Out: &stakeable.LockOut{ + Locktime: uint64(time.Now().Add(time.Second).Unix()), + TransferableOut: &secp256k1fx.TransferOutput{ + Amt: 88 * units.Avax, + OutputOwners: secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{utxosKey.PublicKey().Address()}, + }, + }, + }, }, - Asset: avax.Asset{ID: avaxAssetID}, - Out: &secp256k1fx.TransferOutput{ - Amt: 10 * units.Avax, - OutputOwners: secp256k1fx.OutputOwners{ - Locktime: 0, - Addrs: []ids.ShortID{utxosKey.PublicKey().Address()}, - Threshold: 1, + { // a large UTXO last, which should be enough to pay any fee by itself + UTXOID: avax.UTXOID{ + TxID: ids.Empty.Prefix(utxosOffset + 4), + OutputIndex: uint32(utxosOffset + 4), + }, + Asset: avax.Asset{ID: avaxAssetID}, + Out: &secp256k1fx.TransferOutput{ + Amt: 9 * units.Avax, + OutputOwners: secp256k1fx.OutputOwners{ + Locktime: 0, + Addrs: []ids.ShortID{utxosKey.PublicKey().Address()}, + Threshold: 1, + }, }, }, }, - } + avaxAssetID, + subnetAssetID } From c5182e84471d3181c44e00d98ff5a5a488364bf3 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 25 Jan 2024 10:31:31 +0100 Subject: [PATCH 068/190] added ExportTx to dynamic fees builder --- wallet/chain/p/builder_dynamic_fees.go | 55 +++++++++++++++ wallet/chain/p/builder_dynamic_fees_test.go | 77 +++++++++++++++++++-- 2 files changed, 128 insertions(+), 4 deletions(-) diff --git a/wallet/chain/p/builder_dynamic_fees.go b/wallet/chain/p/builder_dynamic_fees.go index ae10214dd0d6..e02124b54b15 100644 --- a/wallet/chain/p/builder_dynamic_fees.go +++ b/wallet/chain/p/builder_dynamic_fees.go @@ -358,6 +358,61 @@ func (b *DynamicFeesBuilder) NewCreateSubnetTx( return utx, b.initCtx(utx) } +func (b *DynamicFeesBuilder) NewExportTx( + chainID ids.ID, + outputs []*avax.TransferableOutput, + unitFees, unitCaps commonfees.Dimensions, + options ...common.Option, +) (*txs.ExportTx, error) { + // 1. Build core transaction without utxos + ops := common.NewOptions(options) + avax.SortTransferableOutputs(outputs, txs.Codec) // sort exported outputs + + utx := &txs.ExportTx{ + BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ + NetworkID: b.backend.NetworkID(), + BlockchainID: constants.PlatformChainID, + Memo: ops.Memo(), + }}, + DestinationChain: chainID, + ExportedOutputs: outputs, + } + + // 2. Finance the tx by building the utxos (inputs, outputs and stakes) + toStake := map[ids.ID]uint64{} + toBurn := map[ids.ID]uint64{} // fees are calculated in financeTx + for _, out := range outputs { + assetID := out.AssetID() + amountToBurn, err := math.Add64(toBurn[assetID], out.Out.Amount()) + if err != nil { + return nil, err + } + toBurn[assetID] = amountToBurn + } + + feesMan := commonfees.NewManager(unitFees) + feeCalc := &fees.Calculator{ + IsEForkActive: true, + FeeManager: feesMan, + ConsumedUnitsCap: unitCaps, + } + + // feesMan cumulates consumed units. Let's init it with utx filled so far + if err := feeCalc.ExportTx(utx); err != nil { + return nil, err + } + + inputs, changeOuts, _, err := b.financeTx(toBurn, toStake, feeCalc, ops) + if err != nil { + return nil, err + } + + utx.Ins = inputs + utx.Outs = changeOuts + + return utx, b.initCtx(utx) +} + func (b *DynamicFeesBuilder) NewTransformSubnetTx( subnetID ids.ID, assetID ids.ID, diff --git a/wallet/chain/p/builder_dynamic_fees_test.go b/wallet/chain/p/builder_dynamic_fees_test.go index b1c85e69e7d2..382d67f58832 100644 --- a/wallet/chain/p/builder_dynamic_fees_test.go +++ b/wallet/chain/p/builder_dynamic_fees_test.go @@ -427,7 +427,6 @@ func TestCreateSubnetTx(t *testing.T) { var ( subnetAuthKey = testKeys[0] utxosKey = testKeys[1] - subnetAuthAddr = subnetAuthKey.PublicKey().Address() utxoAddr = utxosKey.PublicKey().Address() utxos, avaxAssetID, _ = testUTXOsList(utxosKey) subnetOwner = &secp256k1fx.OutputOwners{ @@ -439,7 +438,7 @@ func TestCreateSubnetTx(t *testing.T) { ) b := &DynamicFeesBuilder{ - addrs: set.Of(utxoAddr, subnetAuthAddr), + addrs: set.Of(utxoAddr), backend: be, } be.EXPECT().AVAXAssetID().Return(avaxAssetID).AnyTimes() @@ -482,6 +481,76 @@ func TestCreateSubnetTx(t *testing.T) { require.Equal(fc.Fee, ins[0].In.Amount()+ins[1].In.Amount()-outs[0].Out.Amount()) } +func TestExportTx(t *testing.T) { + require := require.New(t) + ctrl := gomock.NewController(t) + + be := mocks.NewMockBuilderBackend(ctrl) + + var ( + utxosKey = testKeys[1] + utxoAddr = utxosKey.PublicKey().Address() + subnetID = ids.GenerateTestID() + utxos, avaxAssetID, _ = testUTXOsList(utxosKey) + + exportedOutputs = []*avax.TransferableOutput{{ + Asset: avax.Asset{ID: avaxAssetID}, + Out: &secp256k1fx.TransferOutput{ + Amt: 7 * units.Avax, + OutputOwners: secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{utxosKey.PublicKey().Address()}, + }, + }, + }} + ) + + b := &DynamicFeesBuilder{ + addrs: set.Of(utxoAddr), + backend: be, + } + be.EXPECT().AVAXAssetID().Return(avaxAssetID).AnyTimes() + be.EXPECT().NetworkID().Return(constants.MainnetID).AnyTimes() + be.EXPECT().UTXOs(gomock.Any(), constants.PlatformChainID).Return(utxos, nil) + + utx, err := b.NewExportTx( + subnetID, + exportedOutputs, + testUnitFees, + testBlockMaxConsumedUnits, + ) + require.NoError(err) + + var ( + kc = secp256k1fx.NewKeychain(utxosKey) + sbe = mocks.NewMockSignerBackend(ctrl) + s = NewSigner(kc, sbe) + ) + + for _, utxo := range utxos { + sbe.EXPECT().GetUTXO(gomock.Any(), gomock.Any(), utxo.InputID()).Return(utxo, nil).AnyTimes() + } + + tx, err := s.SignUnsigned(stdcontext.Background(), utx) + require.NoError(err) + + fc := &fees.Calculator{ + IsEForkActive: true, + FeeManager: commonfees.NewManager(testUnitFees), + ConsumedUnitsCap: testBlockMaxConsumedUnits, + Credentials: tx.Creds, + } + require.NoError(utx.Visit(fc)) + require.Equal(5966*units.MicroAvax, fc.Fee) + + ins := utx.Ins + outs := utx.Outs + require.Len(ins, 2) + require.Len(outs, 1) + require.Equal(fc.Fee+exportedOutputs[0].Out.Amount(), ins[0].In.Amount()+ins[1].In.Amount()-outs[0].Out.Amount()) + require.Equal(utx.ExportedOutputs, exportedOutputs) +} + func TestTransformSubnetTx(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) @@ -765,7 +834,7 @@ func testUTXOsList(utxosKey *secp256k1.PrivateKey) ( }, Asset: avax.Asset{ID: avaxAssetID}, Out: &stakeable.LockOut{ - Locktime: uint64(time.Now().Add(time.Second).Unix()), + Locktime: uint64(time.Now().Add(time.Hour).Unix()), TransferableOut: &secp256k1fx.TransferOutput{ Amt: 3 * units.MilliAvax, OutputOwners: secp256k1fx.OutputOwners{ @@ -797,7 +866,7 @@ func testUTXOsList(utxosKey *secp256k1.PrivateKey) ( }, Asset: avax.Asset{ID: avaxAssetID}, Out: &stakeable.LockOut{ - Locktime: uint64(time.Now().Add(time.Second).Unix()), + Locktime: uint64(time.Now().Add(time.Hour).Unix()), TransferableOut: &secp256k1fx.TransferOutput{ Amt: 88 * units.Avax, OutputOwners: secp256k1fx.OutputOwners{ From 728d8db751030ca45c18009c217b1e8684b25e8f Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 25 Jan 2024 10:53:16 +0100 Subject: [PATCH 069/190] added BaseTx to dynamic fees builder --- wallet/chain/p/builder_dynamic_fees.go | 54 ++++++++++++++++ wallet/chain/p/builder_dynamic_fees_test.go | 68 +++++++++++++++++++++ 2 files changed, 122 insertions(+) diff --git a/wallet/chain/p/builder_dynamic_fees.go b/wallet/chain/p/builder_dynamic_fees.go index e02124b54b15..cc24c4d1cbf0 100644 --- a/wallet/chain/p/builder_dynamic_fees.go +++ b/wallet/chain/p/builder_dynamic_fees.go @@ -28,6 +28,60 @@ type DynamicFeesBuilder struct { backend BuilderBackend } +func (b *DynamicFeesBuilder) NewBaseTx( + outputs []*avax.TransferableOutput, + unitFees, unitCaps commonfees.Dimensions, + options ...common.Option, +) (*txs.BaseTx, error) { + // 1. Build core transaction without utxos + ops := common.NewOptions(options) + + utx := &txs.BaseTx{ + BaseTx: avax.BaseTx{ + NetworkID: b.backend.NetworkID(), + BlockchainID: constants.PlatformChainID, + Memo: ops.Memo(), + Outs: outputs, // not sorted yet, we'll sort later on when we have all the outputs + }, + } + + // 2. Finance the tx by building the utxos (inputs, outputs and stakes) + toStake := map[ids.ID]uint64{} + toBurn := map[ids.ID]uint64{} // fees are calculated in financeTx + for _, out := range outputs { + assetID := out.AssetID() + amountToBurn, err := math.Add64(toBurn[assetID], out.Out.Amount()) + if err != nil { + return nil, err + } + toBurn[assetID] = amountToBurn + } + + feesMan := commonfees.NewManager(unitFees) + feeCalc := &fees.Calculator{ + IsEForkActive: true, + FeeManager: feesMan, + ConsumedUnitsCap: unitCaps, + } + + // feesMan cumulates consumed units. Let's init it with utx filled so far + if err := feeCalc.BaseTx(utx); err != nil { + return nil, err + } + + inputs, changeOuts, _, err := b.financeTx(toBurn, toStake, feeCalc, ops) + if err != nil { + return nil, err + } + + outputs = append(outputs, changeOuts...) + avax.SortTransferableOutputs(outputs, txs.Codec) + utx.Ins = inputs + utx.Outs = outputs + + return utx, b.initCtx(utx) +} + func (b *DynamicFeesBuilder) NewAddValidatorTx( vdr *txs.Validator, rewardsOwner *secp256k1fx.OutputOwners, diff --git a/wallet/chain/p/builder_dynamic_fees_test.go b/wallet/chain/p/builder_dynamic_fees_test.go index 382d67f58832..752ba8f580a1 100644 --- a/wallet/chain/p/builder_dynamic_fees_test.go +++ b/wallet/chain/p/builder_dynamic_fees_test.go @@ -49,6 +49,74 @@ var ( // These tests create and sign a tx, then verify that utxos included // in the tx are exactly necessary to pay fees for it +func TestBaseTx(t *testing.T) { + require := require.New(t) + ctrl := gomock.NewController(t) + + be := mocks.NewMockBuilderBackend(ctrl) + + var ( + utxosKey = testKeys[1] + utxoAddr = utxosKey.PublicKey().Address() + utxos, avaxAssetID, _ = testUTXOsList(utxosKey) + + outputsToMove = []*avax.TransferableOutput{{ + Asset: avax.Asset{ID: avaxAssetID}, + Out: &secp256k1fx.TransferOutput{ + Amt: 7 * units.Avax, + OutputOwners: secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{utxosKey.PublicKey().Address()}, + }, + }, + }} + ) + + b := &DynamicFeesBuilder{ + addrs: set.Of(utxoAddr), + backend: be, + } + be.EXPECT().AVAXAssetID().Return(avaxAssetID).AnyTimes() + be.EXPECT().NetworkID().Return(constants.MainnetID).AnyTimes() + be.EXPECT().UTXOs(gomock.Any(), constants.PlatformChainID).Return(utxos, nil) + + utx, err := b.NewBaseTx( + outputsToMove, + testUnitFees, + testBlockMaxConsumedUnits, + ) + require.NoError(err) + + var ( + kc = secp256k1fx.NewKeychain(utxosKey) + sbe = mocks.NewMockSignerBackend(ctrl) + s = NewSigner(kc, sbe) + ) + + for _, utxo := range utxos { + sbe.EXPECT().GetUTXO(gomock.Any(), gomock.Any(), utxo.InputID()).Return(utxo, nil).AnyTimes() + } + + tx, err := s.SignUnsigned(stdcontext.Background(), utx) + require.NoError(err) + + fc := &fees.Calculator{ + IsEForkActive: true, + FeeManager: commonfees.NewManager(testUnitFees), + ConsumedUnitsCap: testBlockMaxConsumedUnits, + Credentials: tx.Creds, + } + require.NoError(utx.Visit(fc)) + require.Equal(5930*units.MicroAvax, fc.Fee) + + ins := utx.Ins + outs := utx.Outs + require.Len(ins, 2) + require.Len(outs, 2) + require.Equal(fc.Fee+outputsToMove[0].Out.Amount(), ins[0].In.Amount()+ins[1].In.Amount()-outs[0].Out.Amount()) + require.Equal(outputsToMove[0], outs[1]) +} + func TestAddValidatorTx(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) From c76445de0c3baa01ab48a52999989639078de663 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 25 Jan 2024 16:30:35 +0100 Subject: [PATCH 070/190] fixed Add/RemoveFees --- vms/platformvm/txs/builder/builder.go | 7 +- vms/platformvm/txs/fees/calculator.go | 57 +++++++++------ vms/platformvm/txs/fees/calculator_test.go | 32 ++++++--- vms/platformvm/utxo/handler.go | 36 ++++++---- vms/platformvm/utxo/handler_test.go | 80 +++++++++++++++++++--- wallet/chain/p/builder_dynamic_fees.go | 62 +++++++++-------- 6 files changed, 187 insertions(+), 87 deletions(-) diff --git a/vms/platformvm/txs/builder/builder.go b/vms/platformvm/txs/builder/builder.go index 649cb0e3b18c..202daa697422 100644 --- a/vms/platformvm/txs/builder/builder.go +++ b/vms/platformvm/txs/builder/builder.go @@ -366,14 +366,15 @@ func (b *builder) NewImportTx( if err != nil { return nil, fmt.Errorf("failed calculating output size: %w", err) } - if err := feeCalc.AddFeesFor(outDimensions); err != nil { + addedFees, err := feeCalc.AddFeesFor(outDimensions) + if err != nil { return nil, fmt.Errorf("account for output fees: %w", err) } - if feeCalc.Fee >= importedAVAX { + if addedFees >= importedAVAX { // imported avax are not enough to pay fees // Drop the changeOut and finance the tx - if err := feeCalc.RemoveFeesFor(outDimensions); err != nil { + if _, err := feeCalc.RemoveFeesFor(outDimensions); err != nil { return nil, fmt.Errorf("failed reverting change output: %w", err) } feeCalc.Fee -= importedAVAX diff --git a/vms/platformvm/txs/fees/calculator.go b/vms/platformvm/txs/fees/calculator.go index 39fbbf425da2..c64e7f3f6de1 100644 --- a/vms/platformvm/txs/fees/calculator.go +++ b/vms/platformvm/txs/fees/calculator.go @@ -76,7 +76,8 @@ func (fc *Calculator) AddValidatorTx(tx *txs.AddValidatorTx) error { return err } - return fc.AddFeesFor(consumedUnits) + _, err = fc.AddFeesFor(consumedUnits) + return err } func (fc *Calculator) AddSubnetValidatorTx(tx *txs.AddSubnetValidatorTx) error { @@ -90,7 +91,8 @@ func (fc *Calculator) AddSubnetValidatorTx(tx *txs.AddSubnetValidatorTx) error { return err } - return fc.AddFeesFor(consumedUnits) + _, err = fc.AddFeesFor(consumedUnits) + return err } func (fc *Calculator) AddDelegatorTx(tx *txs.AddDelegatorTx) error { @@ -108,7 +110,8 @@ func (fc *Calculator) AddDelegatorTx(tx *txs.AddDelegatorTx) error { return err } - return fc.AddFeesFor(consumedUnits) + _, err = fc.AddFeesFor(consumedUnits) + return err } func (fc *Calculator) CreateChainTx(tx *txs.CreateChainTx) error { @@ -122,7 +125,8 @@ func (fc *Calculator) CreateChainTx(tx *txs.CreateChainTx) error { return err } - return fc.AddFeesFor(consumedUnits) + _, err = fc.AddFeesFor(consumedUnits) + return err } func (fc *Calculator) CreateSubnetTx(tx *txs.CreateSubnetTx) error { @@ -136,7 +140,8 @@ func (fc *Calculator) CreateSubnetTx(tx *txs.CreateSubnetTx) error { return err } - return fc.AddFeesFor(consumedUnits) + _, err = fc.AddFeesFor(consumedUnits) + return err } func (*Calculator) AdvanceTimeTx(*txs.AdvanceTimeTx) error { @@ -158,7 +163,8 @@ func (fc *Calculator) RemoveSubnetValidatorTx(tx *txs.RemoveSubnetValidatorTx) e return err } - return fc.AddFeesFor(consumedUnits) + _, err = fc.AddFeesFor(consumedUnits) + return err } func (fc *Calculator) TransformSubnetTx(tx *txs.TransformSubnetTx) error { @@ -172,7 +178,8 @@ func (fc *Calculator) TransformSubnetTx(tx *txs.TransformSubnetTx) error { return err } - return fc.AddFeesFor(consumedUnits) + _, err = fc.AddFeesFor(consumedUnits) + return err } func (fc *Calculator) TransferSubnetOwnershipTx(tx *txs.TransferSubnetOwnershipTx) error { @@ -186,7 +193,8 @@ func (fc *Calculator) TransferSubnetOwnershipTx(tx *txs.TransferSubnetOwnershipT return err } - return fc.AddFeesFor(consumedUnits) + _, err = fc.AddFeesFor(consumedUnits) + return err } func (fc *Calculator) AddPermissionlessValidatorTx(tx *txs.AddPermissionlessValidatorTx) error { @@ -208,7 +216,8 @@ func (fc *Calculator) AddPermissionlessValidatorTx(tx *txs.AddPermissionlessVali return err } - return fc.AddFeesFor(consumedUnits) + _, err = fc.AddFeesFor(consumedUnits) + return err } func (fc *Calculator) AddPermissionlessDelegatorTx(tx *txs.AddPermissionlessDelegatorTx) error { @@ -230,7 +239,8 @@ func (fc *Calculator) AddPermissionlessDelegatorTx(tx *txs.AddPermissionlessDele return err } - return fc.AddFeesFor(consumedUnits) + _, err = fc.AddFeesFor(consumedUnits) + return err } func (fc *Calculator) BaseTx(tx *txs.BaseTx) error { @@ -244,7 +254,8 @@ func (fc *Calculator) BaseTx(tx *txs.BaseTx) error { return err } - return fc.AddFeesFor(consumedUnits) + _, err = fc.AddFeesFor(consumedUnits) + return err } func (fc *Calculator) ImportTx(tx *txs.ImportTx) error { @@ -262,7 +273,8 @@ func (fc *Calculator) ImportTx(tx *txs.ImportTx) error { return err } - return fc.AddFeesFor(consumedUnits) + _, err = fc.AddFeesFor(consumedUnits) + return err } func (fc *Calculator) ExportTx(tx *txs.ExportTx) error { @@ -280,7 +292,8 @@ func (fc *Calculator) ExportTx(tx *txs.ExportTx) error { return err } - return fc.AddFeesFor(consumedUnits) + _, err = fc.AddFeesFor(consumedUnits) + return err } func (fc *Calculator) commonConsumedUnits( @@ -323,31 +336,31 @@ func (fc *Calculator) commonConsumedUnits( return consumedUnits, nil } -func (fc *Calculator) AddFeesFor(consumedUnits fees.Dimensions) error { +func (fc *Calculator) AddFeesFor(consumedUnits fees.Dimensions) (uint64, error) { boundBreached, dimension := fc.FeeManager.CumulateUnits(consumedUnits, fc.ConsumedUnitsCap) if boundBreached { - return fmt.Errorf("%w: breached dimension %d", errFailedConsumedUnitsCumulation, dimension) + return 0, fmt.Errorf("%w: breached dimension %d", errFailedConsumedUnitsCumulation, dimension) } fee, err := fc.FeeManager.CalculateFee(consumedUnits) if err != nil { - return fmt.Errorf("%w: %w", errFailedFeeCalculation, err) + return 0, fmt.Errorf("%w: %w", errFailedFeeCalculation, err) } - fc.Fee = fee - return nil + fc.Fee += fee + return fee, nil } -func (fc *Calculator) RemoveFeesFor(unitsToRm fees.Dimensions) error { +func (fc *Calculator) RemoveFeesFor(unitsToRm fees.Dimensions) (uint64, error) { if err := fc.FeeManager.RemoveUnits(unitsToRm); err != nil { - return fmt.Errorf("failed removing units: %w", err) + return 0, fmt.Errorf("failed removing units: %w", err) } fee, err := fc.FeeManager.CalculateFee(unitsToRm) if err != nil { - return fmt.Errorf("%w: %w", errFailedFeeCalculation, err) + return 0, fmt.Errorf("%w: %w", errFailedFeeCalculation, err) } fc.Fee -= fee - return nil + return fee, nil } diff --git a/vms/platformvm/txs/fees/calculator_test.go b/vms/platformvm/txs/fees/calculator_test.go index 524b944c329b..fcde6cb205ab 100644 --- a/vms/platformvm/txs/fees/calculator_test.go +++ b/vms/platformvm/txs/fees/calculator_test.go @@ -127,19 +127,33 @@ func TestAddAndRemoveFees(t *testing.T) { ConsumedUnitsCap: testBlockMaxConsumedUnits, } - units := fees.Dimensions{ - 1, - 2, - 3, - 4, - } + var ( + units = fees.Dimensions{1, 2, 3, 4} + doubleUnits = fees.Dimensions{2, 4, 6, 8} + ) + + feeDelta, err := fc.AddFeesFor(units) + r.NoError(err) + r.Equal(units, fc.FeeManager.GetCumulatedUnits()) + r.NotZero(feeDelta) + r.Equal(feeDelta, fc.Fee) - r.NoError(fc.AddFeesFor(units)) + feeDelta2, err := fc.AddFeesFor(units) + r.NoError(err) + r.Equal(doubleUnits, fc.FeeManager.GetCumulatedUnits()) + r.Equal(feeDelta, feeDelta2) + r.Equal(feeDelta+feeDelta2, fc.Fee) + + feeDelta3, err := fc.RemoveFeesFor(units) + r.NoError(err) r.Equal(units, fc.FeeManager.GetCumulatedUnits()) - r.NotZero(fc.Fee) + r.Equal(feeDelta, feeDelta3) + r.Equal(feeDelta, fc.Fee) - r.NoError(fc.RemoveFeesFor(units)) + feeDelta4, err := fc.RemoveFeesFor(units) + r.NoError(err) r.Zero(fc.FeeManager.GetCumulatedUnits()) + r.Equal(feeDelta, feeDelta4) r.Zero(fc.Fee) } diff --git a/vms/platformvm/utxo/handler.go b/vms/platformvm/utxo/handler.go index b35c025d66b0..c2179f921ad3 100644 --- a/vms/platformvm/utxo/handler.go +++ b/vms/platformvm/utxo/handler.go @@ -504,10 +504,11 @@ func (h *handler) FinanceTx( if err != nil { return nil, nil, nil, nil, fmt.Errorf("failed calculating input size: %w", err) } - if err := feeCalc.AddFeesFor(insDimensions); err != nil { + addedFees, err := feeCalc.AddFeesFor(insDimensions) + if err != nil { return nil, nil, nil, nil, fmt.Errorf("account for input fees: %w", err) } - targetFee += feeCalc.Fee + targetFee += addedFees // Stake any value that should be staked amountToStake := math.Min( @@ -536,10 +537,11 @@ func (h *handler) FinanceTx( if err != nil { return nil, nil, nil, nil, fmt.Errorf("failed calculating stakedOut size: %w", err) } - if err := feeCalc.AddFeesFor(outDimensions); err != nil { + addedFees, err = feeCalc.AddFeesFor(outDimensions) + if err != nil { return nil, nil, nil, nil, fmt.Errorf("account for stakedOut fees: %w", err) } - targetFee += feeCalc.Fee + targetFee += addedFees // Add the output to the staked outputs stakedOuts = append(stakedOuts, stakedOut) @@ -563,10 +565,11 @@ func (h *handler) FinanceTx( if err != nil { return nil, nil, nil, nil, fmt.Errorf("failed calculating changeOut size: %w", err) } - if err := feeCalc.AddFeesFor(outDimensions); err != nil { + addedFees, err = feeCalc.AddFeesFor(outDimensions) + if err != nil { return nil, nil, nil, nil, fmt.Errorf("account for stakedOut fees: %w", err) } - targetFee += feeCalc.Fee + targetFee += addedFees returnedOuts = append(returnedOuts, changeOut) } @@ -627,10 +630,11 @@ func (h *handler) FinanceTx( if err != nil { return nil, nil, nil, nil, fmt.Errorf("failed calculating input size: %w", err) } - if err := feeCalc.AddFeesFor(insDimensions); err != nil { + addedFees, err := feeCalc.AddFeesFor(insDimensions) + if err != nil { return nil, nil, nil, nil, fmt.Errorf("account for input fees: %w", err) } - targetFee += feeCalc.Fee + targetFee += addedFees // Burn any value that should be burned amountToBurn := math.Min( @@ -670,10 +674,11 @@ func (h *handler) FinanceTx( if err != nil { return nil, nil, nil, nil, fmt.Errorf("failed calculating output size: %w", err) } - if err := feeCalc.AddFeesFor(outDimensions); err != nil { + addedFees, err := feeCalc.AddFeesFor(outDimensions) + if err != nil { return nil, nil, nil, nil, fmt.Errorf("account for output fees: %w", err) } - targetFee += feeCalc.Fee + targetFee += addedFees amountToBurn := math.Min( targetFee-amountBurned, // Amount we still need to burn @@ -703,14 +708,15 @@ func (h *handler) FinanceTx( if err != nil { return nil, nil, nil, nil, fmt.Errorf("failed calculating output size: %w", err) } - if err := feeCalc.AddFeesFor(outDimensions); err != nil { + addedFees, err := feeCalc.AddFeesFor(outDimensions) + if err != nil { return nil, nil, nil, nil, fmt.Errorf("account for output fees: %w", err) } - if remainingValue > feeCalc.Fee { - targetFee += feeCalc.Fee - amountBurned += feeCalc.Fee - remainingValue -= feeCalc.Fee + if remainingValue > addedFees { + targetFee += addedFees + amountBurned += addedFees + remainingValue -= addedFees changeOut.Out.(*secp256k1fx.TransferOutput).Amt = remainingValue // This input had extra value, so some of it must be returned diff --git a/vms/platformvm/utxo/handler_test.go b/vms/platformvm/utxo/handler_test.go index 91d9ee609fa3..cc9a30cb5b8c 100644 --- a/vms/platformvm/utxo/handler_test.go +++ b/vms/platformvm/utxo/handler_test.go @@ -177,7 +177,7 @@ func TestVerifyFinanceTx(t *testing.T) { uTxF func(t *testing.T) txs.UnsignedTx expectedErr error - checksF func(*testing.T, txs.UnsignedTx, *fees.Calculator, []*avax.TransferableInput, []*avax.TransferableOutput, []*avax.TransferableOutput) + checksF func(*testing.T, txs.UnsignedTx, []*avax.TransferableInput, []*avax.TransferableOutput, []*avax.TransferableOutput) }{ { description: "Tx, stake outputs, single locked UTXO and multiple UTXOs", @@ -232,8 +232,17 @@ func TestVerifyFinanceTx(t *testing.T) { return uTx }, expectedErr: nil, - checksF: func(t *testing.T, uTx txs.UnsignedTx, calc *fees.Calculator, ins []*avax.TransferableInput, outs, staked []*avax.TransferableOutput) { + checksF: func(t *testing.T, uTx txs.UnsignedTx, ins []*avax.TransferableInput, outs, staked []*avax.TransferableOutput) { r := require.New(t) + + fm := commonfees.NewManager(testUnitFees) + calc := &fees.Calculator{ + IsEForkActive: true, + FeeManager: fm, + ConsumedUnitsCap: testBlockMaxConsumedUnits, + Credentials: []verify.Verifiable{}, + } + expectedFee := 8911 * units.MicroAvax // complete uTx with the utxos @@ -304,8 +313,17 @@ func TestVerifyFinanceTx(t *testing.T) { return uTx }, expectedErr: nil, - checksF: func(t *testing.T, uTx txs.UnsignedTx, calc *fees.Calculator, ins []*avax.TransferableInput, outs, staked []*avax.TransferableOutput) { + checksF: func(t *testing.T, uTx txs.UnsignedTx, ins []*avax.TransferableInput, outs, staked []*avax.TransferableOutput) { r := require.New(t) + + fm := commonfees.NewManager(testUnitFees) + calc := &fees.Calculator{ + IsEForkActive: true, + FeeManager: fm, + ConsumedUnitsCap: testBlockMaxConsumedUnits, + Credentials: []verify.Verifiable{}, + } + expectedFee := 5999 * units.MicroAvax // complete uTx with the utxos @@ -378,8 +396,17 @@ func TestVerifyFinanceTx(t *testing.T) { return uTx }, expectedErr: nil, - checksF: func(t *testing.T, uTx txs.UnsignedTx, calc *fees.Calculator, ins []*avax.TransferableInput, outs, staked []*avax.TransferableOutput) { + checksF: func(t *testing.T, uTx txs.UnsignedTx, ins []*avax.TransferableInput, outs, staked []*avax.TransferableOutput) { r := require.New(t) + + fm := commonfees.NewManager(testUnitFees) + calc := &fees.Calculator{ + IsEForkActive: true, + FeeManager: fm, + ConsumedUnitsCap: testBlockMaxConsumedUnits, + Credentials: []verify.Verifiable{}, + } + expectedFee := 5879 * units.MicroAvax // complete uTx with the utxos @@ -447,8 +474,17 @@ func TestVerifyFinanceTx(t *testing.T) { return uTx }, expectedErr: nil, - checksF: func(t *testing.T, uTx txs.UnsignedTx, calc *fees.Calculator, ins []*avax.TransferableInput, outs, staked []*avax.TransferableOutput) { + checksF: func(t *testing.T, uTx txs.UnsignedTx, ins []*avax.TransferableInput, outs, staked []*avax.TransferableOutput) { r := require.New(t) + + fm := commonfees.NewManager(testUnitFees) + calc := &fees.Calculator{ + IsEForkActive: true, + FeeManager: fm, + ConsumedUnitsCap: testBlockMaxConsumedUnits, + Credentials: []verify.Verifiable{}, + } + expectedFee := 3341 * units.MicroAvax // complete uTx with the utxos @@ -507,8 +543,17 @@ func TestVerifyFinanceTx(t *testing.T) { return uTx }, expectedErr: nil, - checksF: func(t *testing.T, uTx txs.UnsignedTx, calc *fees.Calculator, ins []*avax.TransferableInput, outs, staked []*avax.TransferableOutput) { + checksF: func(t *testing.T, uTx txs.UnsignedTx, ins []*avax.TransferableInput, outs, staked []*avax.TransferableOutput) { r := require.New(t) + + fm := commonfees.NewManager(testUnitFees) + calc := &fees.Calculator{ + IsEForkActive: true, + FeeManager: fm, + ConsumedUnitsCap: testBlockMaxConsumedUnits, + Credentials: []verify.Verifiable{}, + } + expectedFee := 3014 * units.MicroAvax // complete uTx with the utxos @@ -568,8 +613,17 @@ func TestVerifyFinanceTx(t *testing.T) { return uTx }, expectedErr: nil, - checksF: func(t *testing.T, uTx txs.UnsignedTx, calc *fees.Calculator, ins []*avax.TransferableInput, outs, staked []*avax.TransferableOutput) { + checksF: func(t *testing.T, uTx txs.UnsignedTx, ins []*avax.TransferableInput, outs, staked []*avax.TransferableOutput) { r := require.New(t) + + fm := commonfees.NewManager(testUnitFees) + calc := &fees.Calculator{ + IsEForkActive: true, + FeeManager: fm, + ConsumedUnitsCap: testBlockMaxConsumedUnits, + Credentials: []verify.Verifiable{}, + } + expectedFee := 5552 * units.MicroAvax // complete uTx with the utxos @@ -607,9 +661,17 @@ func TestVerifyFinanceTx(t *testing.T) { return &unsignedTx }, expectedErr: nil, - checksF: func(t *testing.T, uTx txs.UnsignedTx, calc *fees.Calculator, ins []*avax.TransferableInput, outs, staked []*avax.TransferableOutput) { + checksF: func(t *testing.T, uTx txs.UnsignedTx, ins []*avax.TransferableInput, outs, staked []*avax.TransferableOutput) { r := require.New(t) + fm := commonfees.NewManager(testUnitFees) + calc := &fees.Calculator{ + IsEForkActive: true, + FeeManager: fm, + ConsumedUnitsCap: testBlockMaxConsumedUnits, + Credentials: []verify.Verifiable{}, + } + r.NoError(uTx.Visit(calc)) r.Zero(calc.Fee) @@ -646,7 +708,7 @@ func TestVerifyFinanceTx(t *testing.T) { ids.GenerateTestShortID(), ) r.ErrorIs(err, test.expectedErr) - test.checksF(t, uTx, feeCalc, ins, outs, staked) + test.checksF(t, uTx, ins, outs, staked) }) } } diff --git a/wallet/chain/p/builder_dynamic_fees.go b/wallet/chain/p/builder_dynamic_fees.go index cc24c4d1cbf0..f299aa06db79 100644 --- a/wallet/chain/p/builder_dynamic_fees.go +++ b/wallet/chain/p/builder_dynamic_fees.go @@ -170,10 +170,9 @@ func (b *DynamicFeesBuilder) NewAddSubnetValidatorTx( if err != nil { return nil, fmt.Errorf("failed calculating input size: %w", err) } - if err := feeCalc.AddFeesFor(credsDimensions); err != nil { + if _, err := feeCalc.AddFeesFor(credsDimensions); err != nil { return nil, fmt.Errorf("account for input fees: %w", err) } - toBurn[b.backend.AVAXAssetID()] += feeCalc.Fee // feesMan cumulates consumed units. Let's init it with utx filled so far if err := feeCalc.AddSubnetValidatorTx(utx); err != nil { @@ -230,10 +229,9 @@ func (b *DynamicFeesBuilder) NewRemoveSubnetValidatorTx( if err != nil { return nil, fmt.Errorf("failed calculating input size: %w", err) } - if err := feeCalc.AddFeesFor(credsDimensions); err != nil { + if _, err := feeCalc.AddFeesFor(credsDimensions); err != nil { return nil, fmt.Errorf("account for input fees: %w", err) } - toBurn[b.backend.AVAXAssetID()] += feeCalc.Fee // feesMan cumulates consumed units. Let's init it with utx filled so far if err := feeCalc.RemoveSubnetValidatorTx(utx); err != nil { @@ -347,10 +345,9 @@ func (b *DynamicFeesBuilder) NewCreateChainTx( if err != nil { return nil, fmt.Errorf("failed calculating input size: %w", err) } - if err := feeCalc.AddFeesFor(credsDimensions); err != nil { + if _, err := feeCalc.AddFeesFor(credsDimensions); err != nil { return nil, fmt.Errorf("account for input fees: %w", err) } - toBurn[b.backend.AVAXAssetID()] += feeCalc.Fee // feesMan cumulates consumed units. Let's init it with utx filled so far if err = feeCalc.CreateChainTx(uTx); err != nil { @@ -534,10 +531,9 @@ func (b *DynamicFeesBuilder) NewTransformSubnetTx( if err != nil { return nil, fmt.Errorf("failed calculating input size: %w", err) } - if err := feeCalc.AddFeesFor(credsDimensions); err != nil { + if _, err := feeCalc.AddFeesFor(credsDimensions); err != nil { return nil, fmt.Errorf("account for input fees: %w", err) } - toBurn[b.backend.AVAXAssetID()] += feeCalc.Fee // feesMan cumulates consumed units. Let's init it with utx filled so far if err := feeCalc.TransformSubnetTx(utx); err != nil { @@ -747,20 +743,22 @@ func (b *DynamicFeesBuilder) financeTx( if err != nil { return nil, nil, nil, fmt.Errorf("failed calculating input size: %w", err) } - if err := feeCalc.AddFeesFor(insDimensions); err != nil { + addedFees, err := feeCalc.AddFeesFor(insDimensions) + if err != nil { return nil, nil, nil, fmt.Errorf("account for input fees: %w", err) } - amountsToBurn[b.backend.AVAXAssetID()] += feeCalc.Fee + amountsToBurn[b.backend.AVAXAssetID()] += addedFees // update fees to account for the credentials to be added with inputs upon tx signing credsDimensions, err := commonfees.GetCredentialsDimensions(txs.Codec, txs.CodecVersion, inputSigIndices) if err != nil { return nil, nil, nil, fmt.Errorf("failed calculating input size: %w", err) } - if err := feeCalc.AddFeesFor(credsDimensions); err != nil { + addedFees, err = feeCalc.AddFeesFor(credsDimensions) + if err != nil { return nil, nil, nil, fmt.Errorf("account for input fees: %w", err) } - amountsToBurn[b.backend.AVAXAssetID()] += feeCalc.Fee + amountsToBurn[b.backend.AVAXAssetID()] += addedFees inputs = append(inputs, input) @@ -787,10 +785,11 @@ func (b *DynamicFeesBuilder) financeTx( if err != nil { return nil, nil, nil, fmt.Errorf("failed calculating stakedOut size: %w", err) } - if err := feeCalc.AddFeesFor(outDimensions); err != nil { + addedFees, err = feeCalc.AddFeesFor(outDimensions) + if err != nil { return nil, nil, nil, fmt.Errorf("account for stakedOut fees: %w", err) } - amountsToBurn[b.backend.AVAXAssetID()] += feeCalc.Fee + amountsToBurn[b.backend.AVAXAssetID()] += addedFees stakeOutputs = append(stakeOutputs, stakeOut) @@ -813,10 +812,11 @@ func (b *DynamicFeesBuilder) financeTx( if err != nil { return nil, nil, nil, fmt.Errorf("failed calculating changeOut size: %w", err) } - if err := feeCalc.AddFeesFor(outDimensions); err != nil { + addedFees, err := feeCalc.AddFeesFor(outDimensions) + if err != nil { return nil, nil, nil, fmt.Errorf("account for stakedOut fees: %w", err) } - amountsToBurn[b.backend.AVAXAssetID()] += feeCalc.Fee + amountsToBurn[b.backend.AVAXAssetID()] += addedFees changeOutputs = append(changeOutputs, changeOut) } @@ -869,20 +869,22 @@ func (b *DynamicFeesBuilder) financeTx( if err != nil { return nil, nil, nil, fmt.Errorf("failed calculating input size: %w", err) } - if err := feeCalc.AddFeesFor(insDimensions); err != nil { + addedFees, err := feeCalc.AddFeesFor(insDimensions) + if err != nil { return nil, nil, nil, fmt.Errorf("account for input fees: %w", err) } - amountsToBurn[b.backend.AVAXAssetID()] += feeCalc.Fee + amountsToBurn[b.backend.AVAXAssetID()] += addedFees // update fees to account for the credentials to be added with inputs upon tx signing credsDimensions, err := commonfees.GetCredentialsDimensions(txs.Codec, txs.CodecVersion, inputSigIndices) if err != nil { return nil, nil, nil, fmt.Errorf("failed calculating input size: %w", err) } - if err := feeCalc.AddFeesFor(credsDimensions); err != nil { + addedFees, err = feeCalc.AddFeesFor(credsDimensions) + if err != nil { return nil, nil, nil, fmt.Errorf("account for input fees: %w", err) } - amountsToBurn[b.backend.AVAXAssetID()] += feeCalc.Fee + amountsToBurn[b.backend.AVAXAssetID()] += addedFees inputs = append(inputs, input) @@ -917,10 +919,11 @@ func (b *DynamicFeesBuilder) financeTx( if err != nil { return nil, nil, nil, fmt.Errorf("failed calculating stakedOut size: %w", err) } - if err := feeCalc.AddFeesFor(outDimensions); err != nil { + addedFees, err := feeCalc.AddFeesFor(outDimensions) + if err != nil { return nil, nil, nil, fmt.Errorf("account for stakedOut fees: %w", err) } - amountsToBurn[b.backend.AVAXAssetID()] += feeCalc.Fee + amountsToBurn[b.backend.AVAXAssetID()] += addedFees } if remainingAmount := amountAvalibleToStake - amountToStake; remainingAmount > 0 { @@ -937,23 +940,24 @@ func (b *DynamicFeesBuilder) financeTx( if err != nil { return nil, nil, nil, fmt.Errorf("failed calculating changeOut size: %w", err) } - if err := feeCalc.AddFeesFor(outDimensions); err != nil { + addedFees, err := feeCalc.AddFeesFor(outDimensions) + if err != nil { return nil, nil, nil, fmt.Errorf("account for stakedOut fees: %w", err) } switch { - case feeCalc.Fee < remainingAmount: + case addedFees < remainingAmount: if assetID == b.backend.AVAXAssetID() { - changeOut.Out.(*secp256k1fx.TransferOutput).Amt = remainingAmount - feeCalc.Fee + changeOut.Out.(*secp256k1fx.TransferOutput).Amt = remainingAmount - addedFees } else { changeOut.Out.(*secp256k1fx.TransferOutput).Amt = remainingAmount - amountsToBurn[b.backend.AVAXAssetID()] += feeCalc.Fee + amountsToBurn[b.backend.AVAXAssetID()] += addedFees } changeOutputs = append(changeOutputs, changeOut) - case feeCalc.Fee == remainingAmount: + case addedFees == remainingAmount: // fees wholly consume remaining amount. We don't add the change - case feeCalc.Fee > remainingAmount: - amountsToBurn[b.backend.AVAXAssetID()] += feeCalc.Fee - remainingAmount + case addedFees > remainingAmount: + amountsToBurn[b.backend.AVAXAssetID()] += addedFees - remainingAmount } } } From 226e8db94ab5be8a0e1f046d15f0badc9e6e702b Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Fri, 26 Jan 2024 10:47:44 +0100 Subject: [PATCH 071/190] added ImportTx to dynamic fees builder --- wallet/chain/p/builder_dynamic_fees.go | 178 ++++++++++++++++++++ wallet/chain/p/builder_dynamic_fees_test.go | 73 ++++++++ 2 files changed, 251 insertions(+) diff --git a/wallet/chain/p/builder_dynamic_fees.go b/wallet/chain/p/builder_dynamic_fees.go index f299aa06db79..3f722a417bdb 100644 --- a/wallet/chain/p/builder_dynamic_fees.go +++ b/wallet/chain/p/builder_dynamic_fees.go @@ -409,6 +409,184 @@ func (b *DynamicFeesBuilder) NewCreateSubnetTx( return utx, b.initCtx(utx) } +func (b *DynamicFeesBuilder) NewImportTx( + sourceChainID ids.ID, + to *secp256k1fx.OutputOwners, + unitFees, unitCaps commonfees.Dimensions, + options ...common.Option, +) (*txs.ImportTx, error) { + ops := common.NewOptions(options) + // 1. Build core transaction + utx := &txs.ImportTx{ + BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ + NetworkID: b.backend.NetworkID(), + BlockchainID: constants.PlatformChainID, + Memo: ops.Memo(), + }}, + SourceChain: sourceChainID, + } + + // 2. Add imported inputs first + utxos, err := b.backend.UTXOs(ops.Context(), sourceChainID) + if err != nil { + return nil, err + } + + var ( + addrs = ops.Addresses(b.addrs) + minIssuanceTime = ops.MinIssuanceTime() + avaxAssetID = b.backend.AVAXAssetID() + + importedInputs = make([]*avax.TransferableInput, 0, len(utxos)) + importedSigIndices = make([][]uint32, 0) + importedAmounts = make(map[ids.ID]uint64) + ) + + for _, utxo := range utxos { + out, ok := utxo.Out.(*secp256k1fx.TransferOutput) + if !ok { + continue + } + + inputSigIndices, ok := common.MatchOwners(&out.OutputOwners, addrs, minIssuanceTime) + if !ok { + // We couldn't spend this UTXO, so we skip to the next one + continue + } + + importedInputs = append(importedInputs, &avax.TransferableInput{ + UTXOID: utxo.UTXOID, + Asset: utxo.Asset, + In: &secp256k1fx.TransferInput{ + Amt: out.Amt, + Input: secp256k1fx.Input{ + SigIndices: inputSigIndices, + }, + }, + }) + + assetID := utxo.AssetID() + newImportedAmount, err := math.Add64(importedAmounts[assetID], out.Amt) + if err != nil { + return nil, err + } + importedAmounts[assetID] = newImportedAmount + importedSigIndices = append(importedSigIndices, inputSigIndices) + } + if len(importedInputs) == 0 { + return nil, fmt.Errorf( + "%w: no UTXOs available to import", + errInsufficientFunds, + ) + } + + utils.Sort(importedInputs) // sort imported inputs + utx.ImportedInputs = importedInputs + + // 3. Add an output for all non-avax denominated inputs. + for assetID, amount := range importedAmounts { + if assetID == avaxAssetID { + // Avax-denominated inputs may be used to fully or partially pay fees, + // so we'll handle them later on. + continue + } + + utx.Outs = append(utx.Outs, &avax.TransferableOutput{ + Asset: avax.Asset{ID: assetID}, + Out: &secp256k1fx.TransferOutput{ + Amt: amount, + OutputOwners: *to, + }, + }) // we'll sort them later on + } + + // 3. Finance fees as much as possible with imported, Avax-denominated UTXOs + feesMan := commonfees.NewManager(unitFees) + feeCalc := &fees.Calculator{ + IsEForkActive: true, + FeeManager: feesMan, + ConsumedUnitsCap: unitCaps, + } + + // feesMan cumulates consumed units. Let's init it with utx filled so far + if err := feeCalc.ImportTx(utx); err != nil { + return nil, err + } + + for _, sigIndices := range importedSigIndices { + // update fees to account for the credentials to be added with inputs upon tx signing + credsDimensions, err := commonfees.GetCredentialsDimensions(txs.Codec, txs.CodecVersion, sigIndices) + if err != nil { + return nil, fmt.Errorf("failed calculating input size: %w", err) + } + if _, err := feeCalc.AddFeesFor(credsDimensions); err != nil { + return nil, fmt.Errorf("account for input fees: %w", err) + } + } + + switch importedAVAX := importedAmounts[avaxAssetID]; { + case importedAVAX == feeCalc.Fee: + // imported inputs match exactly the fees to be paid + avax.SortTransferableOutputs(utx.Outs, txs.Codec) // sort imported outputs + return utx, b.initCtx(utx) + + case importedAVAX < feeCalc.Fee: + // imported inputs can partially pay fees + feeCalc.Fee -= importedAmounts[avaxAssetID] + + default: + // imported inputs may be enough to pay taxes by themselves + changeOut := &avax.TransferableOutput{ + Asset: avax.Asset{ID: avaxAssetID}, + Out: &secp256k1fx.TransferOutput{ + OutputOwners: *to, // we set amount after considering own fees + }, + } + + // update fees to target given the extra output added + outDimensions, err := commonfees.GetOutputsDimensions(txs.Codec, txs.CodecVersion, []*avax.TransferableOutput{changeOut}) + if err != nil { + return nil, fmt.Errorf("failed calculating output size: %w", err) + } + if _, err := feeCalc.AddFeesFor(outDimensions); err != nil { + return nil, fmt.Errorf("account for output fees: %w", err) + } + + switch { + case feeCalc.Fee < importedAVAX: + changeOut.Out.(*secp256k1fx.TransferOutput).Amt = importedAVAX - feeCalc.Fee + utx.Outs = append(utx.Outs, changeOut) + avax.SortTransferableOutputs(utx.Outs, txs.Codec) // sort imported outputs + return utx, b.initCtx(utx) + + case feeCalc.Fee == importedAVAX: + // imported fees pays exactly the tx cost. We don't include the outputs + avax.SortTransferableOutputs(utx.Outs, txs.Codec) // sort imported outputs + return utx, b.initCtx(utx) + + default: + // imported avax are not enough to pay fees + // Drop the changeOut and finance the tx + if _, err := feeCalc.RemoveFeesFor(outDimensions); err != nil { + return nil, fmt.Errorf("failed reverting change output: %w", err) + } + feeCalc.Fee -= importedAVAX + } + } + + toStake := map[ids.ID]uint64{} + toBurn := map[ids.ID]uint64{} + inputs, changeOuts, _, err := b.financeTx(toBurn, toStake, feeCalc, ops) + if err != nil { + return nil, err + } + + utx.Ins = inputs + utx.Outs = append(utx.Outs, changeOuts...) + avax.SortTransferableOutputs(utx.Outs, txs.Codec) // sort imported outputs + return utx, b.initCtx(utx) +} + func (b *DynamicFeesBuilder) NewExportTx( chainID ids.ID, outputs []*avax.TransferableOutput, diff --git a/wallet/chain/p/builder_dynamic_fees_test.go b/wallet/chain/p/builder_dynamic_fees_test.go index 752ba8f580a1..2ed94f1efa9b 100644 --- a/wallet/chain/p/builder_dynamic_fees_test.go +++ b/wallet/chain/p/builder_dynamic_fees_test.go @@ -549,6 +549,79 @@ func TestCreateSubnetTx(t *testing.T) { require.Equal(fc.Fee, ins[0].In.Amount()+ins[1].In.Amount()-outs[0].Out.Amount()) } +func TestImportTx(t *testing.T) { + require := require.New(t) + ctrl := gomock.NewController(t) + + be := mocks.NewMockBuilderBackend(ctrl) + + var ( + utxosKey = testKeys[1] + utxoAddr = utxosKey.PublicKey().Address() + sourceChainID = ids.GenerateTestID() + utxos, avaxAssetID, _ = testUTXOsList(utxosKey) + + importKey = testKeys[0] + importTo = &secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{ + importKey.Address(), + }, + } + ) + + importedUtxo := utxos[0] + utxos = utxos[1:] + + b := &DynamicFeesBuilder{ + addrs: set.Of(utxoAddr), + backend: be, + } + be.EXPECT().AVAXAssetID().Return(avaxAssetID).AnyTimes() + be.EXPECT().NetworkID().Return(constants.MainnetID).AnyTimes() + be.EXPECT().UTXOs(gomock.Any(), sourceChainID).Return([]*avax.UTXO{importedUtxo}, nil) + be.EXPECT().UTXOs(gomock.Any(), constants.PlatformChainID).Return(utxos, nil) + + utx, err := b.NewImportTx( + sourceChainID, + importTo, + testUnitFees, + testBlockMaxConsumedUnits, + ) + require.NoError(err) + + var ( + kc = secp256k1fx.NewKeychain(utxosKey) + sbe = mocks.NewMockSignerBackend(ctrl) + s = NewSigner(kc, sbe) + ) + + sbe.EXPECT().GetUTXO(gomock.Any(), gomock.Any(), importedUtxo.InputID()).Return(importedUtxo, nil).AnyTimes() + for _, utxo := range utxos { + sbe.EXPECT().GetUTXO(gomock.Any(), gomock.Any(), utxo.InputID()).Return(utxo, nil).AnyTimes() + } + + tx, err := s.SignUnsigned(stdcontext.Background(), utx) + require.NoError(err) + + fc := &fees.Calculator{ + IsEForkActive: true, + FeeManager: commonfees.NewManager(testUnitFees), + ConsumedUnitsCap: testBlockMaxConsumedUnits, + Credentials: tx.Creds, + } + require.NoError(utx.Visit(fc)) + require.Equal(5640*units.MicroAvax, fc.Fee) + + ins := utx.Ins + outs := utx.Outs + importedIns := utx.ImportedInputs + require.Len(ins, 1) + require.Len(importedIns, 1) + require.Len(outs, 1) + require.Equal(fc.Fee, importedIns[0].In.Amount()+ins[0].In.Amount()-outs[0].Out.Amount()) +} + func TestExportTx(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) From c5f083bafeb0b1eff49494483f1f079b220720b9 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Fri, 26 Jan 2024 12:50:22 +0100 Subject: [PATCH 072/190] integrated dynamic fees builder into wallet --- wallet/chain/p/wallet.go | 368 ++++++++++++++++++++++++++++++++++----- 1 file changed, 327 insertions(+), 41 deletions(-) diff --git a/wallet/chain/p/wallet.go b/wallet/chain/p/wallet.go index e982a204a9f8..aa8cfed3f899 100644 --- a/wallet/chain/p/wallet.go +++ b/wallet/chain/p/wallet.go @@ -9,7 +9,9 @@ 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/components/fees" "github.com/ava-labs/avalanchego/vms/platformvm" "github.com/ava-labs/avalanchego/vms/platformvm/signer" "github.com/ava-labs/avalanchego/vms/platformvm/status" @@ -261,9 +263,13 @@ func NewWallet( type wallet struct { Backend - builder Builder - signer Signer - client platformvm.Client + signer Signer + client platformvm.Client + + isEForkActive bool + builder Builder + dynamicBuilder DynamicFeesBuilder + unitFees, unitCaps fees.Dimensions } func (w *wallet) Builder() Builder { @@ -278,10 +284,27 @@ func (w *wallet) IssueBaseTx( outputs []*avax.TransferableOutput, options ...common.Option, ) (*txs.Tx, error) { - utx, err := w.builder.NewBaseTx(outputs, options...) + if err := w.refreshFork(options...); err != nil { + return nil, err + } + + var ( + utx txs.UnsignedTx + err error + ) + if w.isEForkActive { + if err := w.refreshFeesData(options...); err != nil { + return nil, err + } + + utx, err = w.dynamicBuilder.NewBaseTx(outputs, w.unitFees, w.unitCaps, options...) + } else { + utx, err = w.builder.NewBaseTx(outputs, options...) + } if err != nil { return nil, err } + return w.IssueUnsignedTx(utx, options...) } @@ -291,10 +314,27 @@ func (w *wallet) IssueAddValidatorTx( shares uint32, options ...common.Option, ) (*txs.Tx, error) { - utx, err := w.builder.NewAddValidatorTx(vdr, rewardsOwner, shares, options...) + if err := w.refreshFork(options...); err != nil { + return nil, err + } + + var ( + utx txs.UnsignedTx + err error + ) + if w.isEForkActive { + if err := w.refreshFeesData(options...); err != nil { + return nil, err + } + + utx, err = w.dynamicBuilder.NewAddValidatorTx(vdr, rewardsOwner, shares, w.unitFees, w.unitCaps, options...) + } else { + utx, err = w.builder.NewAddValidatorTx(vdr, rewardsOwner, shares, options...) + } if err != nil { return nil, err } + return w.IssueUnsignedTx(utx, options...) } @@ -302,10 +342,27 @@ func (w *wallet) IssueAddSubnetValidatorTx( vdr *txs.SubnetValidator, options ...common.Option, ) (*txs.Tx, error) { - utx, err := w.builder.NewAddSubnetValidatorTx(vdr, options...) + if err := w.refreshFork(options...); err != nil { + return nil, err + } + + var ( + utx txs.UnsignedTx + err error + ) + if w.isEForkActive { + if err := w.refreshFeesData(options...); err != nil { + return nil, err + } + + utx, err = w.dynamicBuilder.NewAddSubnetValidatorTx(vdr, w.unitFees, w.unitCaps, options...) + } else { + utx, err = w.builder.NewAddSubnetValidatorTx(vdr, options...) + } if err != nil { return nil, err } + return w.IssueUnsignedTx(utx, options...) } @@ -314,10 +371,27 @@ func (w *wallet) IssueRemoveSubnetValidatorTx( subnetID ids.ID, options ...common.Option, ) (*txs.Tx, error) { - utx, err := w.builder.NewRemoveSubnetValidatorTx(nodeID, subnetID, options...) + if err := w.refreshFork(options...); err != nil { + return nil, err + } + + var ( + utx txs.UnsignedTx + err error + ) + if w.isEForkActive { + if err := w.refreshFeesData(options...); err != nil { + return nil, err + } + + utx, err = w.dynamicBuilder.NewRemoveSubnetValidatorTx(nodeID, subnetID, w.unitFees, w.unitCaps, options...) + } else { + utx, err = w.builder.NewRemoveSubnetValidatorTx(nodeID, subnetID, options...) + } if err != nil { return nil, err } + return w.IssueUnsignedTx(utx, options...) } @@ -326,10 +400,27 @@ func (w *wallet) IssueAddDelegatorTx( rewardsOwner *secp256k1fx.OutputOwners, options ...common.Option, ) (*txs.Tx, error) { - utx, err := w.builder.NewAddDelegatorTx(vdr, rewardsOwner, options...) + if err := w.refreshFork(options...); err != nil { + return nil, err + } + + var ( + utx txs.UnsignedTx + err error + ) + if w.isEForkActive { + if err := w.refreshFeesData(options...); err != nil { + return nil, err + } + + utx, err = w.dynamicBuilder.NewAddDelegatorTx(vdr, rewardsOwner, w.unitFees, w.unitCaps, options...) + } else { + utx, err = w.builder.NewAddDelegatorTx(vdr, rewardsOwner, options...) + } if err != nil { return nil, err } + return w.IssueUnsignedTx(utx, options...) } @@ -341,10 +432,27 @@ func (w *wallet) IssueCreateChainTx( chainName string, options ...common.Option, ) (*txs.Tx, error) { - utx, err := w.builder.NewCreateChainTx(subnetID, genesis, vmID, fxIDs, chainName, options...) + if err := w.refreshFork(options...); err != nil { + return nil, err + } + + var ( + utx txs.UnsignedTx + err error + ) + if w.isEForkActive { + if err := w.refreshFeesData(options...); err != nil { + return nil, err + } + + utx, err = w.dynamicBuilder.NewCreateChainTx(subnetID, genesis, vmID, fxIDs, chainName, w.unitFees, w.unitCaps, options...) + } else { + utx, err = w.builder.NewCreateChainTx(subnetID, genesis, vmID, fxIDs, chainName, options...) + } if err != nil { return nil, err } + return w.IssueUnsignedTx(utx, options...) } @@ -352,10 +460,27 @@ func (w *wallet) IssueCreateSubnetTx( owner *secp256k1fx.OutputOwners, options ...common.Option, ) (*txs.Tx, error) { - utx, err := w.builder.NewCreateSubnetTx(owner, options...) + if err := w.refreshFork(options...); err != nil { + return nil, err + } + + var ( + utx txs.UnsignedTx + err error + ) + if w.isEForkActive { + if err := w.refreshFeesData(options...); err != nil { + return nil, err + } + + utx, err = w.dynamicBuilder.NewCreateSubnetTx(owner, w.unitFees, w.unitCaps, options...) + } else { + utx, err = w.builder.NewCreateSubnetTx(owner, options...) + } if err != nil { return nil, err } + return w.IssueUnsignedTx(utx, options...) } @@ -364,10 +489,27 @@ func (w *wallet) IssueImportTx( to *secp256k1fx.OutputOwners, options ...common.Option, ) (*txs.Tx, error) { - utx, err := w.builder.NewImportTx(sourceChainID, to, options...) + if err := w.refreshFork(options...); err != nil { + return nil, err + } + + var ( + utx txs.UnsignedTx + err error + ) + if w.isEForkActive { + if err := w.refreshFeesData(options...); err != nil { + return nil, err + } + + utx, err = w.dynamicBuilder.NewImportTx(sourceChainID, to, w.unitFees, w.unitCaps, options...) + } else { + utx, err = w.builder.NewImportTx(sourceChainID, to, options...) + } if err != nil { return nil, err } + return w.IssueUnsignedTx(utx, options...) } @@ -376,10 +518,27 @@ func (w *wallet) IssueExportTx( outputs []*avax.TransferableOutput, options ...common.Option, ) (*txs.Tx, error) { - utx, err := w.builder.NewExportTx(chainID, outputs, options...) + if err := w.refreshFork(options...); err != nil { + return nil, err + } + + var ( + utx txs.UnsignedTx + err error + ) + if w.isEForkActive { + if err := w.refreshFeesData(options...); err != nil { + return nil, err + } + + utx, err = w.dynamicBuilder.NewExportTx(chainID, outputs, w.unitFees, w.unitCaps, options...) + } else { + utx, err = w.builder.NewExportTx(chainID, outputs, options...) + } if err != nil { return nil, err } + return w.IssueUnsignedTx(utx, options...) } @@ -400,26 +559,61 @@ func (w *wallet) IssueTransformSubnetTx( uptimeRequirement uint32, options ...common.Option, ) (*txs.Tx, error) { - utx, err := w.builder.NewTransformSubnetTx( - subnetID, - assetID, - initialSupply, - maxSupply, - minConsumptionRate, - maxConsumptionRate, - minValidatorStake, - maxValidatorStake, - minStakeDuration, - maxStakeDuration, - minDelegationFee, - minDelegatorStake, - maxValidatorWeightFactor, - uptimeRequirement, - options..., + if err := w.refreshFork(options...); err != nil { + return nil, err + } + + var ( + utx txs.UnsignedTx + err error ) + if w.isEForkActive { + if err := w.refreshFeesData(options...); err != nil { + return nil, err + } + + utx, err = w.dynamicBuilder.NewTransformSubnetTx( + subnetID, + assetID, + initialSupply, + maxSupply, + minConsumptionRate, + maxConsumptionRate, + minValidatorStake, + maxValidatorStake, + minStakeDuration, + maxStakeDuration, + minDelegationFee, + minDelegatorStake, + maxValidatorWeightFactor, + uptimeRequirement, + w.unitFees, + w.unitCaps, + options..., + ) + } else { + utx, err = w.builder.NewTransformSubnetTx( + subnetID, + assetID, + initialSupply, + maxSupply, + minConsumptionRate, + maxConsumptionRate, + minValidatorStake, + maxValidatorStake, + minStakeDuration, + maxStakeDuration, + minDelegationFee, + minDelegatorStake, + maxValidatorWeightFactor, + uptimeRequirement, + options..., + ) + } if err != nil { return nil, err } + return w.IssueUnsignedTx(utx, options...) } @@ -432,18 +626,45 @@ func (w *wallet) IssueAddPermissionlessValidatorTx( shares uint32, options ...common.Option, ) (*txs.Tx, error) { - utx, err := w.builder.NewAddPermissionlessValidatorTx( - vdr, - signer, - assetID, - validationRewardsOwner, - delegationRewardsOwner, - shares, - options..., + if err := w.refreshFork(options...); err != nil { + return nil, err + } + + var ( + utx txs.UnsignedTx + err error ) + if w.isEForkActive { + if err := w.refreshFeesData(options...); err != nil { + return nil, err + } + + utx, err = w.dynamicBuilder.NewAddPermissionlessValidatorTx( + vdr, + signer, + assetID, + validationRewardsOwner, + delegationRewardsOwner, + shares, + w.unitFees, + w.unitCaps, + options..., + ) + } else { + utx, err = w.builder.NewAddPermissionlessValidatorTx( + vdr, + signer, + assetID, + validationRewardsOwner, + delegationRewardsOwner, + shares, + options..., + ) + } if err != nil { return nil, err } + return w.IssueUnsignedTx(utx, options...) } @@ -453,15 +674,39 @@ func (w *wallet) IssueAddPermissionlessDelegatorTx( rewardsOwner *secp256k1fx.OutputOwners, options ...common.Option, ) (*txs.Tx, error) { - utx, err := w.builder.NewAddPermissionlessDelegatorTx( - vdr, - assetID, - rewardsOwner, - options..., + if err := w.refreshFork(options...); err != nil { + return nil, err + } + + var ( + utx txs.UnsignedTx + err error ) + if w.isEForkActive { + if err := w.refreshFeesData(options...); err != nil { + return nil, err + } + + utx, err = w.dynamicBuilder.NewAddPermissionlessDelegatorTx( + vdr, + assetID, + rewardsOwner, + w.unitFees, + w.unitCaps, + options..., + ) + } else { + utx, err = w.builder.NewAddPermissionlessDelegatorTx( + vdr, + assetID, + rewardsOwner, + options..., + ) + } if err != nil { return nil, err } + return w.IssueUnsignedTx(utx, options...) } @@ -512,3 +757,44 @@ func (w *wallet) IssueTx( } return nil } + +func (w *wallet) refreshFork(options ...common.Option) error { + if w.isEForkActive { + // E fork enables dinamic fees and it is active + // not need to recheck + return nil + } + + var ( + ops = common.NewOptions(options) + ctx = ops.Context() + eForkTime = version.GetEForkTime(w.NetworkID()) + ) + + chainTime, err := w.client.GetTimestamp(ctx) + if err != nil { + return err + } + + w.isEForkActive = !chainTime.Before(eForkTime) + return nil +} + +func (w *wallet) refreshFeesData(options ...common.Option) error { + var ( + ops = common.NewOptions(options) + ctx = ops.Context() + err error + ) + + w.unitFees, err = w.client.GetUnitFees(ctx) + if err != nil { + return err + } + + w.unitCaps, err = w.client.GetBlockUnitsCap(ctx) + if err != nil { + return err + } + return nil +} From 0d90f0faa0ac2e0712713039b989bff9cd490036 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Fri, 26 Jan 2024 13:24:39 +0100 Subject: [PATCH 073/190] enabled E fork in testnet + minor fixes --- version/constants.go | 3 +-- vms/platformvm/client.go | 2 +- vms/platformvm/state/state.go | 4 ++++ vms/platformvm/txs/fees/calculator.go | 11 +++++++---- wallet/chain/p/builder_dynamic_fees.go | 7 +++++++ wallet/chain/p/wallet.go | 12 +++++++----- wallet/subnet/primary/wallet.go | 3 ++- 7 files changed, 29 insertions(+), 13 deletions(-) diff --git a/version/constants.go b/version/constants.go index 618fe994a76e..a140465335c0 100644 --- a/version/constants.go +++ b/version/constants.go @@ -115,7 +115,6 @@ var ( constants.MainnetID: time.Date(10000, time.December, 1, 0, 0, 0, 0, time.UTC), constants.FujiID: time.Date(10000, time.December, 1, 0, 0, 0, 0, time.UTC), } - TempForkTime = time.Date(10000, time.December, 1, 0, 0, 0, 0, time.UTC) ) func init() { @@ -215,7 +214,7 @@ func GetEForkTime(networkID uint32) time.Time { if upgradeTime, exists := EForkTimes[networkID]; exists { return upgradeTime } - return TempForkTime + return DefaultUpgradeTime } func GetCompatibility(networkID uint32) Compatibility { diff --git a/vms/platformvm/client.go b/vms/platformvm/client.go index ab92a9f97002..1bccc9382139 100644 --- a/vms/platformvm/client.go +++ b/vms/platformvm/client.go @@ -907,6 +907,6 @@ func (c *client) GetUnitFees(ctx context.Context, options ...rpc.Option) (common func (c *client) GetBlockUnitsCap(ctx context.Context, options ...rpc.Option) (commonfees.Dimensions, error) { res := &GetBlockUnitsCapReply{} - err := c.requester.SendRequest(ctx, "platform.GetBlockUnitsCapReply", struct{}{}, res, options...) + err := c.requester.SendRequest(ctx, "platform.getBlockUnitsCap", struct{}{}, res, options...) return res.MaxUnits, err } diff --git a/vms/platformvm/state/state.go b/vms/platformvm/state/state.go index d8fe7b885620..cd90b746a08a 100644 --- a/vms/platformvm/state/state.go +++ b/vms/platformvm/state/state.go @@ -44,6 +44,7 @@ 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/fees" safemath "github.com/ava-labs/avalanchego/utils/math" commonfees "github.com/ava-labs/avalanchego/vms/components/fees" @@ -718,6 +719,9 @@ func newState( chainDBCache: chainDBCache, singletonDB: prefixdb.New(singletonPrefix, baseDB), + + unitFees: fees.DefaultUnitFees, + blockUnitCaps: fees.DefaultBlockMaxConsumedUnits, }, nil } diff --git a/vms/platformvm/txs/fees/calculator.go b/vms/platformvm/txs/fees/calculator.go index c64e7f3f6de1..2db218df6333 100644 --- a/vms/platformvm/txs/fees/calculator.go +++ b/vms/platformvm/txs/fees/calculator.go @@ -6,6 +6,7 @@ package fees import ( "errors" "fmt" + "math" "time" "github.com/ava-labs/avalanchego/utils/constants" @@ -23,6 +24,7 @@ var ( EmptyUnitCaps = fees.Dimensions{} // helps avoiding reading unit fees from db for some pre E fork processing // These are the default unit fees, used upon E-fork activation + // TODO ABENEGIA: to be tuned DefaultUnitFees = fees.Dimensions{ 1, 2, @@ -31,11 +33,12 @@ var ( } // These are the default caps for units consumed in a block, used upon E-fork activation + // TODO ABENEGIA: to be tuned DefaultBlockMaxConsumedUnits = fees.Dimensions{ - 1, - 2, - 3, - 4, + math.MaxUint64, + math.MaxUint64, + math.MaxUint64, + math.MaxUint64, } errFailedFeeCalculation = errors.New("failed fee calculation") diff --git a/wallet/chain/p/builder_dynamic_fees.go b/wallet/chain/p/builder_dynamic_fees.go index 3f722a417bdb..fcc615c02655 100644 --- a/wallet/chain/p/builder_dynamic_fees.go +++ b/wallet/chain/p/builder_dynamic_fees.go @@ -28,6 +28,13 @@ type DynamicFeesBuilder struct { backend BuilderBackend } +func NewDynamicFeesBuilder(addrs set.Set[ids.ShortID], backend BuilderBackend) *DynamicFeesBuilder { + return &DynamicFeesBuilder{ + addrs: addrs, + backend: backend, + } +} + func (b *DynamicFeesBuilder) NewBaseTx( outputs []*avax.TransferableOutput, unitFees, unitCaps commonfees.Dimensions, diff --git a/wallet/chain/p/wallet.go b/wallet/chain/p/wallet.go index aa8cfed3f899..a528d6ddad79 100644 --- a/wallet/chain/p/wallet.go +++ b/wallet/chain/p/wallet.go @@ -249,15 +249,17 @@ type Wallet interface { func NewWallet( builder Builder, + dynFeesBuilder *DynamicFeesBuilder, signer Signer, client platformvm.Client, backend Backend, ) Wallet { return &wallet{ - Backend: backend, - builder: builder, - signer: signer, - client: client, + Backend: backend, + builder: builder, + dynamicBuilder: dynFeesBuilder, + signer: signer, + client: client, } } @@ -268,7 +270,7 @@ type wallet struct { isEForkActive bool builder Builder - dynamicBuilder DynamicFeesBuilder + dynamicBuilder *DynamicFeesBuilder unitFees, unitCaps fees.Dimensions } diff --git a/wallet/subnet/primary/wallet.go b/wallet/subnet/primary/wallet.go index 3bb3e9965684..0825ab1b370f 100644 --- a/wallet/subnet/primary/wallet.go +++ b/wallet/subnet/primary/wallet.go @@ -119,6 +119,7 @@ func MakeWallet(ctx context.Context, config *WalletConfig) (Wallet, error) { pUTXOs := NewChainUTXOs(constants.PlatformChainID, avaxState.UTXOs) pBackend := p.NewBackend(avaxState.PCTX, pUTXOs, pChainTxs) pBuilder := p.NewBuilder(avaxAddrs, pBackend) + pDynamicFeesBuilder := p.NewDynamicFeesBuilder(avaxAddrs, pBackend) pSigner := p.NewSigner(config.AVAXKeychain, pBackend) xChainID := avaxState.XCTX.BlockchainID() @@ -134,7 +135,7 @@ func MakeWallet(ctx context.Context, config *WalletConfig) (Wallet, error) { cSigner := c.NewSigner(config.AVAXKeychain, config.EthKeychain, cBackend) return NewWallet( - p.NewWallet(pBuilder, pSigner, avaxState.PClient, pBackend), + p.NewWallet(pBuilder, pDynamicFeesBuilder, pSigner, avaxState.PClient, pBackend), x.NewWallet(xBuilder, xSigner, avaxState.XClient, xBackend), c.NewWallet(cBuilder, cSigner, avaxState.CClient, ethState.Client, cBackend), ), nil From d984b3be2b3332a1daa33c801e5822607b6a6910 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Fri, 26 Jan 2024 16:01:36 +0100 Subject: [PATCH 074/190] fixed merge --- vms/platformvm/txs/executor/standard_tx_executor_test.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/vms/platformvm/txs/executor/standard_tx_executor_test.go b/vms/platformvm/txs/executor/standard_tx_executor_test.go index 1dab25b27438..08f01c6ea592 100644 --- a/vms/platformvm/txs/executor/standard_tx_executor_test.go +++ b/vms/platformvm/txs/executor/standard_tx_executor_test.go @@ -1697,9 +1697,8 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { env := newValidRemoveSubnetValidatorTxVerifyEnv(t, ctrl) // Set dependency expectations. - env.state.EXPECT().GetTimestamp().Return(env.latestForkTime) + env.state.EXPECT().GetTimestamp().Return(env.latestForkTime).Times(2) env.state.EXPECT().GetCurrentValidator(env.unsignedTx.Subnet, env.unsignedTx.NodeID).Return(env.staker, nil).Times(1) - env.state.EXPECT().GetTimestamp().Return(time.Now()) subnetOwner := fx.NewMockOwner(ctrl) env.state.EXPECT().GetSubnetOwner(env.unsignedTx.Subnet).Return(subnetOwner, nil).Times(1) env.fx.EXPECT().VerifyPermission(env.unsignedTx, env.unsignedTx.SubnetAuth, env.tx.Creds[len(env.tx.Creds)-1], subnetOwner).Return(nil).Times(1) From 77e5779fbd2885f0567ee942e1aa0c90e7cde322 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Fri, 26 Jan 2024 16:15:05 +0100 Subject: [PATCH 075/190] fixed merge --- vms/platformvm/txs/executor/standard_tx_executor_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vms/platformvm/txs/executor/standard_tx_executor_test.go b/vms/platformvm/txs/executor/standard_tx_executor_test.go index 5ad61c4f93f5..098ffeae7aca 100644 --- a/vms/platformvm/txs/executor/standard_tx_executor_test.go +++ b/vms/platformvm/txs/executor/standard_tx_executor_test.go @@ -1738,7 +1738,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { env := newValidRemoveSubnetValidatorTxVerifyEnv(t, ctrl) // Set dependency expectations. - env.state.EXPECT().GetTimestamp().Return(env.latestForkTime).Times(2) + env.state.EXPECT().GetTimestamp().Return(env.latestForkTime) env.state.EXPECT().GetCurrentValidator(env.unsignedTx.Subnet, env.unsignedTx.NodeID).Return(env.staker, nil).Times(1) subnetOwner := fx.NewMockOwner(ctrl) env.state.EXPECT().GetSubnetOwner(env.unsignedTx.Subnet).Return(subnetOwner, nil).Times(1) From 5b35ad35ef6c6f4203fb694007386e7887a00b86 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Fri, 26 Jan 2024 19:23:25 +0100 Subject: [PATCH 076/190] leftover from previous merge --- vms/platformvm/block/executor/manager.go | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/vms/platformvm/block/executor/manager.go b/vms/platformvm/block/executor/manager.go index 27d35a7641ad..fe2cbdf10a44 100644 --- a/vms/platformvm/block/executor/manager.go +++ b/vms/platformvm/block/executor/manager.go @@ -9,6 +9,7 @@ import ( "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/snow/consensus/snowman" "github.com/ava-labs/avalanchego/utils/set" + "github.com/ava-labs/avalanchego/vms/components/fees" "github.com/ava-labs/avalanchego/vms/platformvm/block" "github.com/ava-labs/avalanchego/vms/platformvm/metrics" "github.com/ava-labs/avalanchego/vms/platformvm/state" @@ -142,10 +143,22 @@ func (m *manager) VerifyTx(tx *txs.Tx) error { return err } + unitFees, err := stateDiff.GetUnitFees() + if err != nil { + return err + } + + unitCaps, err := stateDiff.GetBlockUnitCaps() + if err != nil { + return err + } + err = tx.Unsigned.Visit(&executor.StandardTxExecutor{ - Backend: m.txExecutorBackend, - State: stateDiff, - Tx: tx, + Backend: m.txExecutorBackend, + BlkFeeManager: fees.NewManager(unitFees), + UnitCaps: unitCaps, + State: stateDiff, + Tx: tx, }) // We ignore [errFutureStakeTime] here because the time will be advanced // when this transaction is issued. From 7a2a673a67fcda778251ed418112dc1db7cadb26 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Fri, 26 Jan 2024 19:59:56 +0100 Subject: [PATCH 077/190] wip: fixing e2e tests --- tests/e2e/p/workflow.go | 42 +++++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/tests/e2e/p/workflow.go b/tests/e2e/p/workflow.go index 8bf7efca2c2c..41db55904e30 100644 --- a/tests/e2e/p/workflow.go +++ b/tests/e2e/p/workflow.go @@ -20,7 +20,10 @@ import ( "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/platformvm" "github.com/ava-labs/avalanchego/vms/platformvm/txs" + "github.com/ava-labs/avalanchego/vms/platformvm/txs/fees" "github.com/ava-labs/avalanchego/vms/secp256k1fx" + + commonfees "github.com/ava-labs/avalanchego/vms/components/fees" ) // PChainWorkflow is an integration test for normal P-Chain operations @@ -49,25 +52,18 @@ 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 X-chain tx fee {{/}}\n") infoClient := info.NewClient(nodeURI.URI) - fees, err := infoClient.GetTxFee(e2e.DefaultContext()) + XchainFees, err := infoClient.GetTxFee(e2e.DefaultContext()) require.NoError(err) - txFees := uint64(fees.TxFee) - tests.Outf("{{green}} txFee: %d {{/}}\n", txFees) + xChainTxFees := uint64(XchainFees.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. @@ -126,8 +122,15 @@ var _ = e2e.DescribePChain("[Workflow]", func() { OutputOwners: outputOwner, } + pChainExportFee := uint64(0) ginkgo.By("export avax from P to X chain", func() { - _, err := pWallet.IssueExportTx( + unitFees, err := pChainClient.GetUnitFees(e2e.DefaultContext()) + require.NoError(err) + + unitCaps, err := pChainClient.GetBlockUnitsCap(e2e.DefaultContext()) + require.NoError(err) + + tx, err := pWallet.IssueExportTx( xWallet.BlockchainID(), []*avax.TransferableOutput{ { @@ -140,6 +143,17 @@ var _ = e2e.DescribePChain("[Workflow]", func() { e2e.WithDefaultContext(), ) require.NoError(err) + + // retrieve fees paid for the tx + feeCalc := fees.Calculator{ + IsEForkActive: true, + FeeManager: commonfees.NewManager(unitFees), + ConsumedUnitsCap: unitCaps, + Credentials: tx.Creds, + } + + require.NoError(tx.Unsigned.Visit(&feeCalc)) + pChainExportFee = feeCalc.Fee }) // check balances post export @@ -154,7 +168,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( @@ -176,7 +190,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) }) }) From 9b32bb00e346acce9a10e72c283b6074b1799af9 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Fri, 26 Jan 2024 20:10:46 +0100 Subject: [PATCH 078/190] moved X-chain changes to different branch --- tests/e2e/p/workflow.go | 4 +- vms/avm/block/executor/block.go | 9 +- vms/avm/block/executor/manager.go | 8 +- vms/avm/config/config.go | 26 +- vms/avm/txs/executor/syntactic_verifier.go | 42 +- vms/avm/txs/fees/calculator.go | 125 +--- vms/avm/txs/fees/calculator_test.go | 652 --------------------- vms/avm/vm.go | 8 +- 8 files changed, 37 insertions(+), 837 deletions(-) delete mode 100644 vms/avm/txs/fees/calculator_test.go diff --git a/tests/e2e/p/workflow.go b/tests/e2e/p/workflow.go index 41db55904e30..3dc34afdf9de 100644 --- a/tests/e2e/p/workflow.go +++ b/tests/e2e/p/workflow.go @@ -54,9 +54,9 @@ var _ = e2e.DescribePChain("[Workflow]", func() { tests.Outf("{{blue}} fetching X-chain tx fee {{/}}\n") infoClient := info.NewClient(nodeURI.URI) - XchainFees, err := infoClient.GetTxFee(e2e.DefaultContext()) + xchainFees, err := infoClient.GetTxFee(e2e.DefaultContext()) require.NoError(err) - xChainTxFees := uint64(XchainFees.TxFee) + xChainTxFees := uint64(xchainFees.TxFee) tests.Outf("{{green}} X-chain TxFee: %d {{/}}\n", xChainTxFees) // amount to transfer from P to X chain diff --git a/vms/avm/block/executor/block.go b/vms/avm/block/executor/block.go index d0473737d67a..e49f1f482f8d 100644 --- a/vms/avm/block/executor/block.go +++ b/vms/avm/block/executor/block.go @@ -19,7 +19,6 @@ import ( "github.com/ava-labs/avalanchego/vms/avm/block" "github.com/ava-labs/avalanchego/vms/avm/state" "github.com/ava-labs/avalanchego/vms/avm/txs/executor" - "github.com/ava-labs/avalanchego/vms/components/fees" ) const SyncBound = 10 * time.Second @@ -76,13 +75,11 @@ func (b *Block) Verify(context.Context) error { // Syntactic verification is generally pretty fast, so we verify this first // before performing any possible DB reads. - feeManager := fees.NewManager(b.manager.backend.Config.DefaultUnitFees) for _, tx := range txs { err := tx.Unsigned.Visit(&executor.SyntacticVerifier{ - Backend: b.manager.backend, - BlkFeeManager: feeManager, - BlkTimestamp: newChainTime, - Tx: tx, + Backend: b.manager.backend, + BlkTimestamp: newChainTime, + Tx: tx, }) if err != nil { txID := tx.ID() diff --git a/vms/avm/block/executor/manager.go b/vms/avm/block/executor/manager.go index 1ee0f7aef266..a2a981c5185d 100644 --- a/vms/avm/block/executor/manager.go +++ b/vms/avm/block/executor/manager.go @@ -17,7 +17,6 @@ import ( "github.com/ava-labs/avalanchego/vms/avm/txs" "github.com/ava-labs/avalanchego/vms/avm/txs/executor" "github.com/ava-labs/avalanchego/vms/avm/txs/mempool" - "github.com/ava-labs/avalanchego/vms/components/fees" ) var ( @@ -149,10 +148,9 @@ func (m *manager) VerifyTx(tx *txs.Tx) error { } err := tx.Unsigned.Visit(&executor.SyntacticVerifier{ - Backend: m.backend, - BlkFeeManager: fees.NewManager(m.backend.Config.DefaultUnitFees), - BlkTimestamp: m.state.GetTimestamp(), - Tx: tx, + Backend: m.backend, + BlkTimestamp: m.state.GetTimestamp(), + Tx: tx, }) if err != nil { return err diff --git a/vms/avm/config/config.go b/vms/avm/config/config.go index 0561047f009d..b4da6e3781ea 100644 --- a/vms/avm/config/config.go +++ b/vms/avm/config/config.go @@ -3,12 +3,7 @@ package config -import ( - "math" - "time" - - "github.com/ava-labs/avalanchego/vms/components/fees" -) +import "time" // Struct collecting all the foundational parameters of the AVM type Config struct { @@ -18,14 +13,6 @@ type Config struct { // Fee that must be burned by every asset creating transaction CreateAssetTxFee uint64 - // Post E Fork, the unit fee for each dimension, denominated in Avax - // As long as fees are multidimensional but not dynamic, [DefaultUnitFees] - // will be the unit fees - DefaultUnitFees fees.Dimensions - - // Post E Fork, the max complexity of a block for each dimension - DefaultBlockMaxConsumedUnits fees.Dimensions - // Time of the Durango network upgrade DurangoTime time.Time @@ -36,14 +23,3 @@ type Config struct { func (c *Config) IsEForkActivated(timestamp time.Time) bool { return !timestamp.Before(c.EForkTime) } - -func (c *Config) BlockMaxConsumedUnits(timestamp time.Time) fees.Dimensions { - if !c.IsEForkActivated(timestamp) { - var res fees.Dimensions - for i := fees.Dimension(0); i < fees.FeeDimensions; i++ { - res[i] = math.MaxUint64 - } - return res - } - return c.DefaultBlockMaxConsumedUnits -} diff --git a/vms/avm/txs/executor/syntactic_verifier.go b/vms/avm/txs/executor/syntactic_verifier.go index 5032b75cb3dd..2bb1fc6c5aa0 100644 --- a/vms/avm/txs/executor/syntactic_verifier.go +++ b/vms/avm/txs/executor/syntactic_verifier.go @@ -16,8 +16,6 @@ import ( "github.com/ava-labs/avalanchego/vms/avm/txs" "github.com/ava-labs/avalanchego/vms/avm/txs/fees" "github.com/ava-labs/avalanchego/vms/components/avax" - - commonFees "github.com/ava-labs/avalanchego/vms/components/fees" ) const ( @@ -51,9 +49,8 @@ var ( type SyntacticVerifier struct { *Backend - BlkFeeManager *commonFees.Manager - BlkTimestamp time.Time - Tx *txs.Tx + BlkTimestamp time.Time + Tx *txs.Tx } func (v *SyntacticVerifier) BaseTx(tx *txs.BaseTx) error { @@ -62,11 +59,8 @@ func (v *SyntacticVerifier) BaseTx(tx *txs.BaseTx) error { } feeCalculator := fees.Calculator{ - FeeManager: v.BlkFeeManager, - Codec: v.Codec, - Config: v.Config, - ChainTime: v.BlkTimestamp, - Credentials: v.Tx.Creds, + Config: v.Config, + ChainTime: v.BlkTimestamp, } if err := tx.Visit(&feeCalculator); err != nil { return err @@ -136,11 +130,8 @@ func (v *SyntacticVerifier) CreateAssetTx(tx *txs.CreateAssetTx) error { } feeCalculator := fees.Calculator{ - FeeManager: v.BlkFeeManager, - Codec: v.Codec, - Config: v.Config, - ChainTime: v.BlkTimestamp, - Credentials: v.Tx.Creds, + Config: v.Config, + ChainTime: v.BlkTimestamp, } if err := tx.Visit(&feeCalculator); err != nil { return err @@ -195,11 +186,8 @@ func (v *SyntacticVerifier) OperationTx(tx *txs.OperationTx) error { } feeCalculator := fees.Calculator{ - FeeManager: v.BlkFeeManager, - Codec: v.Codec, - Config: v.Config, - ChainTime: v.BlkTimestamp, - Credentials: v.Tx.Creds, + Config: v.Config, + ChainTime: v.BlkTimestamp, } if err := tx.Visit(&feeCalculator); err != nil { return err @@ -266,11 +254,8 @@ func (v *SyntacticVerifier) ImportTx(tx *txs.ImportTx) error { } feeCalculator := fees.Calculator{ - FeeManager: v.BlkFeeManager, - Codec: v.Codec, - Config: v.Config, - ChainTime: v.BlkTimestamp, - Credentials: v.Tx.Creds, + Config: v.Config, + ChainTime: v.BlkTimestamp, } if err := tx.Visit(&feeCalculator); err != nil { return err @@ -319,11 +304,8 @@ func (v *SyntacticVerifier) ExportTx(tx *txs.ExportTx) error { } feeCalculator := fees.Calculator{ - FeeManager: v.BlkFeeManager, - Codec: v.Codec, - Config: v.Config, - ChainTime: v.BlkTimestamp, - Credentials: v.Tx.Creds, + Config: v.Config, + ChainTime: v.BlkTimestamp, } if err := tx.Visit(&feeCalculator); err != nil { return err diff --git a/vms/avm/txs/fees/calculator.go b/vms/avm/txs/fees/calculator.go index 989ef5429e41..dad73ae3607b 100644 --- a/vms/avm/txs/fees/calculator.go +++ b/vms/avm/txs/fees/calculator.go @@ -5,167 +5,68 @@ package fees import ( "errors" - "fmt" "time" - "github.com/ava-labs/avalanchego/codec" "github.com/ava-labs/avalanchego/vms/avm/config" - "github.com/ava-labs/avalanchego/vms/avm/fxs" "github.com/ava-labs/avalanchego/vms/avm/txs" - "github.com/ava-labs/avalanchego/vms/components/avax" - "github.com/ava-labs/avalanchego/vms/components/fees" ) var ( _ txs.Visitor = (*Calculator)(nil) - errFailedFeeCalculation = errors.New("failed fee calculation") - errFailedConsumedUnitsCumulation = errors.New("failed cumulating consumed units") + errEForkFeesNotDefinedYet = errors.New("fees in E fork not defined yet") ) type Calculator struct { // setup, to be filled before visitor methods are called - FeeManager *fees.Manager - Codec codec.Manager - Config *config.Config - ChainTime time.Time - - // inputs, to be filled before visitor methods are called - Credentials []*fxs.FxCredential + Config *config.Config + ChainTime time.Time // outputs of visitor execution Fee uint64 } -func (fc *Calculator) BaseTx(tx *txs.BaseTx) error { +func (fc *Calculator) BaseTx(*txs.BaseTx) error { if !fc.Config.IsEForkActivated(fc.ChainTime) { fc.Fee = fc.Config.TxFee return nil } - consumedUnits, err := fc.commonConsumedUnits(tx, tx.Outs, tx.Ins) - if err != nil { - return err - } - - return fc.AddFeesFor(consumedUnits) + return errEForkFeesNotDefinedYet } -func (fc *Calculator) CreateAssetTx(tx *txs.CreateAssetTx) error { +func (fc *Calculator) CreateAssetTx(*txs.CreateAssetTx) error { if !fc.Config.IsEForkActivated(fc.ChainTime) { fc.Fee = fc.Config.CreateAssetTxFee return nil } - consumedUnits, err := fc.commonConsumedUnits(tx, tx.Outs, tx.Ins) - if err != nil { - return err - } - - return fc.AddFeesFor(consumedUnits) + return errEForkFeesNotDefinedYet } -func (fc *Calculator) OperationTx(tx *txs.OperationTx) error { +func (fc *Calculator) OperationTx(*txs.OperationTx) error { if !fc.Config.IsEForkActivated(fc.ChainTime) { fc.Fee = fc.Config.TxFee return nil } - consumedUnits, err := fc.commonConsumedUnits(tx, tx.Outs, tx.Ins) - if err != nil { - return err - } - - return fc.AddFeesFor(consumedUnits) + return errEForkFeesNotDefinedYet } -func (fc *Calculator) ImportTx(tx *txs.ImportTx) error { +func (fc *Calculator) ImportTx(*txs.ImportTx) error { if !fc.Config.IsEForkActivated(fc.ChainTime) { fc.Fee = fc.Config.TxFee return nil } - ins := make([]*avax.TransferableInput, len(tx.Ins)+len(tx.ImportedIns)) - copy(ins, tx.Ins) - copy(ins[len(tx.Ins):], tx.ImportedIns) - - consumedUnits, err := fc.commonConsumedUnits(tx, tx.Outs, ins) - if err != nil { - return err - } - - return fc.AddFeesFor(consumedUnits) + return errEForkFeesNotDefinedYet } -func (fc *Calculator) ExportTx(tx *txs.ExportTx) error { +func (fc *Calculator) ExportTx(*txs.ExportTx) error { if !fc.Config.IsEForkActivated(fc.ChainTime) { fc.Fee = fc.Config.TxFee return nil } - outs := make([]*avax.TransferableOutput, len(tx.Outs)+len(tx.ExportedOuts)) - copy(outs, tx.Outs) - copy(outs[len(tx.Outs):], tx.ExportedOuts) - - consumedUnits, err := fc.commonConsumedUnits(tx, outs, tx.Ins) - if err != nil { - return err - } - - return fc.AddFeesFor(consumedUnits) -} - -func (fc *Calculator) commonConsumedUnits( - uTx txs.UnsignedTx, - allOuts []*avax.TransferableOutput, - allIns []*avax.TransferableInput, -) (fees.Dimensions, error) { - var consumedUnits fees.Dimensions - - uTxSize, err := fc.Codec.Size(txs.CodecVersion, uTx) - if err != nil { - return consumedUnits, fmt.Errorf("couldn't calculate UnsignedTx marshal length: %w", err) - } - credsSize, err := fc.Codec.Size(txs.CodecVersion, fc.Credentials) - if err != nil { - return consumedUnits, fmt.Errorf("failed retrieving size of credentials: %w", err) - } - consumedUnits[fees.Bandwidth] = uint64(uTxSize + credsSize) - - inputDimensions, err := fees.GetInputsDimensions(fc.Codec, txs.CodecVersion, allIns) - if err != nil { - return consumedUnits, fmt.Errorf("failed retrieving size of inputs: %w", err) - } - inputDimensions[fees.Bandwidth] = 0 // inputs bandwidth is already accounted for above, so we zero it - consumedUnits, err = fees.Add(consumedUnits, inputDimensions) - if err != nil { - return consumedUnits, fmt.Errorf("failed adding inputs: %w", err) - } - - outputDimensions, err := fees.GetOutputsDimensions(fc.Codec, txs.CodecVersion, allOuts) - if err != nil { - return consumedUnits, fmt.Errorf("failed retrieving size of outputs: %w", err) - } - outputDimensions[fees.Bandwidth] = 0 // outputs bandwidth is already accounted for above, so we zero it - consumedUnits, err = fees.Add(consumedUnits, outputDimensions) - if err != nil { - return consumedUnits, fmt.Errorf("failed adding outputs: %w", err) - } - - return consumedUnits, nil -} - -func (fc *Calculator) AddFeesFor(consumedUnits fees.Dimensions) error { - boundBreached, dimension := fc.FeeManager.CumulateUnits(consumedUnits, fc.Config.BlockMaxConsumedUnits(fc.ChainTime)) - if boundBreached { - return fmt.Errorf("%w: breached dimension %d", errFailedConsumedUnitsCumulation, dimension) - } - - fee, err := fc.FeeManager.CalculateFee(consumedUnits) - if err != nil { - return fmt.Errorf("%w: %w", errFailedFeeCalculation, err) - } - - fc.Fee = fee - return nil + return errEForkFeesNotDefinedYet } diff --git a/vms/avm/txs/fees/calculator_test.go b/vms/avm/txs/fees/calculator_test.go deleted file mode 100644 index dab958369cc9..000000000000 --- a/vms/avm/txs/fees/calculator_test.go +++ /dev/null @@ -1,652 +0,0 @@ -// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. -// See the file LICENSE for licensing terms. - -package fees - -import ( - "reflect" - "testing" - "time" - - "github.com/stretchr/testify/require" - - "github.com/ava-labs/avalanchego/codec" - "github.com/ava-labs/avalanchego/ids" - "github.com/ava-labs/avalanchego/snow" - "github.com/ava-labs/avalanchego/snow/snowtest" - "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" - "github.com/ava-labs/avalanchego/utils/timer/mockable" - "github.com/ava-labs/avalanchego/utils/units" - "github.com/ava-labs/avalanchego/vms/avm/block" - "github.com/ava-labs/avalanchego/vms/avm/config" - "github.com/ava-labs/avalanchego/vms/avm/fxs" - "github.com/ava-labs/avalanchego/vms/avm/txs" - "github.com/ava-labs/avalanchego/vms/components/avax" - "github.com/ava-labs/avalanchego/vms/components/fees" - "github.com/ava-labs/avalanchego/vms/components/verify" - "github.com/ava-labs/avalanchego/vms/nftfx" - "github.com/ava-labs/avalanchego/vms/secp256k1fx" -) - -var ( - feeTestsDefaultCfg = config.Config{ - DefaultUnitFees: fees.Dimensions{ - 1 * units.MicroAvax, - 2 * units.MicroAvax, - 3 * units.MicroAvax, - 4 * units.MicroAvax, - }, - DefaultBlockMaxConsumedUnits: fees.Dimensions{ - 3000, - 3500, - 1000, - 1000, - }, - - TxFee: 1 * units.Avax, - CreateAssetTxFee: 2 * units.Avax, - } - - feeTestKeys = secp256k1.TestKeys() - feeTestSigners = [][]*secp256k1.PrivateKey{} - - durangoTime = time.Time{} // assume durango is active in these tests -) - -type feeTests struct { - description string - cfgAndChainTimeF func() (*config.Config, time.Time) - expectedError error - checksF func(*testing.T, *Calculator) -} - -func TestBaseTxFees(t *testing.T) { - r := require.New(t) - - defaultCtx := snowtest.Context(t, snowtest.PChainID) - codec, err := createTestFeesCodec(defaultCtx) - r.NoError(err) - - baseTx, _ := txsCreationHelpers(defaultCtx) - uTx := &baseTx - sTx := &txs.Tx{ - Unsigned: uTx, - } - r.NoError(sTx.SignSECP256K1Fx(codec, feeTestSigners)) - - tests := []feeTests{ - { - description: "pre E fork", - cfgAndChainTimeF: func() (*config.Config, time.Time) { - eForkTime := time.Now().Truncate(time.Second) - chainTime := eForkTime.Add(-1 * time.Second) - - cfg := feeTestsDefaultCfg - cfg.DurangoTime = durangoTime - cfg.EForkTime = eForkTime - - return &cfg, chainTime - }, - expectedError: nil, - checksF: func(t *testing.T, fc *Calculator) { - require.Equal(t, fc.Config.TxFee, fc.Fee) - }, - }, - { - description: "post E fork, success", - cfgAndChainTimeF: func() (*config.Config, time.Time) { - eForkTime := time.Now().Truncate(time.Second) - chainTime := eForkTime.Add(time.Second) - - cfg := feeTestsDefaultCfg - cfg.DurangoTime = durangoTime - cfg.EForkTime = eForkTime - - return &cfg, chainTime - }, - expectedError: nil, - checksF: func(t *testing.T, fc *Calculator) { - require.Equal(t, 2920*units.MicroAvax, fc.Fee) - require.Equal(t, - fees.Dimensions{ - 224, - 1090, - 172, - 0, - }, - fc.FeeManager.GetCumulatedUnits(), - ) - }, - }, - { - description: "post E fork, utxos read cap breached", - cfgAndChainTimeF: func() (*config.Config, time.Time) { - eForkTime := time.Now().Truncate(time.Second) - chainTime := eForkTime.Add(time.Second) - - cfg := feeTestsDefaultCfg - cfg.DurangoTime = durangoTime - cfg.EForkTime = eForkTime - cfg.DefaultBlockMaxConsumedUnits[1] = 1090 - 1 - - return &cfg, chainTime - }, - expectedError: errFailedConsumedUnitsCumulation, - checksF: func(t *testing.T, fc *Calculator) {}, - }, - } - - for _, tt := range tests { - t.Run(tt.description, func(t *testing.T) { - cfg, chainTime := tt.cfgAndChainTimeF() - - fc := &Calculator{ - FeeManager: fees.NewManager(cfg.DefaultUnitFees), - Codec: codec, - Config: cfg, - ChainTime: chainTime, - Credentials: sTx.Creds, - } - err := uTx.Visit(fc) - r.ErrorIs(err, tt.expectedError) - tt.checksF(t, fc) - }) - } -} - -func TestCreateAssetTxFees(t *testing.T) { - r := require.New(t) - - defaultCtx := snowtest.Context(t, snowtest.PChainID) - codec, err := createTestFeesCodec(defaultCtx) - r.NoError(err) - - baseTx, _ := txsCreationHelpers(defaultCtx) - uTx := &txs.CreateAssetTx{ - BaseTx: baseTx, - Name: "name", - Symbol: "symb", - Denomination: 0, - States: []*txs.InitialState{ - { - FxIndex: 0, - Outs: []verify.State{ - &secp256k1fx.MintOutput{ - OutputOwners: secp256k1fx.OutputOwners{ - Threshold: 1, - Addrs: []ids.ShortID{feeTestKeys[0].PublicKey().Address()}, - }, - }, - }, - }, - }, - } - sTx := &txs.Tx{ - Unsigned: uTx, - } - r.NoError(sTx.SignSECP256K1Fx(codec, feeTestSigners)) - - tests := []feeTests{ - { - description: "pre E fork", - cfgAndChainTimeF: func() (*config.Config, time.Time) { - eForkTime := time.Now().Truncate(time.Second) - chainTime := eForkTime.Add(-1 * time.Second) - - cfg := feeTestsDefaultCfg - cfg.DurangoTime = durangoTime - cfg.EForkTime = eForkTime - - return &cfg, chainTime - }, - expectedError: nil, - checksF: func(t *testing.T, fc *Calculator) { - require.Equal(t, fc.Config.CreateAssetTxFee, fc.Fee) - }, - }, - { - description: "post E fork, success", - cfgAndChainTimeF: func() (*config.Config, time.Time) { - eForkTime := time.Now().Truncate(time.Second) - chainTime := eForkTime.Add(time.Second) - - cfg := feeTestsDefaultCfg - cfg.DurangoTime = durangoTime - cfg.EForkTime = eForkTime - - return &cfg, chainTime - }, - expectedError: nil, - checksF: func(t *testing.T, fc *Calculator) { - require.Equal(t, 2985*units.MicroAvax, fc.Fee) - require.Equal(t, - fees.Dimensions{ - 289, - 1090, - 172, - 0, - }, - fc.FeeManager.GetCumulatedUnits(), - ) - }, - }, - { - description: "post E fork, bandwidth cap breached", - cfgAndChainTimeF: func() (*config.Config, time.Time) { - eForkTime := time.Now().Truncate(time.Second) - chainTime := eForkTime.Add(time.Second) - - cfg := feeTestsDefaultCfg - cfg.DurangoTime = durangoTime - cfg.EForkTime = eForkTime - cfg.DefaultBlockMaxConsumedUnits[0] = 289 - 1 - - return &cfg, chainTime - }, - expectedError: errFailedConsumedUnitsCumulation, - checksF: func(t *testing.T, fc *Calculator) {}, - }, - } - - for _, tt := range tests { - t.Run(tt.description, func(t *testing.T) { - cfg, chainTime := tt.cfgAndChainTimeF() - - fc := &Calculator{ - FeeManager: fees.NewManager(cfg.DefaultUnitFees), - Codec: codec, - Config: cfg, - ChainTime: chainTime, - Credentials: sTx.Creds, - } - err := uTx.Visit(fc) - r.ErrorIs(err, tt.expectedError) - tt.checksF(t, fc) - }) - } -} - -func TestOperationTxFees(t *testing.T) { - r := require.New(t) - - defaultCtx := snowtest.Context(t, snowtest.PChainID) - codec, err := createTestFeesCodec(defaultCtx) - r.NoError(err) - - baseTx, _ := txsCreationHelpers(defaultCtx) - assetID := ids.GenerateTestID() - uTx := &txs.OperationTx{ - BaseTx: baseTx, - Ops: []*txs.Operation{{ - Asset: avax.Asset{ID: assetID}, - UTXOIDs: []*avax.UTXOID{{ - TxID: assetID, - OutputIndex: 1, - }}, - Op: &nftfx.MintOperation{ - MintInput: secp256k1fx.Input{ - SigIndices: []uint32{0}, - }, - GroupID: 1, - Payload: []byte{'h', 'e', 'l', 'l', 'o'}, - Outputs: []*secp256k1fx.OutputOwners{{}}, - }, - }}, - } - sTx := &txs.Tx{ - Unsigned: uTx, - } - r.NoError(sTx.SignSECP256K1Fx(codec, feeTestSigners)) - - tests := []feeTests{ - { - description: "pre E fork", - cfgAndChainTimeF: func() (*config.Config, time.Time) { - eForkTime := time.Now().Truncate(time.Second) - chainTime := eForkTime.Add(-1 * time.Second) - - cfg := feeTestsDefaultCfg - cfg.DurangoTime = durangoTime - cfg.EForkTime = eForkTime - - return &cfg, chainTime - }, - expectedError: nil, - checksF: func(t *testing.T, fc *Calculator) { - require.Equal(t, fc.Config.TxFee, fc.Fee) - }, - }, - { - description: "post E fork, success", - cfgAndChainTimeF: func() (*config.Config, time.Time) { - eForkTime := time.Now().Truncate(time.Second) - chainTime := eForkTime.Add(time.Second) - - cfg := feeTestsDefaultCfg - cfg.DurangoTime = durangoTime - cfg.EForkTime = eForkTime - - return &cfg, chainTime - }, - expectedError: nil, - checksF: func(t *testing.T, fc *Calculator) { - require.Equal(t, 3041*units.MicroAvax, fc.Fee) - require.Equal(t, - fees.Dimensions{ - 345, - 1090, - 172, - 0, - }, - fc.FeeManager.GetCumulatedUnits(), - ) - }, - }, - { - description: "post E fork, utxos read cap breached", - cfgAndChainTimeF: func() (*config.Config, time.Time) { - eForkTime := time.Now().Truncate(time.Second) - chainTime := eForkTime.Add(time.Second) - - cfg := feeTestsDefaultCfg - cfg.DurangoTime = durangoTime - cfg.EForkTime = eForkTime - cfg.DefaultBlockMaxConsumedUnits[1] = 1090 - 1 - - return &cfg, chainTime - }, - expectedError: errFailedConsumedUnitsCumulation, - checksF: func(t *testing.T, fc *Calculator) {}, - }, - } - - for _, tt := range tests { - t.Run(tt.description, func(t *testing.T) { - cfg, chainTime := tt.cfgAndChainTimeF() - - fc := &Calculator{ - FeeManager: fees.NewManager(cfg.DefaultUnitFees), - Codec: codec, - Config: cfg, - ChainTime: chainTime, - Credentials: sTx.Creds, - } - err := uTx.Visit(fc) - r.ErrorIs(err, tt.expectedError) - tt.checksF(t, fc) - }) - } -} - -func TestImportTxFees(t *testing.T) { - r := require.New(t) - - defaultCtx := snowtest.Context(t, snowtest.PChainID) - codec, err := createTestFeesCodec(defaultCtx) - r.NoError(err) - - baseTx, _ := txsCreationHelpers(defaultCtx) - uTx := &txs.ImportTx{ - BaseTx: baseTx, - SourceChain: ids.GenerateTestID(), - ImportedIns: []*avax.TransferableInput{{ - UTXOID: avax.UTXOID{ - TxID: ids.Empty.Prefix(1), - OutputIndex: 1, - }, - Asset: avax.Asset{ID: ids.ID{'a', 's', 's', 'e', 'r', 't'}}, - In: &secp256k1fx.TransferInput{ - Amt: 50000, - Input: secp256k1fx.Input{SigIndices: []uint32{0}}, - }, - }}, - } - sTx := &txs.Tx{ - Unsigned: uTx, - } - r.NoError(sTx.SignSECP256K1Fx(codec, feeTestSigners)) - - tests := []feeTests{ - { - description: "pre E fork", - cfgAndChainTimeF: func() (*config.Config, time.Time) { - eForkTime := time.Now().Truncate(time.Second) - chainTime := eForkTime.Add(-1 * time.Second) - - cfg := feeTestsDefaultCfg - cfg.DurangoTime = durangoTime - cfg.EForkTime = eForkTime - - return &cfg, chainTime - }, - expectedError: nil, - checksF: func(t *testing.T, fc *Calculator) { - require.Equal(t, fc.Config.TxFee, fc.Fee) - }, - }, - { - description: "post E fork, success", - cfgAndChainTimeF: func() (*config.Config, time.Time) { - eForkTime := time.Now().Truncate(time.Second) - chainTime := eForkTime.Add(time.Second) - - cfg := feeTestsDefaultCfg - cfg.DurangoTime = durangoTime - cfg.EForkTime = eForkTime - - return &cfg, chainTime - }, - expectedError: nil, - checksF: func(t *testing.T, fc *Calculator) { - require.Equal(t, 5494*units.MicroAvax, fc.Fee) - require.Equal(t, - fees.Dimensions{ - 348, - 2180, - 262, - 0, - }, - fc.FeeManager.GetCumulatedUnits(), - ) - }, - }, - { - description: "post E fork, utxos read cap breached", - cfgAndChainTimeF: func() (*config.Config, time.Time) { - eForkTime := time.Now().Truncate(time.Second) - chainTime := eForkTime.Add(time.Second) - - cfg := feeTestsDefaultCfg - cfg.DurangoTime = durangoTime - cfg.EForkTime = eForkTime - cfg.DefaultBlockMaxConsumedUnits[1] = 1090 - 1 - - return &cfg, chainTime - }, - expectedError: errFailedConsumedUnitsCumulation, - checksF: func(t *testing.T, fc *Calculator) {}, - }, - } - - for _, tt := range tests { - t.Run(tt.description, func(t *testing.T) { - cfg, chainTime := tt.cfgAndChainTimeF() - - fc := &Calculator{ - FeeManager: fees.NewManager(cfg.DefaultUnitFees), - Codec: codec, - Config: cfg, - ChainTime: chainTime, - Credentials: sTx.Creds, - } - err := uTx.Visit(fc) - r.ErrorIs(err, tt.expectedError) - tt.checksF(t, fc) - }) - } -} - -func TestExportTxFees(t *testing.T) { - r := require.New(t) - - defaultCtx := snowtest.Context(t, snowtest.PChainID) - codec, err := createTestFeesCodec(defaultCtx) - r.NoError(err) - - baseTx, outputs := txsCreationHelpers(defaultCtx) - uTx := &txs.ExportTx{ - BaseTx: baseTx, - DestinationChain: ids.GenerateTestID(), - ExportedOuts: outputs, - } - sTx := &txs.Tx{ - Unsigned: uTx, - } - r.NoError(sTx.SignSECP256K1Fx(codec, feeTestSigners)) - - tests := []feeTests{ - { - description: "pre E fork", - cfgAndChainTimeF: func() (*config.Config, time.Time) { - eForkTime := time.Now().Truncate(time.Second) - chainTime := eForkTime.Add(-1 * time.Second) - - cfg := feeTestsDefaultCfg - cfg.DurangoTime = durangoTime - cfg.EForkTime = eForkTime - - return &cfg, chainTime - }, - expectedError: nil, - checksF: func(t *testing.T, fc *Calculator) { - require.Equal(t, fc.Config.TxFee, fc.Fee) - }, - }, - { - description: "post E fork, success", - cfgAndChainTimeF: func() (*config.Config, time.Time) { - eForkTime := time.Now().Truncate(time.Second) - chainTime := eForkTime.Add(time.Second) - - cfg := feeTestsDefaultCfg - cfg.DurangoTime = durangoTime - cfg.EForkTime = eForkTime - - return &cfg, chainTime - }, - expectedError: nil, - checksF: func(t *testing.T, fc *Calculator) { - require.Equal(t, 3282*units.MicroAvax, fc.Fee) - require.Equal(t, - fees.Dimensions{ - 340, - 1090, - 254, - 0, - }, - fc.FeeManager.GetCumulatedUnits(), - ) - }, - }, - { - description: "post E fork, utxos read cap breached", - cfgAndChainTimeF: func() (*config.Config, time.Time) { - eForkTime := time.Now().Truncate(time.Second) - chainTime := eForkTime.Add(time.Second) - - cfg := feeTestsDefaultCfg - cfg.DurangoTime = durangoTime - cfg.EForkTime = eForkTime - cfg.DefaultBlockMaxConsumedUnits[1] = 1090 - 1 - - return &cfg, chainTime - }, - expectedError: errFailedConsumedUnitsCumulation, - checksF: func(t *testing.T, fc *Calculator) {}, - }, - } - - for _, tt := range tests { - t.Run(tt.description, func(t *testing.T) { - cfg, chainTime := tt.cfgAndChainTimeF() - - fc := &Calculator{ - FeeManager: fees.NewManager(cfg.DefaultUnitFees), - Codec: codec, - Config: cfg, - ChainTime: chainTime, - Credentials: sTx.Creds, - } - err := uTx.Visit(fc) - r.ErrorIs(err, tt.expectedError) - tt.checksF(t, fc) - }) - } -} - -func createTestFeesCodec(defaultCtx *snow.Context) (codec.Manager, error) { - fxs := []fxs.Fx{ - &secp256k1fx.Fx{}, - &nftfx.Fx{}, - } - - parser, err := block.NewCustomParser( - durangoTime, - map[reflect.Type]int{}, - &mockable.Clock{}, - defaultCtx.Log, - fxs, - ) - if err != nil { - return nil, err - } - - return parser.Codec(), nil -} - -func txsCreationHelpers(defaultCtx *snow.Context) ( - baseTx txs.BaseTx, - otherOutputs []*avax.TransferableOutput, -) { - inputs := []*avax.TransferableInput{{ - UTXOID: avax.UTXOID{ - TxID: ids.ID{'t', 'x', 'I', 'D'}, - OutputIndex: 2, - }, - Asset: avax.Asset{ID: defaultCtx.AVAXAssetID}, - In: &secp256k1fx.TransferInput{ - Amt: uint64(5678), - Input: secp256k1fx.Input{SigIndices: []uint32{0}}, - }, - }} - outputs := []*avax.TransferableOutput{{ - Asset: avax.Asset{ID: defaultCtx.AVAXAssetID}, - Out: &secp256k1fx.TransferOutput{ - Amt: uint64(1234), - OutputOwners: secp256k1fx.OutputOwners{ - Threshold: 1, - Addrs: []ids.ShortID{feeTestKeys[0].PublicKey().Address()}, - }, - }, - }} - otherOutputs = []*avax.TransferableOutput{{ - Asset: avax.Asset{ID: defaultCtx.AVAXAssetID}, - Out: &secp256k1fx.TransferOutput{ - Amt: uint64(4567), - OutputOwners: secp256k1fx.OutputOwners{ - Threshold: 1, - Addrs: []ids.ShortID{feeTestKeys[1].PublicKey().Address()}, - }, - }, - }} - baseTx = txs.BaseTx{ - BaseTx: avax.BaseTx{ - NetworkID: defaultCtx.NetworkID, - BlockchainID: defaultCtx.ChainID, - Ins: inputs, - Outs: outputs, - }, - } - - return baseTx, otherOutputs -} diff --git a/vms/avm/vm.go b/vms/avm/vm.go index 014b5416b97c..4926a0679f34 100644 --- a/vms/avm/vm.go +++ b/vms/avm/vm.go @@ -42,7 +42,6 @@ import ( "github.com/ava-labs/avalanchego/vms/avm/txs/mempool" "github.com/ava-labs/avalanchego/vms/avm/utxo" "github.com/ava-labs/avalanchego/vms/components/avax" - "github.com/ava-labs/avalanchego/vms/components/fees" "github.com/ava-labs/avalanchego/vms/components/index" "github.com/ava-labs/avalanchego/vms/components/keystore" "github.com/ava-labs/avalanchego/vms/secp256k1fx" @@ -491,10 +490,9 @@ func (vm *VM) ParseTx(_ context.Context, bytes []byte) (snowstorm.Tx, error) { } err = tx.Unsigned.Visit(&txexecutor.SyntacticVerifier{ - Backend: vm.txBackend, - BlkFeeManager: fees.NewManager(vm.Config.DefaultUnitFees), - BlkTimestamp: vm.state.GetTimestamp(), - Tx: tx, + Backend: vm.txBackend, + BlkTimestamp: vm.state.GetTimestamp(), + Tx: tx, }) if err != nil { return nil, err From 921a7ddc5b8e34d2bd25d5dc5188c30f8564006c Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Fri, 26 Jan 2024 20:29:59 +0100 Subject: [PATCH 079/190] fixed p-chain workflow e2e test --- vms/avm/txs/fees/calculator.go | 40 +++++++++------------------------- 1 file changed, 10 insertions(+), 30 deletions(-) diff --git a/vms/avm/txs/fees/calculator.go b/vms/avm/txs/fees/calculator.go index dad73ae3607b..122a675874f4 100644 --- a/vms/avm/txs/fees/calculator.go +++ b/vms/avm/txs/fees/calculator.go @@ -27,46 +27,26 @@ type Calculator struct { } func (fc *Calculator) BaseTx(*txs.BaseTx) error { - if !fc.Config.IsEForkActivated(fc.ChainTime) { - fc.Fee = fc.Config.TxFee - return nil - } - - return errEForkFeesNotDefinedYet + fc.Fee = fc.Config.TxFee + return nil } func (fc *Calculator) CreateAssetTx(*txs.CreateAssetTx) error { - if !fc.Config.IsEForkActivated(fc.ChainTime) { - fc.Fee = fc.Config.CreateAssetTxFee - return nil - } - - return errEForkFeesNotDefinedYet + fc.Fee = fc.Config.CreateAssetTxFee + return nil } func (fc *Calculator) OperationTx(*txs.OperationTx) error { - if !fc.Config.IsEForkActivated(fc.ChainTime) { - fc.Fee = fc.Config.TxFee - return nil - } - - return errEForkFeesNotDefinedYet + fc.Fee = fc.Config.TxFee + return nil } func (fc *Calculator) ImportTx(*txs.ImportTx) error { - if !fc.Config.IsEForkActivated(fc.ChainTime) { - fc.Fee = fc.Config.TxFee - return nil - } - - return errEForkFeesNotDefinedYet + fc.Fee = fc.Config.TxFee + return nil } func (fc *Calculator) ExportTx(*txs.ExportTx) error { - if !fc.Config.IsEForkActivated(fc.ChainTime) { - fc.Fee = fc.Config.TxFee - return nil - } - - return errEForkFeesNotDefinedYet + fc.Fee = fc.Config.TxFee + return nil } From 36399f43d88cd32bb92f42f282d801bef1e23c35 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Fri, 26 Jan 2024 23:04:45 +0100 Subject: [PATCH 080/190] nit --- wallet/chain/p/builder_dynamic_fees_test.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/wallet/chain/p/builder_dynamic_fees_test.go b/wallet/chain/p/builder_dynamic_fees_test.go index 2ed94f1efa9b..b08f992f2b30 100644 --- a/wallet/chain/p/builder_dynamic_fees_test.go +++ b/wallet/chain/p/builder_dynamic_fees_test.go @@ -724,11 +724,16 @@ func TestTransformSubnetTx(t *testing.T) { be.EXPECT().NetworkID().Return(constants.MainnetID).AnyTimes() be.EXPECT().UTXOs(gomock.Any(), constants.PlatformChainID).Return(utxos, nil) + var ( + initialSupply = 40 * units.MegaAvax + maxSupply = 100 * units.MegaAvax + ) + utx, err := b.NewTransformSubnetTx( subnetID, subnetAssetID, - 50*units.MegaAvax, // initial supply - 100*units.MegaAvax, // max supply + initialSupply, // initial supply + maxSupply, // max supply reward.PercentDenominator, // min consumption rate reward.PercentDenominator, // max consumption rate 1, // min validator stake @@ -771,6 +776,7 @@ func TestTransformSubnetTx(t *testing.T) { outs := utx.Outs require.Len(ins, 3) require.Len(outs, 2) + require.Equal(maxSupply-initialSupply, ins[0].In.Amount()-outs[0].Out.Amount()) require.Equal(fc.Fee, ins[1].In.Amount()+ins[2].In.Amount()-outs[1].Out.Amount()) } From cb46cdf587aaaf6dd4551f6b40a64e60b70987a4 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Fri, 26 Jan 2024 23:29:06 +0100 Subject: [PATCH 081/190] nit --- vms/avm/txs/fees/calculator.go | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/vms/avm/txs/fees/calculator.go b/vms/avm/txs/fees/calculator.go index 122a675874f4..9d956486dec3 100644 --- a/vms/avm/txs/fees/calculator.go +++ b/vms/avm/txs/fees/calculator.go @@ -4,18 +4,13 @@ package fees import ( - "errors" "time" "github.com/ava-labs/avalanchego/vms/avm/config" "github.com/ava-labs/avalanchego/vms/avm/txs" ) -var ( - _ txs.Visitor = (*Calculator)(nil) - - errEForkFeesNotDefinedYet = errors.New("fees in E fork not defined yet") -) +var _ txs.Visitor = (*Calculator)(nil) type Calculator struct { // setup, to be filled before visitor methods are called From 5bad5378f12c02139219cbbc7416bdd1046e4e53 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Fri, 26 Jan 2024 23:46:33 +0100 Subject: [PATCH 082/190] leftover --- vms/platformvm/txs/executor/standard_tx_executor.go | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/vms/platformvm/txs/executor/standard_tx_executor.go b/vms/platformvm/txs/executor/standard_tx_executor.go index 5f1509aa0135..29c2224a9311 100644 --- a/vms/platformvm/txs/executor/standard_tx_executor.go +++ b/vms/platformvm/txs/executor/standard_tx_executor.go @@ -500,6 +500,17 @@ func (e *StandardTxExecutor) TransformSubnetTx(tx *txs.TransformSubnetTx) error } totalRewardAmount := tx.MaximumSupply - tx.InitialSupply + feeCalculator := fees.Calculator{ + IsEForkActive: e.Backend.Config.IsEForkActivated(currentTimestamp), + Config: e.Backend.Config, + ChainTime: currentTimestamp, + FeeManager: e.BlkFeeManager, + ConsumedUnitsCap: e.UnitCaps, + Credentials: e.Tx.Creds, + } + if err := tx.Visit(&feeCalculator); err != nil { + return err + } if err := e.Backend.FlowChecker.VerifySpend( tx, e.State, @@ -510,7 +521,7 @@ func (e *StandardTxExecutor) TransformSubnetTx(tx *txs.TransformSubnetTx) error // entry in this map literal from being overwritten by the // second entry. map[ids.ID]uint64{ - e.Ctx.AVAXAssetID: e.Config.TransformSubnetTxFee, + e.Ctx.AVAXAssetID: feeCalculator.Fee, tx.AssetID: totalRewardAmount, }, ); err != nil { From 93fff34bd2341d0b2cbc3d9495e9abd5c3b2d4ec Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 29 Jan 2024 10:22:28 +0100 Subject: [PATCH 083/190] improved utxos selection to finance txs in wallet --- wallet/chain/p/builder_dynamic_fees.go | 53 +++++++++++++++++--------- 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/wallet/chain/p/builder_dynamic_fees.go b/wallet/chain/p/builder_dynamic_fees.go index fcc615c02655..b6228fb62e84 100644 --- a/wallet/chain/p/builder_dynamic_fees.go +++ b/wallet/chain/p/builder_dynamic_fees.go @@ -5,6 +5,7 @@ package p import ( "fmt" + "slices" "time" "github.com/ava-labs/avalanchego/ids" @@ -856,11 +857,25 @@ func (b *DynamicFeesBuilder) financeTx( stakeOutputs []*avax.TransferableOutput, err error, ) { + avaxAssetID := b.backend.AVAXAssetID() utxos, err := b.backend.UTXOs(options.Context(), constants.PlatformChainID) if err != nil { return nil, nil, nil, err } + // we can only pay fees in avax, so we sort avax-denominated UTXOs last + // to maximize probability of being able to pay fees + slices.SortFunc(utxos, func(lhs, rhs *avax.UTXO) int { + switch { + case lhs.Asset.AssetID() == avaxAssetID && rhs.Asset.AssetID() != avaxAssetID: + return 1 + case lhs.Asset.AssetID() != avaxAssetID && rhs.Asset.AssetID() == avaxAssetID: + return -1 + default: + return 0 + } + }) + addrs := options.Addresses(b.addrs) minIssuanceTime := options.MinIssuanceTime() @@ -873,7 +888,7 @@ func (b *DynamicFeesBuilder) financeTx( Addrs: []ids.ShortID{addr}, }) - amountsToBurn[b.backend.AVAXAssetID()] += feeCalc.Fee + amountsToBurn[avaxAssetID] += feeCalc.Fee // Iterate over the locked UTXOs for _, utxo := range utxos { @@ -932,7 +947,7 @@ func (b *DynamicFeesBuilder) financeTx( if err != nil { return nil, nil, nil, fmt.Errorf("account for input fees: %w", err) } - amountsToBurn[b.backend.AVAXAssetID()] += addedFees + amountsToBurn[avaxAssetID] += addedFees // update fees to account for the credentials to be added with inputs upon tx signing credsDimensions, err := commonfees.GetCredentialsDimensions(txs.Codec, txs.CodecVersion, inputSigIndices) @@ -943,7 +958,7 @@ func (b *DynamicFeesBuilder) financeTx( if err != nil { return nil, nil, nil, fmt.Errorf("account for input fees: %w", err) } - amountsToBurn[b.backend.AVAXAssetID()] += addedFees + amountsToBurn[avaxAssetID] += addedFees inputs = append(inputs, input) @@ -974,7 +989,7 @@ func (b *DynamicFeesBuilder) financeTx( if err != nil { return nil, nil, nil, fmt.Errorf("account for stakedOut fees: %w", err) } - amountsToBurn[b.backend.AVAXAssetID()] += addedFees + amountsToBurn[avaxAssetID] += addedFees stakeOutputs = append(stakeOutputs, stakeOut) @@ -1001,7 +1016,7 @@ func (b *DynamicFeesBuilder) financeTx( if err != nil { return nil, nil, nil, fmt.Errorf("account for stakedOut fees: %w", err) } - amountsToBurn[b.backend.AVAXAssetID()] += addedFees + amountsToBurn[avaxAssetID] += addedFees changeOutputs = append(changeOutputs, changeOut) } @@ -1058,7 +1073,7 @@ func (b *DynamicFeesBuilder) financeTx( if err != nil { return nil, nil, nil, fmt.Errorf("account for input fees: %w", err) } - amountsToBurn[b.backend.AVAXAssetID()] += addedFees + amountsToBurn[avaxAssetID] += addedFees // update fees to account for the credentials to be added with inputs upon tx signing credsDimensions, err := commonfees.GetCredentialsDimensions(txs.Codec, txs.CodecVersion, inputSigIndices) @@ -1069,7 +1084,7 @@ func (b *DynamicFeesBuilder) financeTx( if err != nil { return nil, nil, nil, fmt.Errorf("account for input fees: %w", err) } - amountsToBurn[b.backend.AVAXAssetID()] += addedFees + amountsToBurn[avaxAssetID] += addedFees inputs = append(inputs, input) @@ -1108,7 +1123,7 @@ func (b *DynamicFeesBuilder) financeTx( if err != nil { return nil, nil, nil, fmt.Errorf("account for stakedOut fees: %w", err) } - amountsToBurn[b.backend.AVAXAssetID()] += addedFees + amountsToBurn[avaxAssetID] += addedFees } if remainingAmount := amountAvalibleToStake - amountToStake; remainingAmount > 0 { @@ -1130,19 +1145,19 @@ func (b *DynamicFeesBuilder) financeTx( return nil, nil, nil, fmt.Errorf("account for stakedOut fees: %w", err) } - switch { - case addedFees < remainingAmount: - if assetID == b.backend.AVAXAssetID() { + if assetID != avaxAssetID { + changeOut.Out.(*secp256k1fx.TransferOutput).Amt = remainingAmount + amountsToBurn[avaxAssetID] += addedFees + changeOutputs = append(changeOutputs, changeOut) + } else { + // here assetID == b.backend.AVAXAssetID() + switch { + case addedFees < remainingAmount: changeOut.Out.(*secp256k1fx.TransferOutput).Amt = remainingAmount - addedFees - } else { - changeOut.Out.(*secp256k1fx.TransferOutput).Amt = remainingAmount - amountsToBurn[b.backend.AVAXAssetID()] += addedFees + changeOutputs = append(changeOutputs, changeOut) + case addedFees >= remainingAmount: + amountsToBurn[assetID] += addedFees - remainingAmount } - changeOutputs = append(changeOutputs, changeOut) - case addedFees == remainingAmount: - // fees wholly consume remaining amount. We don't add the change - case addedFees > remainingAmount: - amountsToBurn[b.backend.AVAXAssetID()] += addedFees - remainingAmount } } } From 1f3cece158d7c2a17e3f0b5edb34e81a955af6bc Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 29 Jan 2024 10:35:13 +0100 Subject: [PATCH 084/190] fix CI compilation --- wallet/chain/p/builder_dynamic_fees.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wallet/chain/p/builder_dynamic_fees.go b/wallet/chain/p/builder_dynamic_fees.go index b6228fb62e84..b18de30eebf3 100644 --- a/wallet/chain/p/builder_dynamic_fees.go +++ b/wallet/chain/p/builder_dynamic_fees.go @@ -5,9 +5,10 @@ package p import ( "fmt" - "slices" "time" + "golang.org/x/exp/slices" + "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils" "github.com/ava-labs/avalanchego/utils/constants" From 7415a5848a563a0d232a7730e314e9293b424072 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 29 Jan 2024 12:04:30 +0100 Subject: [PATCH 085/190] consolidated code in wallet --- wallet/chain/p/builder_dynamic_fees.go | 143 +++++++++++-------------- 1 file changed, 60 insertions(+), 83 deletions(-) diff --git a/wallet/chain/p/builder_dynamic_fees.go b/wallet/chain/p/builder_dynamic_fees.go index b18de30eebf3..2a0e9c9469cb 100644 --- a/wallet/chain/p/builder_dynamic_fees.go +++ b/wallet/chain/p/builder_dynamic_fees.go @@ -175,12 +175,8 @@ func (b *DynamicFeesBuilder) NewAddSubnetValidatorTx( } // update fees to account for the auth credentials to be added upon tx signing - credsDimensions, err := commonfees.GetCredentialsDimensions(txs.Codec, txs.CodecVersion, subnetAuth.SigIndices) - if err != nil { - return nil, fmt.Errorf("failed calculating input size: %w", err) - } - if _, err := feeCalc.AddFeesFor(credsDimensions); err != nil { - return nil, fmt.Errorf("account for input fees: %w", err) + if _, err = financeCredential(feeCalc, subnetAuth.SigIndices); err != nil { + return nil, fmt.Errorf("account for credential fees: %w", err) } // feesMan cumulates consumed units. Let's init it with utx filled so far @@ -234,12 +230,8 @@ func (b *DynamicFeesBuilder) NewRemoveSubnetValidatorTx( } // update fees to account for the auth credentials to be added upon tx signing - credsDimensions, err := commonfees.GetCredentialsDimensions(txs.Codec, txs.CodecVersion, subnetAuth.SigIndices) - if err != nil { - return nil, fmt.Errorf("failed calculating input size: %w", err) - } - if _, err := feeCalc.AddFeesFor(credsDimensions); err != nil { - return nil, fmt.Errorf("account for input fees: %w", err) + if _, err = financeCredential(feeCalc, subnetAuth.SigIndices); err != nil { + return nil, fmt.Errorf("account for credential fees: %w", err) } // feesMan cumulates consumed units. Let's init it with utx filled so far @@ -350,12 +342,8 @@ func (b *DynamicFeesBuilder) NewCreateChainTx( } // update fees to account for the auth credentials to be added upon tx signing - credsDimensions, err := commonfees.GetCredentialsDimensions(txs.Codec, txs.CodecVersion, subnetAuth.SigIndices) - if err != nil { - return nil, fmt.Errorf("failed calculating input size: %w", err) - } - if _, err := feeCalc.AddFeesFor(credsDimensions); err != nil { - return nil, fmt.Errorf("account for input fees: %w", err) + if _, err = financeCredential(feeCalc, subnetAuth.SigIndices); err != nil { + return nil, fmt.Errorf("account for credential fees: %w", err) } // feesMan cumulates consumed units. Let's init it with utx filled so far @@ -523,13 +511,8 @@ func (b *DynamicFeesBuilder) NewImportTx( } for _, sigIndices := range importedSigIndices { - // update fees to account for the credentials to be added with inputs upon tx signing - credsDimensions, err := commonfees.GetCredentialsDimensions(txs.Codec, txs.CodecVersion, sigIndices) - if err != nil { - return nil, fmt.Errorf("failed calculating input size: %w", err) - } - if _, err := feeCalc.AddFeesFor(credsDimensions); err != nil { - return nil, fmt.Errorf("account for input fees: %w", err) + if _, err = financeCredential(feeCalc, sigIndices); err != nil { + return nil, fmt.Errorf("account for credential fees: %w", err) } } @@ -714,12 +697,8 @@ func (b *DynamicFeesBuilder) NewTransformSubnetTx( } // update fees to account for the auth credentials to be added upon tx signing - credsDimensions, err := commonfees.GetCredentialsDimensions(txs.Codec, txs.CodecVersion, subnetAuth.SigIndices) - if err != nil { - return nil, fmt.Errorf("failed calculating input size: %w", err) - } - if _, err := feeCalc.AddFeesFor(credsDimensions); err != nil { - return nil, fmt.Errorf("account for input fees: %w", err) + if _, err = financeCredential(feeCalc, subnetAuth.SigIndices); err != nil { + return nil, fmt.Errorf("account for credential fees: %w", err) } // feesMan cumulates consumed units. Let's init it with utx filled so far @@ -865,7 +844,7 @@ func (b *DynamicFeesBuilder) financeTx( } // we can only pay fees in avax, so we sort avax-denominated UTXOs last - // to maximize probability of being able to pay fees + // to maximize probability of being able to pay fees. slices.SortFunc(utxos, func(lhs, rhs *avax.UTXO) int { switch { case lhs.Asset.AssetID() == avaxAssetID && rhs.Asset.AssetID() != avaxAssetID: @@ -939,23 +918,13 @@ func (b *DynamicFeesBuilder) financeTx( }, } - // update fees to account for the input added - insDimensions, err := commonfees.GetInputsDimensions(txs.Codec, txs.CodecVersion, []*avax.TransferableInput{input}) - if err != nil { - return nil, nil, nil, fmt.Errorf("failed calculating input size: %w", err) - } - addedFees, err := feeCalc.AddFeesFor(insDimensions) + addedFees, err := financeInput(feeCalc, input) if err != nil { return nil, nil, nil, fmt.Errorf("account for input fees: %w", err) } amountsToBurn[avaxAssetID] += addedFees - // update fees to account for the credentials to be added with inputs upon tx signing - credsDimensions, err := commonfees.GetCredentialsDimensions(txs.Codec, txs.CodecVersion, inputSigIndices) - if err != nil { - return nil, nil, nil, fmt.Errorf("failed calculating input size: %w", err) - } - addedFees, err = feeCalc.AddFeesFor(credsDimensions) + addedFees, err = financeCredential(feeCalc, inputSigIndices) if err != nil { return nil, nil, nil, fmt.Errorf("account for input fees: %w", err) } @@ -981,14 +950,9 @@ func (b *DynamicFeesBuilder) financeTx( }, } - // update fees to account for the staked output - outDimensions, err := commonfees.GetOutputsDimensions(txs.Codec, txs.CodecVersion, []*avax.TransferableOutput{stakeOut}) - if err != nil { - return nil, nil, nil, fmt.Errorf("failed calculating stakedOut size: %w", err) - } - addedFees, err = feeCalc.AddFeesFor(outDimensions) + addedFees, err = financeOutput(feeCalc, stakeOut) if err != nil { - return nil, nil, nil, fmt.Errorf("account for stakedOut fees: %w", err) + return nil, nil, nil, fmt.Errorf("account for output fees: %w", err) } amountsToBurn[avaxAssetID] += addedFees @@ -1009,13 +973,9 @@ func (b *DynamicFeesBuilder) financeTx( } // update fees to account for the change output - outDimensions, err := commonfees.GetOutputsDimensions(txs.Codec, txs.CodecVersion, []*avax.TransferableOutput{changeOut}) - if err != nil { - return nil, nil, nil, fmt.Errorf("failed calculating changeOut size: %w", err) - } - addedFees, err := feeCalc.AddFeesFor(outDimensions) + addedFees, err = financeOutput(feeCalc, changeOut) if err != nil { - return nil, nil, nil, fmt.Errorf("account for stakedOut fees: %w", err) + return nil, nil, nil, fmt.Errorf("account for output fees: %w", err) } amountsToBurn[avaxAssetID] += addedFees @@ -1065,25 +1025,15 @@ func (b *DynamicFeesBuilder) financeTx( }, } - // update fees to account for the input added - insDimensions, err := commonfees.GetInputsDimensions(txs.Codec, txs.CodecVersion, []*avax.TransferableInput{input}) - if err != nil { - return nil, nil, nil, fmt.Errorf("failed calculating input size: %w", err) - } - addedFees, err := feeCalc.AddFeesFor(insDimensions) + addedFees, err := financeInput(feeCalc, input) if err != nil { return nil, nil, nil, fmt.Errorf("account for input fees: %w", err) } amountsToBurn[avaxAssetID] += addedFees - // update fees to account for the credentials to be added with inputs upon tx signing - credsDimensions, err := commonfees.GetCredentialsDimensions(txs.Codec, txs.CodecVersion, inputSigIndices) + addedFees, err = financeCredential(feeCalc, inputSigIndices) if err != nil { - return nil, nil, nil, fmt.Errorf("failed calculating input size: %w", err) - } - addedFees, err = feeCalc.AddFeesFor(credsDimensions) - if err != nil { - return nil, nil, nil, fmt.Errorf("account for input fees: %w", err) + return nil, nil, nil, fmt.Errorf("account for credential fees: %w", err) } amountsToBurn[avaxAssetID] += addedFees @@ -1115,14 +1065,9 @@ func (b *DynamicFeesBuilder) financeTx( stakeOutputs = append(stakeOutputs, stakeOut) - // update fees to account for the staked output - outDimensions, err := commonfees.GetOutputsDimensions(txs.Codec, txs.CodecVersion, []*avax.TransferableOutput{stakeOut}) + addedFees, err = financeOutput(feeCalc, stakeOut) if err != nil { - return nil, nil, nil, fmt.Errorf("failed calculating stakedOut size: %w", err) - } - addedFees, err := feeCalc.AddFeesFor(outDimensions) - if err != nil { - return nil, nil, nil, fmt.Errorf("account for stakedOut fees: %w", err) + return nil, nil, nil, fmt.Errorf("account for output fees: %w", err) } amountsToBurn[avaxAssetID] += addedFees } @@ -1137,13 +1082,9 @@ func (b *DynamicFeesBuilder) financeTx( } // update fees to account for the change output - outDimensions, err := commonfees.GetOutputsDimensions(txs.Codec, txs.CodecVersion, []*avax.TransferableOutput{changeOut}) - if err != nil { - return nil, nil, nil, fmt.Errorf("failed calculating changeOut size: %w", err) - } - addedFees, err := feeCalc.AddFeesFor(outDimensions) + addedFees, err = financeOutput(feeCalc, changeOut) if err != nil { - return nil, nil, nil, fmt.Errorf("account for stakedOut fees: %w", err) + return nil, nil, nil, fmt.Errorf("account for output fees: %w", err) } if assetID != avaxAssetID { @@ -1231,3 +1172,39 @@ func (b *DynamicFeesBuilder) initCtx(tx txs.UnsignedTx) error { tx.InitCtx(ctx) return nil } + +func financeInput(feeCalc *fees.Calculator, input *avax.TransferableInput) (uint64, error) { + insDimensions, err := commonfees.GetInputsDimensions(txs.Codec, txs.CodecVersion, []*avax.TransferableInput{input}) + if err != nil { + return 0, fmt.Errorf("failed calculating input size: %w", err) + } + addedFees, err := feeCalc.AddFeesFor(insDimensions) + if err != nil { + return 0, fmt.Errorf("account for input fees: %w", err) + } + return addedFees, nil +} + +func financeOutput(feeCalc *fees.Calculator, output *avax.TransferableOutput) (uint64, error) { + outDimensions, err := commonfees.GetOutputsDimensions(txs.Codec, txs.CodecVersion, []*avax.TransferableOutput{output}) + if err != nil { + return 0, fmt.Errorf("failed calculating changeOut size: %w", err) + } + addedFees, err := feeCalc.AddFeesFor(outDimensions) + if err != nil { + return 0, fmt.Errorf("account for stakedOut fees: %w", err) + } + return addedFees, nil +} + +func financeCredential(feeCalc *fees.Calculator, inputSigIndices []uint32) (uint64, error) { + credsDimensions, err := commonfees.GetCredentialsDimensions(txs.Codec, txs.CodecVersion, inputSigIndices) + if err != nil { + return 0, fmt.Errorf("failed calculating input size: %w", err) + } + addedFees, err := feeCalc.AddFeesFor(credsDimensions) + if err != nil { + return 0, fmt.Errorf("account for input fees: %w", err) + } + return addedFees, nil +} From 8197e72a482a0bf38fb530dedd55c92a1061cdd2 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 29 Jan 2024 13:22:40 +0100 Subject: [PATCH 086/190] fixed e2e test to account for fees --- tests/e2e/p/staking_rewards.go | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/tests/e2e/p/staking_rewards.go b/tests/e2e/p/staking_rewards.go index 43b64456de96..c8fa4b032520 100644 --- a/tests/e2e/p/staking_rewards.go +++ b/tests/e2e/p/staking_rewards.go @@ -237,6 +237,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.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. @@ -290,13 +301,14 @@ 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]) } From 25b942460a0b7a81624e19c103f6c685f9710507 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 29 Jan 2024 13:50:14 +0100 Subject: [PATCH 087/190] reduced diffs --- vms/avm/txs/fees/calculator.go | 47 +++------- vms/platformvm/txs/fees/calculator.go | 123 +++++++------------------- 2 files changed, 44 insertions(+), 126 deletions(-) diff --git a/vms/avm/txs/fees/calculator.go b/vms/avm/txs/fees/calculator.go index dad73ae3607b..9d956486dec3 100644 --- a/vms/avm/txs/fees/calculator.go +++ b/vms/avm/txs/fees/calculator.go @@ -4,18 +4,13 @@ package fees import ( - "errors" "time" "github.com/ava-labs/avalanchego/vms/avm/config" "github.com/ava-labs/avalanchego/vms/avm/txs" ) -var ( - _ txs.Visitor = (*Calculator)(nil) - - errEForkFeesNotDefinedYet = errors.New("fees in E fork not defined yet") -) +var _ txs.Visitor = (*Calculator)(nil) type Calculator struct { // setup, to be filled before visitor methods are called @@ -27,46 +22,26 @@ type Calculator struct { } func (fc *Calculator) BaseTx(*txs.BaseTx) error { - if !fc.Config.IsEForkActivated(fc.ChainTime) { - fc.Fee = fc.Config.TxFee - return nil - } - - return errEForkFeesNotDefinedYet + fc.Fee = fc.Config.TxFee + return nil } func (fc *Calculator) CreateAssetTx(*txs.CreateAssetTx) error { - if !fc.Config.IsEForkActivated(fc.ChainTime) { - fc.Fee = fc.Config.CreateAssetTxFee - return nil - } - - return errEForkFeesNotDefinedYet + fc.Fee = fc.Config.CreateAssetTxFee + return nil } func (fc *Calculator) OperationTx(*txs.OperationTx) error { - if !fc.Config.IsEForkActivated(fc.ChainTime) { - fc.Fee = fc.Config.TxFee - return nil - } - - return errEForkFeesNotDefinedYet + fc.Fee = fc.Config.TxFee + return nil } func (fc *Calculator) ImportTx(*txs.ImportTx) error { - if !fc.Config.IsEForkActivated(fc.ChainTime) { - fc.Fee = fc.Config.TxFee - return nil - } - - return errEForkFeesNotDefinedYet + fc.Fee = fc.Config.TxFee + return nil } func (fc *Calculator) ExportTx(*txs.ExportTx) error { - if !fc.Config.IsEForkActivated(fc.ChainTime) { - fc.Fee = fc.Config.TxFee - return nil - } - - return errEForkFeesNotDefinedYet + fc.Fee = fc.Config.TxFee + return nil } diff --git a/vms/platformvm/txs/fees/calculator.go b/vms/platformvm/txs/fees/calculator.go index 5ee928102cb0..b35568d4229e 100644 --- a/vms/platformvm/txs/fees/calculator.go +++ b/vms/platformvm/txs/fees/calculator.go @@ -4,7 +4,6 @@ package fees import ( - "errors" "time" "github.com/ava-labs/avalanchego/utils/constants" @@ -12,11 +11,7 @@ import ( "github.com/ava-labs/avalanchego/vms/platformvm/txs" ) -var ( - _ txs.Visitor = (*Calculator)(nil) - - errEForkFeesNotDefinedYet = errors.New("fees in E fork not defined yet") -) +var _ txs.Visitor = (*Calculator)(nil) type Calculator struct { // setup, to be filled before visitor methods are called @@ -28,48 +23,28 @@ type Calculator struct { } func (fc *Calculator) AddValidatorTx(*txs.AddValidatorTx) error { - if !fc.Config.IsEForkActivated(fc.ChainTime) { - fc.Fee = fc.Config.AddPrimaryNetworkValidatorFee - return nil - } - - return errEForkFeesNotDefinedYet + fc.Fee = fc.Config.AddPrimaryNetworkValidatorFee + return nil } func (fc *Calculator) AddSubnetValidatorTx(*txs.AddSubnetValidatorTx) error { - if !fc.Config.IsEForkActivated(fc.ChainTime) { - fc.Fee = fc.Config.AddSubnetValidatorFee - return nil - } - - return errEForkFeesNotDefinedYet + fc.Fee = fc.Config.AddSubnetValidatorFee + return nil } func (fc *Calculator) AddDelegatorTx(*txs.AddDelegatorTx) error { - if !fc.Config.IsEForkActivated(fc.ChainTime) { - fc.Fee = fc.Config.AddPrimaryNetworkDelegatorFee - return nil - } - - return errEForkFeesNotDefinedYet + fc.Fee = fc.Config.AddPrimaryNetworkDelegatorFee + return nil } func (fc *Calculator) CreateChainTx(*txs.CreateChainTx) error { - if !fc.Config.IsEForkActivated(fc.ChainTime) { - fc.Fee = fc.Config.GetCreateBlockchainTxFee(fc.ChainTime) - return nil - } - - return errEForkFeesNotDefinedYet + fc.Fee = fc.Config.GetCreateBlockchainTxFee(fc.ChainTime) + return nil } func (fc *Calculator) CreateSubnetTx(*txs.CreateSubnetTx) error { - if !fc.Config.IsEForkActivated(fc.ChainTime) { - fc.Fee = fc.Config.GetCreateSubnetTxFee(fc.ChainTime) - return nil - } - - return errEForkFeesNotDefinedYet + fc.Fee = fc.Config.GetCreateSubnetTxFee(fc.ChainTime) + return nil } func (*Calculator) AdvanceTimeTx(*txs.AdvanceTimeTx) error { @@ -81,81 +56,49 @@ func (*Calculator) RewardValidatorTx(*txs.RewardValidatorTx) error { } func (fc *Calculator) RemoveSubnetValidatorTx(*txs.RemoveSubnetValidatorTx) error { - if !fc.Config.IsEForkActivated(fc.ChainTime) { - fc.Fee = fc.Config.TxFee - return nil - } - - return errEForkFeesNotDefinedYet + fc.Fee = fc.Config.TxFee + return nil } func (fc *Calculator) TransformSubnetTx(*txs.TransformSubnetTx) error { - if !fc.Config.IsEForkActivated(fc.ChainTime) { - fc.Fee = fc.Config.TransformSubnetTxFee - return nil - } - - return errEForkFeesNotDefinedYet + fc.Fee = fc.Config.TransformSubnetTxFee + return nil } func (fc *Calculator) TransferSubnetOwnershipTx(*txs.TransferSubnetOwnershipTx) error { - if !fc.Config.IsEForkActivated(fc.ChainTime) { - fc.Fee = fc.Config.TxFee - return nil - } - - return errEForkFeesNotDefinedYet + fc.Fee = fc.Config.TxFee + return nil } func (fc *Calculator) AddPermissionlessValidatorTx(tx *txs.AddPermissionlessValidatorTx) error { - if !fc.Config.IsEForkActivated(fc.ChainTime) { - if tx.Subnet != constants.PrimaryNetworkID { - fc.Fee = fc.Config.AddSubnetValidatorFee - } else { - fc.Fee = fc.Config.AddPrimaryNetworkValidatorFee - } - return nil + if tx.Subnet != constants.PrimaryNetworkID { + fc.Fee = fc.Config.AddSubnetValidatorFee + } else { + fc.Fee = fc.Config.AddPrimaryNetworkValidatorFee } - - return errEForkFeesNotDefinedYet + return nil } func (fc *Calculator) AddPermissionlessDelegatorTx(tx *txs.AddPermissionlessDelegatorTx) error { - if !fc.Config.IsEForkActivated(fc.ChainTime) { - if tx.Subnet != constants.PrimaryNetworkID { - fc.Fee = fc.Config.AddSubnetDelegatorFee - } else { - fc.Fee = fc.Config.AddPrimaryNetworkDelegatorFee - } - return nil + if tx.Subnet != constants.PrimaryNetworkID { + fc.Fee = fc.Config.AddSubnetDelegatorFee + } else { + fc.Fee = fc.Config.AddPrimaryNetworkDelegatorFee } - - return errEForkFeesNotDefinedYet + return nil } func (fc *Calculator) BaseTx(*txs.BaseTx) error { - if !fc.Config.IsEForkActivated(fc.ChainTime) { - fc.Fee = fc.Config.TxFee - return nil - } - - return errEForkFeesNotDefinedYet + fc.Fee = fc.Config.TxFee + return nil } func (fc *Calculator) ImportTx(*txs.ImportTx) error { - if !fc.Config.IsEForkActivated(fc.ChainTime) { - fc.Fee = fc.Config.TxFee - return nil - } - - return errEForkFeesNotDefinedYet + fc.Fee = fc.Config.TxFee + return nil } func (fc *Calculator) ExportTx(*txs.ExportTx) error { - if !fc.Config.IsEForkActivated(fc.ChainTime) { - fc.Fee = fc.Config.TxFee - return nil - } - - return errEForkFeesNotDefinedYet + fc.Fee = fc.Config.TxFee + return nil } From d28afdfa88799cc76ebc5da183c8dd01e5549366 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 29 Jan 2024 14:25:41 +0100 Subject: [PATCH 088/190] restored x-chain fee calculator --- vms/avm/block/executor/block.go | 22 +- vms/avm/block/executor/block_test.go | 49 +- vms/avm/block/executor/manager.go | 21 +- vms/avm/block/executor/manager_test.go | 10 + vms/avm/state/diff.go | 17 + vms/avm/state/mock_state.go | 119 ++++ vms/avm/state/state.go | 36 ++ vms/avm/txs/executor/syntactic_verifier.go | 48 +- vms/avm/txs/fees/calculator.go | 205 +++++- vms/avm/txs/fees/calculator_test.go | 698 +++++++++++++++++++++ vms/avm/vm.go | 19 +- 11 files changed, 1201 insertions(+), 43 deletions(-) create mode 100644 vms/avm/txs/fees/calculator_test.go diff --git a/vms/avm/block/executor/block.go b/vms/avm/block/executor/block.go index e49f1f482f8d..7874d199f55b 100644 --- a/vms/avm/block/executor/block.go +++ b/vms/avm/block/executor/block.go @@ -19,6 +19,7 @@ import ( "github.com/ava-labs/avalanchego/vms/avm/block" "github.com/ava-labs/avalanchego/vms/avm/state" "github.com/ava-labs/avalanchego/vms/avm/txs/executor" + "github.com/ava-labs/avalanchego/vms/components/fees" ) const SyncBound = 10 * time.Second @@ -74,12 +75,25 @@ func (b *Block) Verify(context.Context) error { } // Syntactic verification is generally pretty fast, so we verify this first - // before performing any possible DB reads. + // before performing any possible DB reads. TODO ABENEGIA: except we do DB reads now with fees stuff? + unitFees, err := b.manager.state.GetUnitFees() + if err != nil { + return err + } + + unitCaps, err := b.manager.state.GetBlockUnitCaps() + if err != nil { + return err + } + + feeManager := fees.NewManager(unitFees) for _, tx := range txs { err := tx.Unsigned.Visit(&executor.SyntacticVerifier{ - Backend: b.manager.backend, - BlkTimestamp: newChainTime, - Tx: tx, + Backend: b.manager.backend, + BlkFeeManager: feeManager, + UnitCaps: unitCaps, + BlkTimestamp: newChainTime, + Tx: tx, }) if err != nil { txID := tx.ID() diff --git a/vms/avm/block/executor/block_test.go b/vms/avm/block/executor/block_test.go index c44a69389568..5c8615639427 100644 --- a/vms/avm/block/executor/block_test.go +++ b/vms/avm/block/executor/block_test.go @@ -28,6 +28,7 @@ import ( "github.com/ava-labs/avalanchego/vms/avm/state" "github.com/ava-labs/avalanchego/vms/avm/txs" "github.com/ava-labs/avalanchego/vms/avm/txs/executor" + "github.com/ava-labs/avalanchego/vms/avm/txs/fees" "github.com/ava-labs/avalanchego/vms/avm/txs/mempool" ) @@ -149,6 +150,11 @@ func TestBlockVerify(t *testing.T) { mempool := mempool.NewMockMempool(ctrl) mempool.EXPECT().MarkDropped(errTx.ID(), errTest).Times(1) + + mockState := state.NewMockState(ctrl) + mockState.EXPECT().GetUnitFees().Return(fees.DefaultUnitFees, nil).AnyTimes() + mockState.EXPECT().GetBlockUnitCaps().Return(fees.DefaultBlockMaxConsumedUnits, nil).AnyTimes() + return &Block{ Block: mockBlock, manager: &manager{ @@ -158,6 +164,7 @@ func TestBlockVerify(t *testing.T) { EForkTime: mockable.MaxTime, }, }, + state: mockState, mempool: mempool, metrics: metrics.NewMockMetrics(ctrl), blkIDToState: map[ids.ID]*blockState{}, @@ -187,6 +194,9 @@ func TestBlockVerify(t *testing.T) { mockState := state.NewMockState(ctrl) mockState.EXPECT().GetBlock(parentID).Return(nil, errTest) + mockState.EXPECT().GetUnitFees().Return(fees.DefaultUnitFees, nil).AnyTimes() + mockState.EXPECT().GetBlockUnitCaps().Return(fees.DefaultBlockMaxConsumedUnits, nil).AnyTimes() + return &Block{ Block: mockBlock, manager: &manager{ @@ -224,10 +234,13 @@ func TestBlockVerify(t *testing.T) { parentID := ids.GenerateTestID() mockBlock.EXPECT().Parent().Return(parentID).AnyTimes() - mockState := state.NewMockState(ctrl) mockParentBlock := block.NewMockBlock(ctrl) mockParentBlock.EXPECT().Height().Return(blockHeight) // Should be blockHeight - 1 + + mockState := state.NewMockState(ctrl) mockState.EXPECT().GetBlock(parentID).Return(mockParentBlock, nil) + mockState.EXPECT().GetUnitFees().Return(fees.DefaultUnitFees, nil).AnyTimes() + mockState.EXPECT().GetBlockUnitCaps().Return(fees.DefaultBlockMaxConsumedUnits, nil).AnyTimes() return &Block{ Block: mockBlock, @@ -274,6 +287,10 @@ func TestBlockVerify(t *testing.T) { mockParentState.EXPECT().GetLastAccepted().Return(parentID) mockParentState.EXPECT().GetTimestamp().Return(blockTimestamp.Add(1)) + mockState := state.NewMockState(ctrl) + mockState.EXPECT().GetUnitFees().Return(fees.DefaultUnitFees, nil).AnyTimes() + mockState.EXPECT().GetBlockUnitCaps().Return(fees.DefaultBlockMaxConsumedUnits, nil).AnyTimes() + return &Block{ Block: mockBlock, manager: &manager{ @@ -283,6 +300,7 @@ func TestBlockVerify(t *testing.T) { EForkTime: mockable.MaxTime, }, }, + state: mockState, blkIDToState: map[ids.ID]*blockState{ parentID: { onAcceptState: mockParentState, @@ -325,6 +343,10 @@ func TestBlockVerify(t *testing.T) { mockParentState.EXPECT().GetLastAccepted().Return(parentID) mockParentState.EXPECT().GetTimestamp().Return(blockTimestamp) + mockState := state.NewMockState(ctrl) + mockState.EXPECT().GetUnitFees().Return(fees.DefaultUnitFees, nil).AnyTimes() + mockState.EXPECT().GetBlockUnitCaps().Return(fees.DefaultBlockMaxConsumedUnits, nil).AnyTimes() + mempool := mempool.NewMockMempool(ctrl) mempool.EXPECT().MarkDropped(tx.ID(), errTest).Times(1) return &Block{ @@ -336,6 +358,7 @@ func TestBlockVerify(t *testing.T) { EForkTime: mockable.MaxTime, }, }, + state: mockState, mempool: mempool, metrics: metrics.NewMockMetrics(ctrl), blkIDToState: map[ids.ID]*blockState{ @@ -381,6 +404,10 @@ func TestBlockVerify(t *testing.T) { mockParentState.EXPECT().GetLastAccepted().Return(parentID) mockParentState.EXPECT().GetTimestamp().Return(blockTimestamp) + mockState := state.NewMockState(ctrl) + mockState.EXPECT().GetUnitFees().Return(fees.DefaultUnitFees, nil).AnyTimes() + mockState.EXPECT().GetBlockUnitCaps().Return(fees.DefaultBlockMaxConsumedUnits, nil).AnyTimes() + mempool := mempool.NewMockMempool(ctrl) mempool.EXPECT().MarkDropped(tx.ID(), errTest).Times(1) return &Block{ @@ -394,6 +421,7 @@ func TestBlockVerify(t *testing.T) { EForkTime: mockable.MaxTime, }, }, + state: mockState, blkIDToState: map[ids.ID]*blockState{ parentID: { onAcceptState: mockParentState, @@ -464,6 +492,10 @@ func TestBlockVerify(t *testing.T) { mockParentState.EXPECT().GetLastAccepted().Return(parentID) mockParentState.EXPECT().GetTimestamp().Return(blockTimestamp) + mockState := state.NewMockState(ctrl) + mockState.EXPECT().GetUnitFees().Return(fees.DefaultUnitFees, nil).AnyTimes() + mockState.EXPECT().GetBlockUnitCaps().Return(fees.DefaultBlockMaxConsumedUnits, nil).AnyTimes() + mempool := mempool.NewMockMempool(ctrl) mempool.EXPECT().MarkDropped(tx2.ID(), ErrConflictingBlockTxs).Times(1) return &Block{ @@ -477,6 +509,7 @@ func TestBlockVerify(t *testing.T) { EForkTime: mockable.MaxTime, }, }, + state: mockState, blkIDToState: map[ids.ID]*blockState{ parentID: { onAcceptState: mockParentState, @@ -531,6 +564,10 @@ func TestBlockVerify(t *testing.T) { mockParentState.EXPECT().GetLastAccepted().Return(parentID) mockParentState.EXPECT().GetTimestamp().Return(blockTimestamp) + mockState := state.NewMockState(ctrl) + mockState.EXPECT().GetUnitFees().Return(fees.DefaultUnitFees, nil).AnyTimes() + mockState.EXPECT().GetBlockUnitCaps().Return(fees.DefaultBlockMaxConsumedUnits, nil).AnyTimes() + return &Block{ Block: mockBlock, manager: &manager{ @@ -540,6 +577,7 @@ func TestBlockVerify(t *testing.T) { EForkTime: mockable.MaxTime, }, }, + state: mockState, blkIDToState: map[ids.ID]*blockState{ parentID: { onAcceptState: mockParentState, @@ -584,6 +622,10 @@ func TestBlockVerify(t *testing.T) { mockParentState.EXPECT().GetLastAccepted().Return(parentID) mockParentState.EXPECT().GetTimestamp().Return(blockTimestamp) + mockState := state.NewMockState(ctrl) + mockState.EXPECT().GetUnitFees().Return(fees.DefaultUnitFees, nil).AnyTimes() + mockState.EXPECT().GetBlockUnitCaps().Return(fees.DefaultBlockMaxConsumedUnits, nil).AnyTimes() + mockMempool := mempool.NewMockMempool(ctrl) mockMempool.EXPECT().Remove([]*txs.Tx{tx}) return &Block{ @@ -597,6 +639,7 @@ func TestBlockVerify(t *testing.T) { EForkTime: mockable.MaxTime, }, }, + state: mockState, blkIDToState: map[ids.ID]*blockState{ parentID: { onAcceptState: mockParentState, @@ -959,6 +1002,8 @@ func TestBlockReject(t *testing.T) { mockState := state.NewMockState(ctrl) mockState.EXPECT().GetLastAccepted().Return(lastAcceptedID).AnyTimes() mockState.EXPECT().GetTimestamp().Return(time.Now()).AnyTimes() + mockState.EXPECT().GetUnitFees().Return(fees.DefaultUnitFees, nil).AnyTimes() + mockState.EXPECT().GetBlockUnitCaps().Return(fees.DefaultBlockMaxConsumedUnits, nil).AnyTimes() return &Block{ Block: mockBlock, @@ -1021,6 +1066,8 @@ func TestBlockReject(t *testing.T) { mockState := state.NewMockState(ctrl) mockState.EXPECT().GetLastAccepted().Return(lastAcceptedID).AnyTimes() mockState.EXPECT().GetTimestamp().Return(time.Now()).AnyTimes() + mockState.EXPECT().GetUnitFees().Return(fees.DefaultUnitFees, nil).AnyTimes() + mockState.EXPECT().GetBlockUnitCaps().Return(fees.DefaultBlockMaxConsumedUnits, nil).AnyTimes() return &Block{ Block: mockBlock, diff --git a/vms/avm/block/executor/manager.go b/vms/avm/block/executor/manager.go index a2a981c5185d..0f4cb6ba1bdd 100644 --- a/vms/avm/block/executor/manager.go +++ b/vms/avm/block/executor/manager.go @@ -17,6 +17,7 @@ import ( "github.com/ava-labs/avalanchego/vms/avm/txs" "github.com/ava-labs/avalanchego/vms/avm/txs/executor" "github.com/ava-labs/avalanchego/vms/avm/txs/mempool" + "github.com/ava-labs/avalanchego/vms/components/fees" ) var ( @@ -147,10 +148,22 @@ func (m *manager) VerifyTx(tx *txs.Tx) error { return ErrChainNotSynced } - err := tx.Unsigned.Visit(&executor.SyntacticVerifier{ - Backend: m.backend, - BlkTimestamp: m.state.GetTimestamp(), - Tx: tx, + unitFees, err := m.state.GetUnitFees() + if err != nil { + return err + } + + unitCaps, err := m.state.GetBlockUnitCaps() + if err != nil { + return err + } + + err = tx.Unsigned.Visit(&executor.SyntacticVerifier{ + Backend: m.backend, + BlkFeeManager: fees.NewManager(unitFees), + UnitCaps: unitCaps, + BlkTimestamp: m.state.GetTimestamp(), + Tx: tx, }) if err != nil { return err diff --git a/vms/avm/block/executor/manager_test.go b/vms/avm/block/executor/manager_test.go index de09f434d904..34012cb0264b 100644 --- a/vms/avm/block/executor/manager_test.go +++ b/vms/avm/block/executor/manager_test.go @@ -20,6 +20,7 @@ import ( "github.com/ava-labs/avalanchego/vms/avm/state" "github.com/ava-labs/avalanchego/vms/avm/txs" "github.com/ava-labs/avalanchego/vms/avm/txs/executor" + "github.com/ava-labs/avalanchego/vms/avm/txs/fees" ) var ( @@ -148,6 +149,9 @@ func TestManagerVerifyTx(t *testing.T) { managerF: func(ctrl *gomock.Controller) *manager { state := state.NewMockState(ctrl) state.EXPECT().GetTimestamp().Return(time.Time{}) + state.EXPECT().GetUnitFees().Return(fees.DefaultUnitFees, nil).AnyTimes() + state.EXPECT().GetBlockUnitCaps().Return(fees.DefaultBlockMaxConsumedUnits, nil).AnyTimes() + return &manager{ backend: &executor.Backend{ Bootstrapped: true, @@ -180,6 +184,8 @@ func TestManagerVerifyTx(t *testing.T) { state := state.NewMockState(ctrl) state.EXPECT().GetLastAccepted().Return(lastAcceptedID) state.EXPECT().GetTimestamp().Return(time.Time{}).Times(2) + state.EXPECT().GetUnitFees().Return(fees.DefaultUnitFees, nil).AnyTimes() + state.EXPECT().GetBlockUnitCaps().Return(fees.DefaultBlockMaxConsumedUnits, nil).AnyTimes() return &manager{ backend: &executor.Backend{ @@ -216,6 +222,8 @@ func TestManagerVerifyTx(t *testing.T) { state := state.NewMockState(ctrl) state.EXPECT().GetLastAccepted().Return(lastAcceptedID) state.EXPECT().GetTimestamp().Return(time.Time{}).Times(2) + state.EXPECT().GetUnitFees().Return(fees.DefaultUnitFees, nil).AnyTimes() + state.EXPECT().GetBlockUnitCaps().Return(fees.DefaultBlockMaxConsumedUnits, nil).AnyTimes() return &manager{ backend: &executor.Backend{ @@ -252,6 +260,8 @@ func TestManagerVerifyTx(t *testing.T) { state := state.NewMockState(ctrl) state.EXPECT().GetLastAccepted().Return(lastAcceptedID) state.EXPECT().GetTimestamp().Return(time.Time{}).Times(2) + state.EXPECT().GetUnitFees().Return(fees.DefaultUnitFees, nil).AnyTimes() + state.EXPECT().GetBlockUnitCaps().Return(fees.DefaultBlockMaxConsumedUnits, nil).AnyTimes() return &manager{ backend: &executor.Backend{ diff --git a/vms/avm/state/diff.go b/vms/avm/state/diff.go index 83e9c5e0d590..911bc1e1000f 100644 --- a/vms/avm/state/diff.go +++ b/vms/avm/state/diff.go @@ -13,6 +13,7 @@ import ( "github.com/ava-labs/avalanchego/vms/avm/block" "github.com/ava-labs/avalanchego/vms/avm/txs" "github.com/ava-labs/avalanchego/vms/components/avax" + commonfees "github.com/ava-labs/avalanchego/vms/components/fees" ) var ( @@ -161,6 +162,22 @@ func (d *diff) SetTimestamp(t time.Time) { d.timestamp = t } +func (d *diff) GetUnitFees() (commonfees.Dimensions, error) { + parentState, ok := d.stateVersions.GetState(d.parentID) + if !ok { + return commonfees.Dimensions{}, fmt.Errorf("%w: %s", ErrMissingParentState, d.parentID) + } + return parentState.GetUnitFees() +} + +func (d *diff) GetBlockUnitCaps() (commonfees.Dimensions, error) { + parentState, ok := d.stateVersions.GetState(d.parentID) + if !ok { + return commonfees.Dimensions{}, fmt.Errorf("%w: %s", ErrMissingParentState, d.parentID) + } + return parentState.GetBlockUnitCaps() +} + func (d *diff) Apply(state Chain) { for utxoID, utxo := range d.modifiedUTXOs { if utxo != nil { diff --git a/vms/avm/state/mock_state.go b/vms/avm/state/mock_state.go index cb5138c90369..5d281e470c73 100644 --- a/vms/avm/state/mock_state.go +++ b/vms/avm/state/mock_state.go @@ -20,6 +20,7 @@ import ( block "github.com/ava-labs/avalanchego/vms/avm/block" txs "github.com/ava-labs/avalanchego/vms/avm/txs" avax "github.com/ava-labs/avalanchego/vms/components/avax" + fees "github.com/ava-labs/avalanchego/vms/components/fees" gomock "go.uber.org/mock/gomock" ) @@ -124,6 +125,21 @@ func (mr *MockChainMockRecorder) GetBlockIDAtHeight(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBlockIDAtHeight", reflect.TypeOf((*MockChain)(nil).GetBlockIDAtHeight), arg0) } +// GetBlockUnitCaps mocks base method. +func (m *MockChain) GetBlockUnitCaps() (fees.Dimensions, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetBlockUnitCaps") + ret0, _ := ret[0].(fees.Dimensions) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetBlockUnitCaps indicates an expected call of GetBlockUnitCaps. +func (mr *MockChainMockRecorder) GetBlockUnitCaps() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBlockUnitCaps", reflect.TypeOf((*MockChain)(nil).GetBlockUnitCaps)) +} + // GetLastAccepted mocks base method. func (m *MockChain) GetLastAccepted() ids.ID { m.ctrl.T.Helper() @@ -182,6 +198,21 @@ func (mr *MockChainMockRecorder) GetUTXO(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUTXO", reflect.TypeOf((*MockChain)(nil).GetUTXO), arg0) } +// GetUnitFees mocks base method. +func (m *MockChain) GetUnitFees() (fees.Dimensions, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetUnitFees") + ret0, _ := ret[0].(fees.Dimensions) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetUnitFees indicates an expected call of GetUnitFees. +func (mr *MockChainMockRecorder) GetUnitFees() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUnitFees", reflect.TypeOf((*MockChain)(nil).GetUnitFees)) +} + // SetLastAccepted mocks base method. func (m *MockChain) SetLastAccepted(arg0 ids.ID) { m.ctrl.T.Helper() @@ -377,6 +408,21 @@ func (mr *MockStateMockRecorder) GetBlockIDAtHeight(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBlockIDAtHeight", reflect.TypeOf((*MockState)(nil).GetBlockIDAtHeight), arg0) } +// GetBlockUnitCaps mocks base method. +func (m *MockState) GetBlockUnitCaps() (fees.Dimensions, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetBlockUnitCaps") + ret0, _ := ret[0].(fees.Dimensions) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetBlockUnitCaps indicates an expected call of GetBlockUnitCaps. +func (mr *MockStateMockRecorder) GetBlockUnitCaps() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBlockUnitCaps", reflect.TypeOf((*MockState)(nil).GetBlockUnitCaps)) +} + // GetLastAccepted mocks base method. func (m *MockState) GetLastAccepted() ids.ID { m.ctrl.T.Helper() @@ -435,6 +481,21 @@ func (mr *MockStateMockRecorder) GetUTXO(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUTXO", reflect.TypeOf((*MockState)(nil).GetUTXO), arg0) } +// GetUnitFees mocks base method. +func (m *MockState) GetUnitFees() (fees.Dimensions, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetUnitFees") + ret0, _ := ret[0].(fees.Dimensions) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetUnitFees indicates an expected call of GetUnitFees. +func (mr *MockStateMockRecorder) GetUnitFees() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUnitFees", reflect.TypeOf((*MockState)(nil).GetUnitFees)) +} + // InitializeChainState mocks base method. func (m *MockState) InitializeChainState(arg0 ids.ID, arg1 time.Time) error { m.ctrl.T.Helper() @@ -478,6 +539,20 @@ func (mr *MockStateMockRecorder) Prune(arg0, arg1 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Prune", reflect.TypeOf((*MockState)(nil).Prune), arg0, arg1) } +// SetBlockUnitCaps mocks base method. +func (m *MockState) SetBlockUnitCaps(arg0 fees.Dimensions) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetBlockUnitCaps", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// SetBlockUnitCaps indicates an expected call of SetBlockUnitCaps. +func (mr *MockStateMockRecorder) SetBlockUnitCaps(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetBlockUnitCaps", reflect.TypeOf((*MockState)(nil).SetBlockUnitCaps), arg0) +} + // SetInitialized mocks base method. func (m *MockState) SetInitialized() error { m.ctrl.T.Helper() @@ -516,6 +591,20 @@ func (mr *MockStateMockRecorder) SetTimestamp(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetTimestamp", reflect.TypeOf((*MockState)(nil).SetTimestamp), arg0) } +// SetUnitFees mocks base method. +func (m *MockState) SetUnitFees(arg0 fees.Dimensions) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetUnitFees", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// SetUnitFees indicates an expected call of SetUnitFees. +func (mr *MockStateMockRecorder) SetUnitFees(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetUnitFees", reflect.TypeOf((*MockState)(nil).SetUnitFees), arg0) +} + // UTXOIDs mocks base method. func (m *MockState) UTXOIDs(arg0 []byte, arg1 ids.ID, arg2 int) ([]ids.ID, error) { m.ctrl.T.Helper() @@ -644,6 +733,21 @@ func (mr *MockDiffMockRecorder) GetBlockIDAtHeight(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBlockIDAtHeight", reflect.TypeOf((*MockDiff)(nil).GetBlockIDAtHeight), arg0) } +// GetBlockUnitCaps mocks base method. +func (m *MockDiff) GetBlockUnitCaps() (fees.Dimensions, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetBlockUnitCaps") + ret0, _ := ret[0].(fees.Dimensions) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetBlockUnitCaps indicates an expected call of GetBlockUnitCaps. +func (mr *MockDiffMockRecorder) GetBlockUnitCaps() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBlockUnitCaps", reflect.TypeOf((*MockDiff)(nil).GetBlockUnitCaps)) +} + // GetLastAccepted mocks base method. func (m *MockDiff) GetLastAccepted() ids.ID { m.ctrl.T.Helper() @@ -702,6 +806,21 @@ func (mr *MockDiffMockRecorder) GetUTXO(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUTXO", reflect.TypeOf((*MockDiff)(nil).GetUTXO), arg0) } +// GetUnitFees mocks base method. +func (m *MockDiff) GetUnitFees() (fees.Dimensions, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetUnitFees") + ret0, _ := ret[0].(fees.Dimensions) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetUnitFees indicates an expected call of GetUnitFees. +func (mr *MockDiffMockRecorder) GetUnitFees() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUnitFees", reflect.TypeOf((*MockDiff)(nil).GetUnitFees)) +} + // SetLastAccepted mocks base method. func (m *MockDiff) SetLastAccepted(arg0 ids.ID) { m.ctrl.T.Helper() diff --git a/vms/avm/state/state.go b/vms/avm/state/state.go index e85907d77a50..141abbd8343e 100644 --- a/vms/avm/state/state.go +++ b/vms/avm/state/state.go @@ -27,9 +27,11 @@ import ( "github.com/ava-labs/avalanchego/utils/timer" "github.com/ava-labs/avalanchego/vms/avm/block" "github.com/ava-labs/avalanchego/vms/avm/txs" + "github.com/ava-labs/avalanchego/vms/avm/txs/fees" "github.com/ava-labs/avalanchego/vms/components/avax" safemath "github.com/ava-labs/avalanchego/utils/math" + commonfees "github.com/ava-labs/avalanchego/vms/components/fees" ) const ( @@ -69,6 +71,10 @@ type ReadOnlyChain interface { GetBlock(blkID ids.ID) (block.Block, error) GetLastAccepted() ids.ID GetTimestamp() time.Time + + // at this iteration we don't need to reset these, we are just metering + GetUnitFees() (commonfees.Dimensions, error) + GetBlockUnitCaps() (commonfees.Dimensions, error) } type Chain interface { @@ -99,6 +105,10 @@ type State interface { // called during startup. InitializeChainState(stopVertexID ids.ID, genesisTimestamp time.Time) error + // At this iteration these getters are helpful for UTs only + SetUnitFees(uf commonfees.Dimensions) error + SetBlockUnitCaps(caps commonfees.Dimensions) error + // Discard uncommitted changes to the database. Abort() @@ -174,6 +184,11 @@ type state struct { timestamp, persistedTimestamp time.Time singletonDB database.Database + // multifees data are not persisted at this stage. We just meter for now, + // we'll revisit when we'll introduce dynamic fees + unitFees commonfees.Dimensions + blockUnitCaps commonfees.Dimensions + trackChecksum bool txChecksum ids.ID } @@ -257,6 +272,9 @@ func New( singletonDB: singletonDB, + unitFees: fees.DefaultUnitFees, + blockUnitCaps: fees.DefaultBlockMaxConsumedUnits, + trackChecksum: trackChecksums, } return s, s.initTxChecksum() @@ -501,6 +519,24 @@ func (s *state) SetTimestamp(t time.Time) { s.timestamp = t } +func (s *state) GetUnitFees() (commonfees.Dimensions, error) { + return s.unitFees, nil +} + +func (s *state) SetUnitFees(uf commonfees.Dimensions) error { + s.unitFees = uf + return nil +} + +func (s *state) GetBlockUnitCaps() (commonfees.Dimensions, error) { + return s.blockUnitCaps, nil +} + +func (s *state) SetBlockUnitCaps(caps commonfees.Dimensions) error { + s.blockUnitCaps = caps + return nil +} + func (s *state) Commit() error { defer s.Abort() batch, err := s.CommitBatch() diff --git a/vms/avm/txs/executor/syntactic_verifier.go b/vms/avm/txs/executor/syntactic_verifier.go index 2bb1fc6c5aa0..4a5f7c27853e 100644 --- a/vms/avm/txs/executor/syntactic_verifier.go +++ b/vms/avm/txs/executor/syntactic_verifier.go @@ -16,6 +16,8 @@ import ( "github.com/ava-labs/avalanchego/vms/avm/txs" "github.com/ava-labs/avalanchego/vms/avm/txs/fees" "github.com/ava-labs/avalanchego/vms/components/avax" + + commonFees "github.com/ava-labs/avalanchego/vms/components/fees" ) const ( @@ -49,8 +51,10 @@ var ( type SyntacticVerifier struct { *Backend - BlkTimestamp time.Time - Tx *txs.Tx + BlkFeeManager *commonFees.Manager + UnitCaps commonFees.Dimensions + BlkTimestamp time.Time + Tx *txs.Tx } func (v *SyntacticVerifier) BaseTx(tx *txs.BaseTx) error { @@ -59,8 +63,12 @@ func (v *SyntacticVerifier) BaseTx(tx *txs.BaseTx) error { } feeCalculator := fees.Calculator{ - Config: v.Config, - ChainTime: v.BlkTimestamp, + IsEForkActive: v.Config.IsEForkActivated(v.BlkTimestamp), + Config: v.Config, + Codec: v.Codec, + FeeManager: v.BlkFeeManager, + ConsumedUnitsCap: v.UnitCaps, + Credentials: v.Tx.Creds, } if err := tx.Visit(&feeCalculator); err != nil { return err @@ -130,8 +138,12 @@ func (v *SyntacticVerifier) CreateAssetTx(tx *txs.CreateAssetTx) error { } feeCalculator := fees.Calculator{ - Config: v.Config, - ChainTime: v.BlkTimestamp, + IsEForkActive: v.Config.IsEForkActivated(v.BlkTimestamp), + Config: v.Config, + Codec: v.Codec, + FeeManager: v.BlkFeeManager, + ConsumedUnitsCap: v.UnitCaps, + Credentials: v.Tx.Creds, } if err := tx.Visit(&feeCalculator); err != nil { return err @@ -186,8 +198,12 @@ func (v *SyntacticVerifier) OperationTx(tx *txs.OperationTx) error { } feeCalculator := fees.Calculator{ - Config: v.Config, - ChainTime: v.BlkTimestamp, + IsEForkActive: v.Config.IsEForkActivated(v.BlkTimestamp), + Config: v.Config, + Codec: v.Codec, + FeeManager: v.BlkFeeManager, + ConsumedUnitsCap: v.UnitCaps, + Credentials: v.Tx.Creds, } if err := tx.Visit(&feeCalculator); err != nil { return err @@ -254,8 +270,12 @@ func (v *SyntacticVerifier) ImportTx(tx *txs.ImportTx) error { } feeCalculator := fees.Calculator{ - Config: v.Config, - ChainTime: v.BlkTimestamp, + IsEForkActive: v.Config.IsEForkActivated(v.BlkTimestamp), + Config: v.Config, + Codec: v.Codec, + FeeManager: v.BlkFeeManager, + ConsumedUnitsCap: v.UnitCaps, + Credentials: v.Tx.Creds, } if err := tx.Visit(&feeCalculator); err != nil { return err @@ -304,8 +324,12 @@ func (v *SyntacticVerifier) ExportTx(tx *txs.ExportTx) error { } feeCalculator := fees.Calculator{ - Config: v.Config, - ChainTime: v.BlkTimestamp, + IsEForkActive: v.Config.IsEForkActivated(v.BlkTimestamp), + Config: v.Config, + Codec: v.Codec, + FeeManager: v.BlkFeeManager, + ConsumedUnitsCap: v.UnitCaps, + Credentials: v.Tx.Creds, } if err := tx.Visit(&feeCalculator); err != nil { return err diff --git a/vms/avm/txs/fees/calculator.go b/vms/avm/txs/fees/calculator.go index 9d956486dec3..cbfe74d1f14c 100644 --- a/vms/avm/txs/fees/calculator.go +++ b/vms/avm/txs/fees/calculator.go @@ -4,44 +4,211 @@ package fees import ( - "time" + "errors" + "fmt" + "math" + "github.com/ava-labs/avalanchego/codec" "github.com/ava-labs/avalanchego/vms/avm/config" + "github.com/ava-labs/avalanchego/vms/avm/fxs" "github.com/ava-labs/avalanchego/vms/avm/txs" + "github.com/ava-labs/avalanchego/vms/components/avax" + "github.com/ava-labs/avalanchego/vms/components/fees" ) -var _ txs.Visitor = (*Calculator)(nil) +var ( + _ txs.Visitor = (*Calculator)(nil) + + // These are the default unit fees, used upon E-fork activation + // TODO ABENEGIA: to be tuned + DefaultUnitFees = fees.Dimensions{ + 1, + 2, + 3, + 4, + } + + // These are the default caps for units consumed in a block, used upon E-fork activation + // TODO ABENEGIA: to be tuned + DefaultBlockMaxConsumedUnits = fees.Dimensions{ + math.MaxUint64, + math.MaxUint64, + math.MaxUint64, + math.MaxUint64, + } + + errFailedFeeCalculation = errors.New("failed fee calculation") + errFailedConsumedUnitsCumulation = errors.New("failed cumulating consumed units") +) type Calculator struct { // setup, to be filled before visitor methods are called - Config *config.Config - ChainTime time.Time + IsEForkActive bool + + // Pre E-fork inputs + Config *config.Config + Codec codec.Manager + // ChainTime time.Time + + // Post E-fork inputs + FeeManager *fees.Manager + ConsumedUnitsCap fees.Dimensions + + // inputs, to be filled before visitor methods are called + Credentials []*fxs.FxCredential // outputs of visitor execution Fee uint64 } -func (fc *Calculator) BaseTx(*txs.BaseTx) error { - fc.Fee = fc.Config.TxFee - return nil +func (fc *Calculator) BaseTx(tx *txs.BaseTx) error { + if !fc.IsEForkActive { + fc.Fee = fc.Config.TxFee + return nil + } + + consumedUnits, err := fc.commonConsumedUnits(tx, tx.Outs, tx.Ins) + if err != nil { + return err + } + + _, err = fc.AddFeesFor(consumedUnits) + return err } -func (fc *Calculator) CreateAssetTx(*txs.CreateAssetTx) error { - fc.Fee = fc.Config.CreateAssetTxFee - return nil +func (fc *Calculator) CreateAssetTx(tx *txs.CreateAssetTx) error { + if !fc.IsEForkActive { + fc.Fee = fc.Config.CreateAssetTxFee + return nil + } + + consumedUnits, err := fc.commonConsumedUnits(tx, tx.Outs, tx.Ins) + if err != nil { + return err + } + + _, err = fc.AddFeesFor(consumedUnits) + return err } -func (fc *Calculator) OperationTx(*txs.OperationTx) error { - fc.Fee = fc.Config.TxFee - return nil +func (fc *Calculator) OperationTx(tx *txs.OperationTx) error { + if !fc.IsEForkActive { + fc.Fee = fc.Config.TxFee + return nil + } + + consumedUnits, err := fc.commonConsumedUnits(tx, tx.Outs, tx.Ins) + if err != nil { + return err + } + + _, err = fc.AddFeesFor(consumedUnits) + return err } -func (fc *Calculator) ImportTx(*txs.ImportTx) error { - fc.Fee = fc.Config.TxFee - return nil +func (fc *Calculator) ImportTx(tx *txs.ImportTx) error { + if !fc.IsEForkActive { + fc.Fee = fc.Config.TxFee + return nil + } + + ins := make([]*avax.TransferableInput, len(tx.Ins)+len(tx.ImportedIns)) + copy(ins, tx.Ins) + copy(ins[len(tx.Ins):], tx.ImportedIns) + + consumedUnits, err := fc.commonConsumedUnits(tx, tx.Outs, ins) + if err != nil { + return err + } + + _, err = fc.AddFeesFor(consumedUnits) + return err } -func (fc *Calculator) ExportTx(*txs.ExportTx) error { - fc.Fee = fc.Config.TxFee - return nil +func (fc *Calculator) ExportTx(tx *txs.ExportTx) error { + if !fc.IsEForkActive { + fc.Fee = fc.Config.TxFee + return nil + } + + outs := make([]*avax.TransferableOutput, len(tx.Outs)+len(tx.ExportedOuts)) + copy(outs, tx.Outs) + copy(outs[len(tx.Outs):], tx.ExportedOuts) + + consumedUnits, err := fc.commonConsumedUnits(tx, outs, tx.Ins) + if err != nil { + return err + } + + _, err = fc.AddFeesFor(consumedUnits) + return err +} + +func (fc *Calculator) commonConsumedUnits( + uTx txs.UnsignedTx, + allOuts []*avax.TransferableOutput, + allIns []*avax.TransferableInput, +) (fees.Dimensions, error) { + var consumedUnits fees.Dimensions + + uTxSize, err := fc.Codec.Size(txs.CodecVersion, uTx) + if err != nil { + return consumedUnits, fmt.Errorf("couldn't calculate UnsignedTx marshal length: %w", err) + } + credsSize, err := fc.Codec.Size(txs.CodecVersion, fc.Credentials) + if err != nil { + return consumedUnits, fmt.Errorf("failed retrieving size of credentials: %w", err) + } + consumedUnits[fees.Bandwidth] = uint64(uTxSize + credsSize) + + inputDimensions, err := fees.GetInputsDimensions(fc.Codec, txs.CodecVersion, allIns) + if err != nil { + return consumedUnits, fmt.Errorf("failed retrieving size of inputs: %w", err) + } + inputDimensions[fees.Bandwidth] = 0 // inputs bandwidth is already accounted for above, so we zero it + consumedUnits, err = fees.Add(consumedUnits, inputDimensions) + if err != nil { + return consumedUnits, fmt.Errorf("failed adding inputs: %w", err) + } + + outputDimensions, err := fees.GetOutputsDimensions(fc.Codec, txs.CodecVersion, allOuts) + if err != nil { + return consumedUnits, fmt.Errorf("failed retrieving size of outputs: %w", err) + } + outputDimensions[fees.Bandwidth] = 0 // outputs bandwidth is already accounted for above, so we zero it + consumedUnits, err = fees.Add(consumedUnits, outputDimensions) + if err != nil { + return consumedUnits, fmt.Errorf("failed adding outputs: %w", err) + } + + return consumedUnits, nil +} + +func (fc *Calculator) AddFeesFor(consumedUnits fees.Dimensions) (uint64, error) { + boundBreached, dimension := fc.FeeManager.CumulateUnits(consumedUnits, fc.ConsumedUnitsCap) + if boundBreached { + return 0, fmt.Errorf("%w: breached dimension %d", errFailedConsumedUnitsCumulation, dimension) + } + + fee, err := fc.FeeManager.CalculateFee(consumedUnits) + if err != nil { + return 0, fmt.Errorf("%w: %w", errFailedFeeCalculation, err) + } + + fc.Fee += fee + return fee, nil +} + +func (fc *Calculator) RemoveFeesFor(unitsToRm fees.Dimensions) (uint64, error) { + if err := fc.FeeManager.RemoveUnits(unitsToRm); err != nil { + return 0, fmt.Errorf("failed removing units: %w", err) + } + + fee, err := fc.FeeManager.CalculateFee(unitsToRm) + if err != nil { + return 0, fmt.Errorf("%w: %w", errFailedFeeCalculation, err) + } + + fc.Fee -= fee + return fee, nil } diff --git a/vms/avm/txs/fees/calculator_test.go b/vms/avm/txs/fees/calculator_test.go new file mode 100644 index 000000000000..f2ccc7b3ccf5 --- /dev/null +++ b/vms/avm/txs/fees/calculator_test.go @@ -0,0 +1,698 @@ +// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package fees + +import ( + "reflect" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/ava-labs/avalanchego/codec" + "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/snow" + "github.com/ava-labs/avalanchego/snow/snowtest" + "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" + "github.com/ava-labs/avalanchego/utils/timer/mockable" + "github.com/ava-labs/avalanchego/utils/units" + "github.com/ava-labs/avalanchego/vms/avm/block" + "github.com/ava-labs/avalanchego/vms/avm/config" + "github.com/ava-labs/avalanchego/vms/avm/fxs" + "github.com/ava-labs/avalanchego/vms/avm/txs" + "github.com/ava-labs/avalanchego/vms/components/avax" + "github.com/ava-labs/avalanchego/vms/components/fees" + "github.com/ava-labs/avalanchego/vms/components/verify" + "github.com/ava-labs/avalanchego/vms/nftfx" + "github.com/ava-labs/avalanchego/vms/secp256k1fx" +) + +var ( + testUnitFees = fees.Dimensions{ + 1 * units.MicroAvax, + 2 * units.MicroAvax, + 3 * units.MicroAvax, + 4 * units.MicroAvax, + } + testBlockMaxConsumedUnits = fees.Dimensions{ + 3000, + 3500, + 1000, + 1000, + } + + feeTestsDefaultCfg = config.Config{ + TxFee: 1 * units.Avax, + CreateAssetTxFee: 2 * units.Avax, + } + + feeTestKeys = secp256k1.TestKeys() + feeTestSigners = [][]*secp256k1.PrivateKey{} + + durangoTime = time.Time{} // assume durango is active in these tests +) + +type feeTests struct { + description string + cfgAndChainTimeF func() (*config.Config, time.Time) + consumedUnitCapsF func() fees.Dimensions + expectedError error + checksF func(*testing.T, *Calculator) +} + +func TestBaseTxFees(t *testing.T) { + r := require.New(t) + + defaultCtx := snowtest.Context(t, snowtest.PChainID) + codec, err := createTestFeesCodec(defaultCtx) + r.NoError(err) + + baseTx, _ := txsCreationHelpers(defaultCtx) + uTx := &baseTx + sTx := &txs.Tx{ + Unsigned: uTx, + } + r.NoError(sTx.SignSECP256K1Fx(codec, feeTestSigners)) + + tests := []feeTests{ + { + description: "pre E fork", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(-1 * time.Second) + + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime + + return &cfg, chainTime + }, + expectedError: nil, + checksF: func(t *testing.T, fc *Calculator) { + require.Equal(t, fc.Config.TxFee, fc.Fee) + }, + }, + { + description: "post E fork, success", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(time.Second) + + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime + + return &cfg, chainTime + }, + expectedError: nil, + checksF: func(t *testing.T, fc *Calculator) { + require.Equal(t, 2920*units.MicroAvax, fc.Fee) + require.Equal(t, + fees.Dimensions{ + 224, + 1090, + 172, + 0, + }, + fc.FeeManager.GetCumulatedUnits(), + ) + }, + }, + { + description: "post E fork, utxos read cap breached", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(time.Second) + + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime + return &cfg, chainTime + }, + consumedUnitCapsF: func() fees.Dimensions { + caps := testBlockMaxConsumedUnits + caps[fees.UTXORead] = 1090 - 1 + return caps + }, + expectedError: errFailedConsumedUnitsCumulation, + checksF: func(t *testing.T, fc *Calculator) {}, + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + cfg, chainTime := tt.cfgAndChainTimeF() + + consumedUnitCaps := testBlockMaxConsumedUnits + if tt.consumedUnitCapsF != nil { + consumedUnitCaps = tt.consumedUnitCapsF() + } + + fc := &Calculator{ + IsEForkActive: cfg.IsEForkActivated(chainTime), + Config: cfg, + Codec: codec, + FeeManager: fees.NewManager(testUnitFees), + ConsumedUnitsCap: consumedUnitCaps, + Credentials: sTx.Creds, + } + err := uTx.Visit(fc) + r.ErrorIs(err, tt.expectedError) + tt.checksF(t, fc) + }) + } +} + +func TestCreateAssetTxFees(t *testing.T) { + r := require.New(t) + + defaultCtx := snowtest.Context(t, snowtest.PChainID) + codec, err := createTestFeesCodec(defaultCtx) + r.NoError(err) + + baseTx, _ := txsCreationHelpers(defaultCtx) + uTx := &txs.CreateAssetTx{ + BaseTx: baseTx, + Name: "name", + Symbol: "symb", + Denomination: 0, + States: []*txs.InitialState{ + { + FxIndex: 0, + Outs: []verify.State{ + &secp256k1fx.MintOutput{ + OutputOwners: secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{feeTestKeys[0].PublicKey().Address()}, + }, + }, + }, + }, + }, + } + sTx := &txs.Tx{ + Unsigned: uTx, + } + r.NoError(sTx.SignSECP256K1Fx(codec, feeTestSigners)) + + tests := []feeTests{ + { + description: "pre E fork", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(-1 * time.Second) + + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime + + return &cfg, chainTime + }, + expectedError: nil, + checksF: func(t *testing.T, fc *Calculator) { + require.Equal(t, fc.Config.CreateAssetTxFee, fc.Fee) + }, + }, + { + description: "post E fork, success", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(time.Second) + + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime + + return &cfg, chainTime + }, + expectedError: nil, + checksF: func(t *testing.T, fc *Calculator) { + require.Equal(t, 2985*units.MicroAvax, fc.Fee) + require.Equal(t, + fees.Dimensions{ + 289, + 1090, + 172, + 0, + }, + fc.FeeManager.GetCumulatedUnits(), + ) + }, + }, + { + description: "post E fork, bandwidth cap breached", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(time.Second) + + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime + return &cfg, chainTime + }, + consumedUnitCapsF: func() fees.Dimensions { + caps := testBlockMaxConsumedUnits + caps[fees.Bandwidth] = 289 - 1 + return caps + }, + expectedError: errFailedConsumedUnitsCumulation, + checksF: func(t *testing.T, fc *Calculator) {}, + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + cfg, chainTime := tt.cfgAndChainTimeF() + + consumedUnitCaps := testBlockMaxConsumedUnits + if tt.consumedUnitCapsF != nil { + consumedUnitCaps = tt.consumedUnitCapsF() + } + + fc := &Calculator{ + IsEForkActive: cfg.IsEForkActivated(chainTime), + Config: cfg, + Codec: codec, + FeeManager: fees.NewManager(testUnitFees), + ConsumedUnitsCap: consumedUnitCaps, + Credentials: sTx.Creds, + } + err := uTx.Visit(fc) + r.ErrorIs(err, tt.expectedError) + tt.checksF(t, fc) + }) + } +} + +func TestOperationTxFees(t *testing.T) { + r := require.New(t) + + defaultCtx := snowtest.Context(t, snowtest.PChainID) + codec, err := createTestFeesCodec(defaultCtx) + r.NoError(err) + + baseTx, _ := txsCreationHelpers(defaultCtx) + assetID := ids.GenerateTestID() + uTx := &txs.OperationTx{ + BaseTx: baseTx, + Ops: []*txs.Operation{{ + Asset: avax.Asset{ID: assetID}, + UTXOIDs: []*avax.UTXOID{{ + TxID: assetID, + OutputIndex: 1, + }}, + Op: &nftfx.MintOperation{ + MintInput: secp256k1fx.Input{ + SigIndices: []uint32{0}, + }, + GroupID: 1, + Payload: []byte{'h', 'e', 'l', 'l', 'o'}, + Outputs: []*secp256k1fx.OutputOwners{{}}, + }, + }}, + } + sTx := &txs.Tx{ + Unsigned: uTx, + } + r.NoError(sTx.SignSECP256K1Fx(codec, feeTestSigners)) + + tests := []feeTests{ + { + description: "pre E fork", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(-1 * time.Second) + + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime + + return &cfg, chainTime + }, + expectedError: nil, + checksF: func(t *testing.T, fc *Calculator) { + require.Equal(t, fc.Config.TxFee, fc.Fee) + }, + }, + { + description: "post E fork, success", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(time.Second) + + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime + + return &cfg, chainTime + }, + expectedError: nil, + checksF: func(t *testing.T, fc *Calculator) { + require.Equal(t, 3041*units.MicroAvax, fc.Fee) + require.Equal(t, + fees.Dimensions{ + 345, + 1090, + 172, + 0, + }, + fc.FeeManager.GetCumulatedUnits(), + ) + }, + }, + { + description: "post E fork, utxos read cap breached", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(time.Second) + + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime + return &cfg, chainTime + }, + consumedUnitCapsF: func() fees.Dimensions { + caps := testBlockMaxConsumedUnits + caps[fees.UTXORead] = 1090 - 1 + return caps + }, + expectedError: errFailedConsumedUnitsCumulation, + checksF: func(t *testing.T, fc *Calculator) {}, + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + cfg, chainTime := tt.cfgAndChainTimeF() + + consumedUnitCaps := testBlockMaxConsumedUnits + if tt.consumedUnitCapsF != nil { + consumedUnitCaps = tt.consumedUnitCapsF() + } + + fc := &Calculator{ + IsEForkActive: cfg.IsEForkActivated(chainTime), + Config: cfg, + Codec: codec, + FeeManager: fees.NewManager(testUnitFees), + ConsumedUnitsCap: consumedUnitCaps, + Credentials: sTx.Creds, + } + err := uTx.Visit(fc) + r.ErrorIs(err, tt.expectedError) + tt.checksF(t, fc) + }) + } +} + +func TestImportTxFees(t *testing.T) { + r := require.New(t) + + defaultCtx := snowtest.Context(t, snowtest.PChainID) + codec, err := createTestFeesCodec(defaultCtx) + r.NoError(err) + + baseTx, _ := txsCreationHelpers(defaultCtx) + uTx := &txs.ImportTx{ + BaseTx: baseTx, + SourceChain: ids.GenerateTestID(), + ImportedIns: []*avax.TransferableInput{{ + UTXOID: avax.UTXOID{ + TxID: ids.Empty.Prefix(1), + OutputIndex: 1, + }, + Asset: avax.Asset{ID: ids.ID{'a', 's', 's', 'e', 'r', 't'}}, + In: &secp256k1fx.TransferInput{ + Amt: 50000, + Input: secp256k1fx.Input{SigIndices: []uint32{0}}, + }, + }}, + } + sTx := &txs.Tx{ + Unsigned: uTx, + } + r.NoError(sTx.SignSECP256K1Fx(codec, feeTestSigners)) + + tests := []feeTests{ + { + description: "pre E fork", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(-1 * time.Second) + + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime + + return &cfg, chainTime + }, + expectedError: nil, + checksF: func(t *testing.T, fc *Calculator) { + require.Equal(t, fc.Config.TxFee, fc.Fee) + }, + }, + { + description: "post E fork, success", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(time.Second) + + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime + + return &cfg, chainTime + }, + expectedError: nil, + checksF: func(t *testing.T, fc *Calculator) { + require.Equal(t, 5494*units.MicroAvax, fc.Fee) + require.Equal(t, + fees.Dimensions{ + 348, + 2180, + 262, + 0, + }, + fc.FeeManager.GetCumulatedUnits(), + ) + }, + }, + { + description: "post E fork, utxos read cap breached", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(time.Second) + + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime + return &cfg, chainTime + }, + consumedUnitCapsF: func() fees.Dimensions { + caps := testBlockMaxConsumedUnits + caps[fees.UTXORead] = 1090 - 1 + return caps + }, + expectedError: errFailedConsumedUnitsCumulation, + checksF: func(t *testing.T, fc *Calculator) {}, + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + cfg, chainTime := tt.cfgAndChainTimeF() + + consumedUnitCaps := testBlockMaxConsumedUnits + if tt.consumedUnitCapsF != nil { + consumedUnitCaps = tt.consumedUnitCapsF() + } + + fc := &Calculator{ + IsEForkActive: cfg.IsEForkActivated(chainTime), + Config: cfg, + Codec: codec, + FeeManager: fees.NewManager(testUnitFees), + ConsumedUnitsCap: consumedUnitCaps, + Credentials: sTx.Creds, + } + err := uTx.Visit(fc) + r.ErrorIs(err, tt.expectedError) + tt.checksF(t, fc) + }) + } +} + +func TestExportTxFees(t *testing.T) { + r := require.New(t) + + defaultCtx := snowtest.Context(t, snowtest.PChainID) + codec, err := createTestFeesCodec(defaultCtx) + r.NoError(err) + + baseTx, outputs := txsCreationHelpers(defaultCtx) + uTx := &txs.ExportTx{ + BaseTx: baseTx, + DestinationChain: ids.GenerateTestID(), + ExportedOuts: outputs, + } + sTx := &txs.Tx{ + Unsigned: uTx, + } + r.NoError(sTx.SignSECP256K1Fx(codec, feeTestSigners)) + + tests := []feeTests{ + { + description: "pre E fork", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(-1 * time.Second) + + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime + + return &cfg, chainTime + }, + expectedError: nil, + checksF: func(t *testing.T, fc *Calculator) { + require.Equal(t, fc.Config.TxFee, fc.Fee) + }, + }, + { + description: "post E fork, success", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(time.Second) + + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime + + return &cfg, chainTime + }, + expectedError: nil, + checksF: func(t *testing.T, fc *Calculator) { + require.Equal(t, 3282*units.MicroAvax, fc.Fee) + require.Equal(t, + fees.Dimensions{ + 340, + 1090, + 254, + 0, + }, + fc.FeeManager.GetCumulatedUnits(), + ) + }, + }, + { + description: "post E fork, utxos read cap breached", + cfgAndChainTimeF: func() (*config.Config, time.Time) { + eForkTime := time.Now().Truncate(time.Second) + chainTime := eForkTime.Add(time.Second) + + cfg := feeTestsDefaultCfg + cfg.DurangoTime = durangoTime + cfg.EForkTime = eForkTime + return &cfg, chainTime + }, + consumedUnitCapsF: func() fees.Dimensions { + caps := testBlockMaxConsumedUnits + caps[fees.UTXORead] = 1090 - 1 + return caps + }, + expectedError: errFailedConsumedUnitsCumulation, + checksF: func(t *testing.T, fc *Calculator) {}, + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + cfg, chainTime := tt.cfgAndChainTimeF() + + consumedUnitCaps := testBlockMaxConsumedUnits + if tt.consumedUnitCapsF != nil { + consumedUnitCaps = tt.consumedUnitCapsF() + } + + fc := &Calculator{ + IsEForkActive: cfg.IsEForkActivated(chainTime), + Config: cfg, + Codec: codec, + FeeManager: fees.NewManager(testUnitFees), + ConsumedUnitsCap: consumedUnitCaps, + Credentials: sTx.Creds, + } + err := uTx.Visit(fc) + r.ErrorIs(err, tt.expectedError) + tt.checksF(t, fc) + }) + } +} + +func createTestFeesCodec(defaultCtx *snow.Context) (codec.Manager, error) { + fxs := []fxs.Fx{ + &secp256k1fx.Fx{}, + &nftfx.Fx{}, + } + + parser, err := block.NewCustomParser( + durangoTime, + map[reflect.Type]int{}, + &mockable.Clock{}, + defaultCtx.Log, + fxs, + ) + if err != nil { + return nil, err + } + + return parser.Codec(), nil +} + +func txsCreationHelpers(defaultCtx *snow.Context) ( + baseTx txs.BaseTx, + otherOutputs []*avax.TransferableOutput, +) { + inputs := []*avax.TransferableInput{{ + UTXOID: avax.UTXOID{ + TxID: ids.ID{'t', 'x', 'I', 'D'}, + OutputIndex: 2, + }, + Asset: avax.Asset{ID: defaultCtx.AVAXAssetID}, + In: &secp256k1fx.TransferInput{ + Amt: uint64(5678), + Input: secp256k1fx.Input{SigIndices: []uint32{0}}, + }, + }} + outputs := []*avax.TransferableOutput{{ + Asset: avax.Asset{ID: defaultCtx.AVAXAssetID}, + Out: &secp256k1fx.TransferOutput{ + Amt: uint64(1234), + OutputOwners: secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{feeTestKeys[0].PublicKey().Address()}, + }, + }, + }} + otherOutputs = []*avax.TransferableOutput{{ + Asset: avax.Asset{ID: defaultCtx.AVAXAssetID}, + Out: &secp256k1fx.TransferOutput{ + Amt: uint64(4567), + OutputOwners: secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{feeTestKeys[1].PublicKey().Address()}, + }, + }, + }} + baseTx = txs.BaseTx{ + BaseTx: avax.BaseTx{ + NetworkID: defaultCtx.NetworkID, + BlockchainID: defaultCtx.ChainID, + Ins: inputs, + Outs: outputs, + }, + } + + return baseTx, otherOutputs +} diff --git a/vms/avm/vm.go b/vms/avm/vm.go index 4926a0679f34..5bd1776b1ecf 100644 --- a/vms/avm/vm.go +++ b/vms/avm/vm.go @@ -42,6 +42,7 @@ import ( "github.com/ava-labs/avalanchego/vms/avm/txs/mempool" "github.com/ava-labs/avalanchego/vms/avm/utxo" "github.com/ava-labs/avalanchego/vms/components/avax" + "github.com/ava-labs/avalanchego/vms/components/fees" "github.com/ava-labs/avalanchego/vms/components/index" "github.com/ava-labs/avalanchego/vms/components/keystore" "github.com/ava-labs/avalanchego/vms/secp256k1fx" @@ -489,10 +490,22 @@ func (vm *VM) ParseTx(_ context.Context, bytes []byte) (snowstorm.Tx, error) { return nil, err } + unitFees, err := vm.state.GetUnitFees() + if err != nil { + return nil, err + } + + unitCaps, err := vm.state.GetBlockUnitCaps() + if err != nil { + return nil, err + } + err = tx.Unsigned.Visit(&txexecutor.SyntacticVerifier{ - Backend: vm.txBackend, - BlkTimestamp: vm.state.GetTimestamp(), - Tx: tx, + Backend: vm.txBackend, + BlkFeeManager: fees.NewManager(unitFees), + UnitCaps: unitCaps, + BlkTimestamp: vm.state.GetTimestamp(), + Tx: tx, }) if err != nil { return nil, err From ddce06a1d6e299f42031165b4e6fc61655aa4c76 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 29 Jan 2024 16:05:13 +0100 Subject: [PATCH 089/190] added dynamic fees builder for x-chain wallet --- scripts/mocks.mockgen.txt | 2 + vms/avm/txs/executor/syntactic_verifier.go | 10 +- vms/avm/txs/fees/calculator.go | 3 +- wallet/chain/x/builder_dynamic_fees.go | 581 +++++++++++++++++++ wallet/chain/x/builder_dynamic_fees_test.go | 477 +++++++++++++++ wallet/chain/x/mocks/mock_builder_backend.go | 127 ++++ wallet/chain/x/mocks/mock_signer_backend.go | 57 ++ 7 files changed, 1250 insertions(+), 7 deletions(-) create mode 100644 wallet/chain/x/builder_dynamic_fees.go create mode 100644 wallet/chain/x/builder_dynamic_fees_test.go create mode 100644 wallet/chain/x/mocks/mock_builder_backend.go create mode 100644 wallet/chain/x/mocks/mock_signer_backend.go diff --git a/scripts/mocks.mockgen.txt b/scripts/mocks.mockgen.txt index 701da0a02ac9..28f724234850 100644 --- a/scripts/mocks.mockgen.txt +++ b/scripts/mocks.mockgen.txt @@ -42,5 +42,7 @@ github.com/ava-labs/avalanchego/vms/registry=VMRegistry=vms/registry/mock_vm_reg github.com/ava-labs/avalanchego/vms=Factory,Manager=vms/mock_manager.go github.com/ava-labs/avalanchego/wallet/chain/p=BuilderBackend=wallet/chain/p/mocks/mock_builder_backend.go github.com/ava-labs/avalanchego/wallet/chain/p=SignerBackend=wallet/chain/p/mocks/mock_signer_backend.go +github.com/ava-labs/avalanchego/wallet/chain/x=BuilderBackend=wallet/chain/x/mocks/mock_builder_backend.go +github.com/ava-labs/avalanchego/wallet/chain/x=SignerBackend=wallet/chain/x/mocks/mock_signer_backend.go github.com/ava-labs/avalanchego/x/sync=Client=x/sync/mock_client.go github.com/ava-labs/avalanchego/x/sync=NetworkClient=x/sync/mock_network_client.go diff --git a/vms/avm/txs/executor/syntactic_verifier.go b/vms/avm/txs/executor/syntactic_verifier.go index 4a5f7c27853e..c19526309086 100644 --- a/vms/avm/txs/executor/syntactic_verifier.go +++ b/vms/avm/txs/executor/syntactic_verifier.go @@ -64,8 +64,8 @@ func (v *SyntacticVerifier) BaseTx(tx *txs.BaseTx) error { feeCalculator := fees.Calculator{ IsEForkActive: v.Config.IsEForkActivated(v.BlkTimestamp), - Config: v.Config, Codec: v.Codec, + Config: v.Config, FeeManager: v.BlkFeeManager, ConsumedUnitsCap: v.UnitCaps, Credentials: v.Tx.Creds, @@ -139,8 +139,8 @@ func (v *SyntacticVerifier) CreateAssetTx(tx *txs.CreateAssetTx) error { feeCalculator := fees.Calculator{ IsEForkActive: v.Config.IsEForkActivated(v.BlkTimestamp), - Config: v.Config, Codec: v.Codec, + Config: v.Config, FeeManager: v.BlkFeeManager, ConsumedUnitsCap: v.UnitCaps, Credentials: v.Tx.Creds, @@ -199,8 +199,8 @@ func (v *SyntacticVerifier) OperationTx(tx *txs.OperationTx) error { feeCalculator := fees.Calculator{ IsEForkActive: v.Config.IsEForkActivated(v.BlkTimestamp), - Config: v.Config, Codec: v.Codec, + Config: v.Config, FeeManager: v.BlkFeeManager, ConsumedUnitsCap: v.UnitCaps, Credentials: v.Tx.Creds, @@ -271,8 +271,8 @@ func (v *SyntacticVerifier) ImportTx(tx *txs.ImportTx) error { feeCalculator := fees.Calculator{ IsEForkActive: v.Config.IsEForkActivated(v.BlkTimestamp), - Config: v.Config, Codec: v.Codec, + Config: v.Config, FeeManager: v.BlkFeeManager, ConsumedUnitsCap: v.UnitCaps, Credentials: v.Tx.Creds, @@ -325,8 +325,8 @@ func (v *SyntacticVerifier) ExportTx(tx *txs.ExportTx) error { feeCalculator := fees.Calculator{ IsEForkActive: v.Config.IsEForkActivated(v.BlkTimestamp), - Config: v.Config, Codec: v.Codec, + Config: v.Config, FeeManager: v.BlkFeeManager, ConsumedUnitsCap: v.UnitCaps, Credentials: v.Tx.Creds, diff --git a/vms/avm/txs/fees/calculator.go b/vms/avm/txs/fees/calculator.go index cbfe74d1f14c..dffc194e4d13 100644 --- a/vms/avm/txs/fees/calculator.go +++ b/vms/avm/txs/fees/calculator.go @@ -44,11 +44,10 @@ var ( type Calculator struct { // setup, to be filled before visitor methods are called IsEForkActive bool + Codec codec.Manager // Pre E-fork inputs Config *config.Config - Codec codec.Manager - // ChainTime time.Time // Post E-fork inputs FeeManager *fees.Manager diff --git a/wallet/chain/x/builder_dynamic_fees.go b/wallet/chain/x/builder_dynamic_fees.go new file mode 100644 index 000000000000..ff7fc5d99547 --- /dev/null +++ b/wallet/chain/x/builder_dynamic_fees.go @@ -0,0 +1,581 @@ +// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package x + +import ( + "fmt" + + "golang.org/x/exp/slices" + + "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/utils" + "github.com/ava-labs/avalanchego/utils/constants" + "github.com/ava-labs/avalanchego/utils/math" + "github.com/ava-labs/avalanchego/utils/set" + "github.com/ava-labs/avalanchego/vms/avm/txs" + "github.com/ava-labs/avalanchego/vms/avm/txs/fees" + "github.com/ava-labs/avalanchego/vms/components/avax" + "github.com/ava-labs/avalanchego/vms/components/verify" + "github.com/ava-labs/avalanchego/vms/platformvm/stakeable" + "github.com/ava-labs/avalanchego/vms/secp256k1fx" + "github.com/ava-labs/avalanchego/wallet/subnet/primary/common" + + commonfees "github.com/ava-labs/avalanchego/vms/components/fees" +) + +type DynamicFeesBuilder struct { + addrs set.Set[ids.ShortID] + backend BuilderBackend +} + +func NewDynamicFeesBuilder(addrs set.Set[ids.ShortID], backend BuilderBackend) *DynamicFeesBuilder { + return &DynamicFeesBuilder{ + addrs: addrs, + backend: backend, + } +} + +func (b *DynamicFeesBuilder) NewBaseTx( + outputs []*avax.TransferableOutput, + unitFees, unitCaps commonfees.Dimensions, + options ...common.Option, +) (*txs.BaseTx, error) { + // 1. Build core transaction without utxos + ops := common.NewOptions(options) + + utx := &txs.BaseTx{ + BaseTx: avax.BaseTx{ + NetworkID: b.backend.NetworkID(), + BlockchainID: constants.PlatformChainID, + Memo: ops.Memo(), + Outs: outputs, // not sorted yet, we'll sort later on when we have all the outputs + }, + } + + // 2. Finance the tx by building the utxos (inputs, outputs and stakes) + toBurn := map[ids.ID]uint64{} // fees are calculated in financeTx + for _, out := range outputs { + assetID := out.AssetID() + amountToBurn, err := math.Add64(toBurn[assetID], out.Out.Amount()) + if err != nil { + return nil, err + } + toBurn[assetID] = amountToBurn + } + + feesMan := commonfees.NewManager(unitFees) + feeCalc := &fees.Calculator{ + IsEForkActive: true, + Codec: Parser.Codec(), + FeeManager: feesMan, + ConsumedUnitsCap: unitCaps, + } + + // feesMan cumulates consumed units. Let's init it with utx filled so far + if err := feeCalc.BaseTx(utx); err != nil { + return nil, err + } + + inputs, changeOuts, err := b.financeTx(toBurn, feeCalc, ops) + if err != nil { + return nil, err + } + + outputs = append(outputs, changeOuts...) + avax.SortTransferableOutputs(outputs, Parser.Codec()) + utx.Ins = inputs + utx.Outs = outputs + + return utx, b.initCtx(utx) +} + +func (b *DynamicFeesBuilder) NewCreateAssetTx( + name string, + symbol string, + denomination byte, + initialState map[uint32][]verify.State, + unitFees, unitCaps commonfees.Dimensions, + options ...common.Option, +) (*txs.CreateAssetTx, error) { + // 1. Build core transaction without utxos + ops := common.NewOptions(options) + codec := Parser.Codec() + states := make([]*txs.InitialState, 0, len(initialState)) + for fxIndex, outs := range initialState { + state := &txs.InitialState{ + FxIndex: fxIndex, + FxID: fxIndexToID[fxIndex], + Outs: outs, + } + state.Sort(codec) // sort the outputs + states = append(states, state) + } + + utils.Sort(states) // sort the initial states + + utx := &txs.CreateAssetTx{ + BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ + NetworkID: b.backend.NetworkID(), + BlockchainID: b.backend.BlockchainID(), + Memo: ops.Memo(), + }}, + Name: name, + Symbol: symbol, + Denomination: denomination, + States: states, + } + + // 2. Finance the tx by building the utxos (inputs, outputs and stakes) + toBurn := map[ids.ID]uint64{} // fees are calculated in financeTx + feesMan := commonfees.NewManager(unitFees) + feeCalc := &fees.Calculator{ + IsEForkActive: true, + Codec: Parser.Codec(), + FeeManager: feesMan, + ConsumedUnitsCap: unitCaps, + } + + // feesMan cumulates consumed units. Let's init it with utx filled so far + if err := feeCalc.CreateAssetTx(utx); err != nil { + return nil, err + } + + inputs, changeOuts, err := b.financeTx(toBurn, feeCalc, ops) + if err != nil { + return nil, err + } + + utx.Ins = inputs + utx.Outs = changeOuts + + return utx, b.initCtx(utx) +} + +func (b *DynamicFeesBuilder) NewImportTx( + sourceChainID ids.ID, + to *secp256k1fx.OutputOwners, + unitFees, unitCaps commonfees.Dimensions, + options ...common.Option, +) (*txs.ImportTx, error) { + ops := common.NewOptions(options) + // 1. Build core transaction + utx := &txs.ImportTx{ + BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ + NetworkID: b.backend.NetworkID(), + BlockchainID: constants.PlatformChainID, + Memo: ops.Memo(), + }}, + SourceChain: sourceChainID, + } + + // 2. Add imported inputs first + utxos, err := b.backend.UTXOs(ops.Context(), sourceChainID) + if err != nil { + return nil, err + } + + var ( + addrs = ops.Addresses(b.addrs) + minIssuanceTime = ops.MinIssuanceTime() + avaxAssetID = b.backend.AVAXAssetID() + + importedInputs = make([]*avax.TransferableInput, 0, len(utxos)) + importedSigIndices = make([][]uint32, 0) + importedAmounts = make(map[ids.ID]uint64) + ) + + for _, utxo := range utxos { + out, ok := utxo.Out.(*secp256k1fx.TransferOutput) + if !ok { + continue + } + + inputSigIndices, ok := common.MatchOwners(&out.OutputOwners, addrs, minIssuanceTime) + if !ok { + // We couldn't spend this UTXO, so we skip to the next one + continue + } + + importedInputs = append(importedInputs, &avax.TransferableInput{ + UTXOID: utxo.UTXOID, + Asset: utxo.Asset, + In: &secp256k1fx.TransferInput{ + Amt: out.Amt, + Input: secp256k1fx.Input{ + SigIndices: inputSigIndices, + }, + }, + }) + + assetID := utxo.AssetID() + newImportedAmount, err := math.Add64(importedAmounts[assetID], out.Amt) + if err != nil { + return nil, err + } + importedAmounts[assetID] = newImportedAmount + importedSigIndices = append(importedSigIndices, inputSigIndices) + } + if len(importedInputs) == 0 { + return nil, fmt.Errorf( + "%w: no UTXOs available to import", + errInsufficientFunds, + ) + } + + utils.Sort(importedInputs) // sort imported inputs + utx.ImportedIns = importedInputs + + // 3. Add an output for all non-avax denominated inputs. + for assetID, amount := range importedAmounts { + if assetID == avaxAssetID { + // Avax-denominated inputs may be used to fully or partially pay fees, + // so we'll handle them later on. + continue + } + + utx.Outs = append(utx.Outs, &avax.TransferableOutput{ + Asset: avax.Asset{ID: assetID}, + Out: &secp256k1fx.TransferOutput{ + Amt: amount, + OutputOwners: *to, + }, + }) // we'll sort them later on + } + + // 3. Finance fees as much as possible with imported, Avax-denominated UTXOs + feesMan := commonfees.NewManager(unitFees) + feeCalc := &fees.Calculator{ + IsEForkActive: true, + Codec: Parser.Codec(), + FeeManager: feesMan, + ConsumedUnitsCap: unitCaps, + } + + // feesMan cumulates consumed units. Let's init it with utx filled so far + if err := feeCalc.ImportTx(utx); err != nil { + return nil, err + } + + for _, sigIndices := range importedSigIndices { + if _, err = financeCredential(feeCalc, sigIndices); err != nil { + return nil, fmt.Errorf("account for credential fees: %w", err) + } + } + + switch importedAVAX := importedAmounts[avaxAssetID]; { + case importedAVAX == feeCalc.Fee: + // imported inputs match exactly the fees to be paid + avax.SortTransferableOutputs(utx.Outs, Parser.Codec()) // sort imported outputs + return utx, b.initCtx(utx) + + case importedAVAX < feeCalc.Fee: + // imported inputs can partially pay fees + feeCalc.Fee -= importedAmounts[avaxAssetID] + + default: + // imported inputs may be enough to pay taxes by themselves + changeOut := &avax.TransferableOutput{ + Asset: avax.Asset{ID: avaxAssetID}, + Out: &secp256k1fx.TransferOutput{ + OutputOwners: *to, // we set amount after considering own fees + }, + } + + // update fees to target given the extra output added + outDimensions, err := commonfees.GetOutputsDimensions(Parser.Codec(), txs.CodecVersion, []*avax.TransferableOutput{changeOut}) + if err != nil { + return nil, fmt.Errorf("failed calculating output size: %w", err) + } + if _, err := feeCalc.AddFeesFor(outDimensions); err != nil { + return nil, fmt.Errorf("account for output fees: %w", err) + } + + switch { + case feeCalc.Fee < importedAVAX: + changeOut.Out.(*secp256k1fx.TransferOutput).Amt = importedAVAX - feeCalc.Fee + utx.Outs = append(utx.Outs, changeOut) + avax.SortTransferableOutputs(utx.Outs, Parser.Codec()) // sort imported outputs + return utx, b.initCtx(utx) + + case feeCalc.Fee == importedAVAX: + // imported fees pays exactly the tx cost. We don't include the outputs + avax.SortTransferableOutputs(utx.Outs, Parser.Codec()) // sort imported outputs + return utx, b.initCtx(utx) + + default: + // imported avax are not enough to pay fees + // Drop the changeOut and finance the tx + if _, err := feeCalc.RemoveFeesFor(outDimensions); err != nil { + return nil, fmt.Errorf("failed reverting change output: %w", err) + } + feeCalc.Fee -= importedAVAX + } + } + + toBurn := map[ids.ID]uint64{} + inputs, changeOuts, err := b.financeTx(toBurn, feeCalc, ops) + if err != nil { + return nil, err + } + + utx.Ins = inputs + utx.Outs = append(utx.Outs, changeOuts...) + avax.SortTransferableOutputs(utx.Outs, Parser.Codec()) // sort imported outputs + return utx, b.initCtx(utx) +} + +func (b *DynamicFeesBuilder) NewExportTx( + chainID ids.ID, + outputs []*avax.TransferableOutput, + unitFees, unitCaps commonfees.Dimensions, + options ...common.Option, +) (*txs.ExportTx, error) { + // 1. Build core transaction without utxos + ops := common.NewOptions(options) + avax.SortTransferableOutputs(outputs, Parser.Codec()) // sort exported outputs + + utx := &txs.ExportTx{ + BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ + NetworkID: b.backend.NetworkID(), + BlockchainID: constants.PlatformChainID, + Memo: ops.Memo(), + }}, + DestinationChain: chainID, + ExportedOuts: outputs, + } + + // 2. Finance the tx by building the utxos (inputs, outputs and stakes) + toBurn := map[ids.ID]uint64{} // fees are calculated in financeTx + for _, out := range outputs { + assetID := out.AssetID() + amountToBurn, err := math.Add64(toBurn[assetID], out.Out.Amount()) + if err != nil { + return nil, err + } + toBurn[assetID] = amountToBurn + } + + feesMan := commonfees.NewManager(unitFees) + feeCalc := &fees.Calculator{ + IsEForkActive: true, + Codec: Parser.Codec(), + FeeManager: feesMan, + ConsumedUnitsCap: unitCaps, + } + + // feesMan cumulates consumed units. Let's init it with utx filled so far + if err := feeCalc.ExportTx(utx); err != nil { + return nil, err + } + + inputs, changeOuts, err := b.financeTx(toBurn, feeCalc, ops) + if err != nil { + return nil, err + } + + utx.Ins = inputs + utx.Outs = changeOuts + + return utx, b.initCtx(utx) +} + +func (b *DynamicFeesBuilder) financeTx( + amountsToBurn map[ids.ID]uint64, + feeCalc *fees.Calculator, + options *common.Options, +) ( + inputs []*avax.TransferableInput, + changeOutputs []*avax.TransferableOutput, + err error, +) { + avaxAssetID := b.backend.AVAXAssetID() + utxos, err := b.backend.UTXOs(options.Context(), constants.PlatformChainID) + if err != nil { + return nil, nil, err + } + + // we can only pay fees in avax, so we sort avax-denominated UTXOs last + // to maximize probability of being able to pay fees. + slices.SortFunc(utxos, func(lhs, rhs *avax.UTXO) int { + switch { + case lhs.Asset.AssetID() == avaxAssetID && rhs.Asset.AssetID() != avaxAssetID: + return 1 + case lhs.Asset.AssetID() != avaxAssetID && rhs.Asset.AssetID() == avaxAssetID: + return -1 + default: + return 0 + } + }) + + addrs := options.Addresses(b.addrs) + minIssuanceTime := options.MinIssuanceTime() + + addr, ok := addrs.Peek() + if !ok { + return nil, nil, errNoChangeAddress + } + changeOwner := options.ChangeOwner(&secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{addr}, + }) + + amountsToBurn[avaxAssetID] += feeCalc.Fee + + // Iterate over the unlocked UTXOs + for _, utxo := range utxos { + assetID := utxo.AssetID() + + // If we have consumed enough of the asset, then we have no need burn + // more. + if amountsToBurn[assetID] == 0 { + continue + } + + outIntf := utxo.Out + if lockedOut, ok := outIntf.(*stakeable.LockOut); ok { + if lockedOut.Locktime > minIssuanceTime { + // This output is currently locked, so this output can't be + // burned. + continue + } + outIntf = lockedOut.TransferableOut + } + + out, ok := outIntf.(*secp256k1fx.TransferOutput) + if !ok { + return nil, nil, errUnknownOutputType + } + + inputSigIndices, ok := common.MatchOwners(&out.OutputOwners, addrs, minIssuanceTime) + if !ok { + // We couldn't spend this UTXO, so we skip to the next one + continue + } + + input := &avax.TransferableInput{ + UTXOID: utxo.UTXOID, + Asset: utxo.Asset, + In: &secp256k1fx.TransferInput{ + Amt: out.Amt, + Input: secp256k1fx.Input{ + SigIndices: inputSigIndices, + }, + }, + } + + addedFees, err := financeInput(feeCalc, input) + if err != nil { + return nil, nil, fmt.Errorf("account for input fees: %w", err) + } + amountsToBurn[avaxAssetID] += addedFees + + addedFees, err = financeCredential(feeCalc, inputSigIndices) + if err != nil { + return nil, nil, fmt.Errorf("account for credential fees: %w", err) + } + amountsToBurn[avaxAssetID] += addedFees + + inputs = append(inputs, input) + + // Burn any value that should be burned + amountToBurn := math.Min( + amountsToBurn[assetID], // Amount we still need to burn + out.Amt, // Amount available to burn + ) + amountsToBurn[assetID] -= amountToBurn + + // Burn any value that should be burned + if remainingAmount := out.Amt - amountToBurn; remainingAmount > 0 { + // This input had extra value, so some of it must be returned, once fees are removed + changeOut := &avax.TransferableOutput{ + Asset: utxo.Asset, + Out: &secp256k1fx.TransferOutput{ + OutputOwners: *changeOwner, + }, + } + + // update fees to account for the change output + addedFees, err = financeOutput(feeCalc, changeOut) + if err != nil { + return nil, nil, fmt.Errorf("account for output fees: %w", err) + } + + if assetID != avaxAssetID { + changeOut.Out.(*secp256k1fx.TransferOutput).Amt = remainingAmount + amountsToBurn[avaxAssetID] += addedFees + changeOutputs = append(changeOutputs, changeOut) + } else { + // here assetID == b.backend.AVAXAssetID() + switch { + case addedFees < remainingAmount: + changeOut.Out.(*secp256k1fx.TransferOutput).Amt = remainingAmount - addedFees + changeOutputs = append(changeOutputs, changeOut) + case addedFees >= remainingAmount: + amountsToBurn[assetID] += addedFees - remainingAmount + } + } + } + } + + for assetID, amount := range amountsToBurn { + if amount != 0 { + return nil, nil, fmt.Errorf( + "%w: provided UTXOs need %d more units of asset %q", + errInsufficientFunds, + amount, + assetID, + ) + } + } + + utils.Sort(inputs) // sort inputs + avax.SortTransferableOutputs(changeOutputs, Parser.Codec()) // sort the change outputs + return inputs, changeOutputs, nil +} + +func (b *DynamicFeesBuilder) initCtx(tx txs.UnsignedTx) error { + ctx, err := newSnowContext(b.backend) + if err != nil { + return err + } + + tx.InitCtx(ctx) + return nil +} + +func financeInput(feeCalc *fees.Calculator, input *avax.TransferableInput) (uint64, error) { + insDimensions, err := commonfees.GetInputsDimensions(Parser.Codec(), txs.CodecVersion, []*avax.TransferableInput{input}) + if err != nil { + return 0, fmt.Errorf("failed calculating input size: %w", err) + } + addedFees, err := feeCalc.AddFeesFor(insDimensions) + if err != nil { + return 0, fmt.Errorf("account for input fees: %w", err) + } + return addedFees, nil +} + +func financeOutput(feeCalc *fees.Calculator, output *avax.TransferableOutput) (uint64, error) { + outDimensions, err := commonfees.GetOutputsDimensions(Parser.Codec(), txs.CodecVersion, []*avax.TransferableOutput{output}) + if err != nil { + return 0, fmt.Errorf("failed calculating changeOut size: %w", err) + } + addedFees, err := feeCalc.AddFeesFor(outDimensions) + if err != nil { + return 0, fmt.Errorf("account for stakedOut fees: %w", err) + } + return addedFees, nil +} + +func financeCredential(feeCalc *fees.Calculator, inputSigIndices []uint32) (uint64, error) { + credsDimensions, err := commonfees.GetCredentialsDimensions(Parser.Codec(), txs.CodecVersion, inputSigIndices) + if err != nil { + return 0, fmt.Errorf("failed calculating input size: %w", err) + } + addedFees, err := feeCalc.AddFeesFor(credsDimensions) + if err != nil { + return 0, fmt.Errorf("account for input fees: %w", err) + } + return addedFees, nil +} diff --git a/wallet/chain/x/builder_dynamic_fees_test.go b/wallet/chain/x/builder_dynamic_fees_test.go new file mode 100644 index 000000000000..51936e002515 --- /dev/null +++ b/wallet/chain/x/builder_dynamic_fees_test.go @@ -0,0 +1,477 @@ +// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package x + +import ( + stdcontext "context" + "math" + "testing" + "time" + + "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" + + "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/utils/constants" + "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" + "github.com/ava-labs/avalanchego/utils/set" + "github.com/ava-labs/avalanchego/utils/units" + "github.com/ava-labs/avalanchego/vms/avm/txs/fees" + "github.com/ava-labs/avalanchego/vms/components/avax" + "github.com/ava-labs/avalanchego/vms/components/verify" + "github.com/ava-labs/avalanchego/vms/nftfx" + "github.com/ava-labs/avalanchego/vms/platformvm/stakeable" + "github.com/ava-labs/avalanchego/vms/propertyfx" + "github.com/ava-labs/avalanchego/vms/secp256k1fx" + "github.com/ava-labs/avalanchego/wallet/chain/x/mocks" + + commonfees "github.com/ava-labs/avalanchego/vms/components/fees" +) + +var ( + testKeys = secp256k1.TestKeys() + testUnitFees = commonfees.Dimensions{ + 1 * units.MicroAvax, + 2 * units.MicroAvax, + 3 * units.MicroAvax, + 4 * units.MicroAvax, + } + testBlockMaxConsumedUnits = commonfees.Dimensions{ + math.MaxUint64, + math.MaxUint64, + math.MaxUint64, + math.MaxUint64, + } +) + +// These tests create and sign a tx, then verify that utxos included +// in the tx are exactly necessary to pay fees for it + +func TestBaseTx(t *testing.T) { + require := require.New(t) + ctrl := gomock.NewController(t) + + be := mocks.NewMockBuilderBackend(ctrl) + + var ( + utxosKey = testKeys[1] + utxoAddr = utxosKey.PublicKey().Address() + utxos, avaxAssetID, _ = testUTXOsList(utxosKey) + + outputsToMove = []*avax.TransferableOutput{{ + Asset: avax.Asset{ID: avaxAssetID}, + Out: &secp256k1fx.TransferOutput{ + Amt: 7 * units.Avax, + OutputOwners: secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{utxosKey.PublicKey().Address()}, + }, + }, + }} + ) + + b := &DynamicFeesBuilder{ + addrs: set.Of(utxoAddr), + backend: be, + } + + be.EXPECT().AVAXAssetID().Return(avaxAssetID).AnyTimes() + be.EXPECT().NetworkID().Return(constants.MainnetID).AnyTimes() + be.EXPECT().BlockchainID().Return(constants.PlatformChainID) + be.EXPECT().UTXOs(gomock.Any(), constants.PlatformChainID).Return(utxos, nil) + + utx, err := b.NewBaseTx( + outputsToMove, + testUnitFees, + testBlockMaxConsumedUnits, + ) + require.NoError(err) + + var ( + kc = secp256k1fx.NewKeychain(utxosKey) + sbe = mocks.NewMockSignerBackend(ctrl) + s = NewSigner(kc, sbe) + ) + + for _, utxo := range utxos { + sbe.EXPECT().GetUTXO(gomock.Any(), gomock.Any(), utxo.InputID()).Return(utxo, nil).AnyTimes() + } + + tx, err := s.SignUnsigned(stdcontext.Background(), utx) + require.NoError(err) + + fc := &fees.Calculator{ + IsEForkActive: true, + Codec: Parser.Codec(), + FeeManager: commonfees.NewManager(testUnitFees), + ConsumedUnitsCap: testBlockMaxConsumedUnits, + Credentials: tx.Creds, + } + require.NoError(utx.Visit(fc)) + require.Equal(5930*units.MicroAvax, fc.Fee) + + ins := utx.Ins + outs := utx.Outs + require.Len(ins, 2) + require.Len(outs, 2) + require.Equal(fc.Fee+outputsToMove[0].Out.Amount(), ins[0].In.Amount()+ins[1].In.Amount()-outs[0].Out.Amount()) + require.Equal(outputsToMove[0], outs[1]) +} + +func TestCreateAssetTx(t *testing.T) { + require := require.New(t) + ctrl := gomock.NewController(t) + + be := mocks.NewMockBuilderBackend(ctrl) + + var ( + utxosKey = testKeys[1] + utxoAddr = utxosKey.PublicKey().Address() + utxos, avaxAssetID, _ = testUTXOsList(utxosKey) + + assetName = "Team Rocket" + symbol = "TR" + denomination uint8 = 0 + initialState = map[uint32][]verify.State{ + 0: { + &secp256k1fx.MintOutput{ + OutputOwners: secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{testKeys[0].PublicKey().Address()}, + }, + }, &secp256k1fx.MintOutput{ + OutputOwners: secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{testKeys[0].PublicKey().Address()}, + }, + }, + }, + 1: { + &nftfx.MintOutput{ + GroupID: 1, + OutputOwners: secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{testKeys[1].PublicKey().Address()}, + }, + }, + &nftfx.MintOutput{ + GroupID: 2, + OutputOwners: secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{testKeys[1].PublicKey().Address()}, + }, + }, + }, + 2: { + &propertyfx.MintOutput{ + OutputOwners: secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{testKeys[2].PublicKey().Address()}, + }, + }, + &propertyfx.MintOutput{ + OutputOwners: secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{testKeys[2].PublicKey().Address()}, + }, + }, + }, + } + ) + + b := &DynamicFeesBuilder{ + addrs: set.Of(utxoAddr), + backend: be, + } + + be.EXPECT().AVAXAssetID().Return(avaxAssetID).AnyTimes() + be.EXPECT().NetworkID().Return(constants.MainnetID).AnyTimes() + be.EXPECT().BlockchainID().Return(constants.PlatformChainID).AnyTimes() + be.EXPECT().UTXOs(gomock.Any(), constants.PlatformChainID).Return(utxos, nil) + + utx, err := b.NewCreateAssetTx( + assetName, + symbol, + denomination, + initialState, + testUnitFees, + testBlockMaxConsumedUnits, + ) + require.NoError(err) + + var ( + kc = secp256k1fx.NewKeychain(utxosKey) + sbe = mocks.NewMockSignerBackend(ctrl) + s = NewSigner(kc, sbe) + ) + + for _, utxo := range utxos { + sbe.EXPECT().GetUTXO(gomock.Any(), gomock.Any(), utxo.InputID()).Return(utxo, nil).AnyTimes() + } + + tx, err := s.SignUnsigned(stdcontext.Background(), utx) + require.NoError(err) + + fc := &fees.Calculator{ + IsEForkActive: true, + Codec: Parser.Codec(), + FeeManager: commonfees.NewManager(testUnitFees), + ConsumedUnitsCap: testBlockMaxConsumedUnits, + Credentials: tx.Creds, + } + require.NoError(utx.Visit(fc)) + require.Equal(5898*units.MicroAvax, fc.Fee) + + ins := utx.Ins + outs := utx.Outs + require.Len(ins, 2) + require.Len(outs, 1) + require.Equal(fc.Fee, ins[0].In.Amount()+ins[1].In.Amount()-outs[0].Out.Amount()) +} + +func TestImportTx(t *testing.T) { + require := require.New(t) + ctrl := gomock.NewController(t) + + be := mocks.NewMockBuilderBackend(ctrl) + + var ( + utxosKey = testKeys[1] + utxoAddr = utxosKey.PublicKey().Address() + sourceChainID = ids.GenerateTestID() + utxos, avaxAssetID, _ = testUTXOsList(utxosKey) + + importKey = testKeys[0] + importTo = &secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{ + importKey.Address(), + }, + } + ) + + importedUtxo := utxos[0] + utxos = utxos[1:] + + b := &DynamicFeesBuilder{ + addrs: set.Of(utxoAddr), + backend: be, + } + be.EXPECT().AVAXAssetID().Return(avaxAssetID).AnyTimes() + be.EXPECT().NetworkID().Return(constants.MainnetID).AnyTimes() + be.EXPECT().BlockchainID().Return(constants.PlatformChainID).AnyTimes() + be.EXPECT().UTXOs(gomock.Any(), sourceChainID).Return([]*avax.UTXO{importedUtxo}, nil) + be.EXPECT().UTXOs(gomock.Any(), constants.PlatformChainID).Return(utxos, nil) + + utx, err := b.NewImportTx( + sourceChainID, + importTo, + testUnitFees, + testBlockMaxConsumedUnits, + ) + require.NoError(err) + + var ( + kc = secp256k1fx.NewKeychain(utxosKey) + sbe = mocks.NewMockSignerBackend(ctrl) + s = NewSigner(kc, sbe) + ) + + sbe.EXPECT().GetUTXO(gomock.Any(), gomock.Any(), importedUtxo.InputID()).Return(importedUtxo, nil).AnyTimes() + for _, utxo := range utxos { + sbe.EXPECT().GetUTXO(gomock.Any(), gomock.Any(), utxo.InputID()).Return(utxo, nil).AnyTimes() + } + + tx, err := s.SignUnsigned(stdcontext.Background(), utx) + require.NoError(err) + + fc := &fees.Calculator{ + IsEForkActive: true, + Codec: Parser.Codec(), + FeeManager: commonfees.NewManager(testUnitFees), + ConsumedUnitsCap: testBlockMaxConsumedUnits, + Credentials: tx.Creds, + } + require.NoError(utx.Visit(fc)) + require.Equal(5640*units.MicroAvax, fc.Fee) + + ins := utx.Ins + outs := utx.Outs + importedIns := utx.ImportedIns + require.Len(ins, 1) + require.Len(importedIns, 1) + require.Len(outs, 1) + require.Equal(fc.Fee, importedIns[0].In.Amount()+ins[0].In.Amount()-outs[0].Out.Amount()) +} + +func TestExportTx(t *testing.T) { + require := require.New(t) + ctrl := gomock.NewController(t) + + be := mocks.NewMockBuilderBackend(ctrl) + + var ( + utxosKey = testKeys[1] + utxoAddr = utxosKey.PublicKey().Address() + subnetID = ids.GenerateTestID() + utxos, avaxAssetID, _ = testUTXOsList(utxosKey) + + exportedOutputs = []*avax.TransferableOutput{{ + Asset: avax.Asset{ID: avaxAssetID}, + Out: &secp256k1fx.TransferOutput{ + Amt: 7 * units.Avax, + OutputOwners: secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{utxosKey.PublicKey().Address()}, + }, + }, + }} + ) + + b := &DynamicFeesBuilder{ + addrs: set.Of(utxoAddr), + backend: be, + } + be.EXPECT().AVAXAssetID().Return(avaxAssetID).AnyTimes() + be.EXPECT().NetworkID().Return(constants.MainnetID).AnyTimes() + be.EXPECT().BlockchainID().Return(constants.PlatformChainID) + be.EXPECT().UTXOs(gomock.Any(), constants.PlatformChainID).Return(utxos, nil) + + utx, err := b.NewExportTx( + subnetID, + exportedOutputs, + testUnitFees, + testBlockMaxConsumedUnits, + ) + require.NoError(err) + + var ( + kc = secp256k1fx.NewKeychain(utxosKey) + sbe = mocks.NewMockSignerBackend(ctrl) + s = NewSigner(kc, sbe) + ) + + for _, utxo := range utxos { + sbe.EXPECT().GetUTXO(gomock.Any(), gomock.Any(), utxo.InputID()).Return(utxo, nil).AnyTimes() + } + + tx, err := s.SignUnsigned(stdcontext.Background(), utx) + require.NoError(err) + + fc := &fees.Calculator{ + IsEForkActive: true, + Codec: Parser.Codec(), + FeeManager: commonfees.NewManager(testUnitFees), + ConsumedUnitsCap: testBlockMaxConsumedUnits, + Credentials: tx.Creds, + } + require.NoError(utx.Visit(fc)) + require.Equal(5966*units.MicroAvax, fc.Fee) + + ins := utx.Ins + outs := utx.Outs + require.Len(ins, 2) + require.Len(outs, 1) + require.Equal(fc.Fee+exportedOutputs[0].Out.Amount(), ins[0].In.Amount()+ins[1].In.Amount()-outs[0].Out.Amount()) + require.Equal(utx.ExportedOuts, exportedOutputs) +} + +func testUTXOsList(utxosKey *secp256k1.PrivateKey) ( + []*avax.UTXO, + ids.ID, // avaxAssetID, + ids.ID, // subnetAssetID +) { + // Note: we avoid ids.GenerateTestNodeID here to make sure that UTXO IDs won't change + // run by run. This simplifies checking what utxos are included in the built txs. + utxosOffset := uint64(2024) + + var ( + avaxAssetID = ids.Empty.Prefix(utxosOffset) + subnetAssetID = ids.Empty.Prefix(utxosOffset + 1) + ) + + return []*avax.UTXO{ // currently, the wallet scans UTXOs in the order provided here + { // a small UTXO first, which should not be enough to pay fees + UTXOID: avax.UTXOID{ + TxID: ids.Empty.Prefix(utxosOffset), + OutputIndex: uint32(utxosOffset), + }, + Asset: avax.Asset{ID: avaxAssetID}, + Out: &secp256k1fx.TransferOutput{ + Amt: 2 * units.MilliAvax, + OutputOwners: secp256k1fx.OutputOwners{ + Locktime: 0, + Addrs: []ids.ShortID{utxosKey.PublicKey().Address()}, + Threshold: 1, + }, + }, + }, + { // a locked, small UTXO + UTXOID: avax.UTXOID{ + TxID: ids.Empty.Prefix(utxosOffset + 1), + OutputIndex: uint32(utxosOffset + 1), + }, + Asset: avax.Asset{ID: avaxAssetID}, + Out: &stakeable.LockOut{ + Locktime: uint64(time.Now().Add(time.Hour).Unix()), + TransferableOut: &secp256k1fx.TransferOutput{ + Amt: 3 * units.MilliAvax, + OutputOwners: secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{utxosKey.PublicKey().Address()}, + }, + }, + }, + }, + { // a subnetAssetID denominated UTXO + UTXOID: avax.UTXOID{ + TxID: ids.Empty.Prefix(utxosOffset + 2), + OutputIndex: uint32(utxosOffset + 2), + }, + Asset: avax.Asset{ID: subnetAssetID}, + Out: &secp256k1fx.TransferOutput{ + Amt: 99 * units.MegaAvax, + OutputOwners: secp256k1fx.OutputOwners{ + Locktime: 0, + Addrs: []ids.ShortID{utxosKey.PublicKey().Address()}, + Threshold: 1, + }, + }, + }, + { // a locked, large UTXO + UTXOID: avax.UTXOID{ + TxID: ids.Empty.Prefix(utxosOffset + 3), + OutputIndex: uint32(utxosOffset + 3), + }, + Asset: avax.Asset{ID: avaxAssetID}, + Out: &stakeable.LockOut{ + Locktime: uint64(time.Now().Add(time.Hour).Unix()), + TransferableOut: &secp256k1fx.TransferOutput{ + Amt: 88 * units.Avax, + OutputOwners: secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{utxosKey.PublicKey().Address()}, + }, + }, + }, + }, + { // a large UTXO last, which should be enough to pay any fee by itself + UTXOID: avax.UTXOID{ + TxID: ids.Empty.Prefix(utxosOffset + 4), + OutputIndex: uint32(utxosOffset + 4), + }, + Asset: avax.Asset{ID: avaxAssetID}, + Out: &secp256k1fx.TransferOutput{ + Amt: 9 * units.Avax, + OutputOwners: secp256k1fx.OutputOwners{ + Locktime: 0, + Addrs: []ids.ShortID{utxosKey.PublicKey().Address()}, + Threshold: 1, + }, + }, + }, + }, + avaxAssetID, + subnetAssetID +} diff --git a/wallet/chain/x/mocks/mock_builder_backend.go b/wallet/chain/x/mocks/mock_builder_backend.go new file mode 100644 index 000000000000..9e2a047ae7d1 --- /dev/null +++ b/wallet/chain/x/mocks/mock_builder_backend.go @@ -0,0 +1,127 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/ava-labs/avalanchego/wallet/chain/x (interfaces: BuilderBackend) +// +// Generated by this command: +// +// mockgen -package=mocks -destination=wallet/chain/x/mocks/mock_builder_backend.go github.com/ava-labs/avalanchego/wallet/chain/x BuilderBackend +// + +// Package mocks is a generated GoMock package. +package mocks + +import ( + context "context" + reflect "reflect" + + ids "github.com/ava-labs/avalanchego/ids" + avax "github.com/ava-labs/avalanchego/vms/components/avax" + gomock "go.uber.org/mock/gomock" +) + +// MockBuilderBackend is a mock of BuilderBackend interface. +type MockBuilderBackend struct { + ctrl *gomock.Controller + recorder *MockBuilderBackendMockRecorder +} + +// MockBuilderBackendMockRecorder is the mock recorder for MockBuilderBackend. +type MockBuilderBackendMockRecorder struct { + mock *MockBuilderBackend +} + +// NewMockBuilderBackend creates a new mock instance. +func NewMockBuilderBackend(ctrl *gomock.Controller) *MockBuilderBackend { + mock := &MockBuilderBackend{ctrl: ctrl} + mock.recorder = &MockBuilderBackendMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockBuilderBackend) EXPECT() *MockBuilderBackendMockRecorder { + return m.recorder +} + +// AVAXAssetID mocks base method. +func (m *MockBuilderBackend) AVAXAssetID() ids.ID { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AVAXAssetID") + ret0, _ := ret[0].(ids.ID) + return ret0 +} + +// AVAXAssetID indicates an expected call of AVAXAssetID. +func (mr *MockBuilderBackendMockRecorder) AVAXAssetID() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AVAXAssetID", reflect.TypeOf((*MockBuilderBackend)(nil).AVAXAssetID)) +} + +// BaseTxFee mocks base method. +func (m *MockBuilderBackend) BaseTxFee() uint64 { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BaseTxFee") + ret0, _ := ret[0].(uint64) + return ret0 +} + +// BaseTxFee indicates an expected call of BaseTxFee. +func (mr *MockBuilderBackendMockRecorder) BaseTxFee() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BaseTxFee", reflect.TypeOf((*MockBuilderBackend)(nil).BaseTxFee)) +} + +// BlockchainID mocks base method. +func (m *MockBuilderBackend) BlockchainID() ids.ID { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BlockchainID") + ret0, _ := ret[0].(ids.ID) + return ret0 +} + +// BlockchainID indicates an expected call of BlockchainID. +func (mr *MockBuilderBackendMockRecorder) BlockchainID() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockchainID", reflect.TypeOf((*MockBuilderBackend)(nil).BlockchainID)) +} + +// CreateAssetTxFee mocks base method. +func (m *MockBuilderBackend) CreateAssetTxFee() uint64 { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateAssetTxFee") + ret0, _ := ret[0].(uint64) + return ret0 +} + +// CreateAssetTxFee indicates an expected call of CreateAssetTxFee. +func (mr *MockBuilderBackendMockRecorder) CreateAssetTxFee() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateAssetTxFee", reflect.TypeOf((*MockBuilderBackend)(nil).CreateAssetTxFee)) +} + +// NetworkID mocks base method. +func (m *MockBuilderBackend) NetworkID() uint32 { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NetworkID") + ret0, _ := ret[0].(uint32) + return ret0 +} + +// NetworkID indicates an expected call of NetworkID. +func (mr *MockBuilderBackendMockRecorder) NetworkID() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NetworkID", reflect.TypeOf((*MockBuilderBackend)(nil).NetworkID)) +} + +// UTXOs mocks base method. +func (m *MockBuilderBackend) UTXOs(arg0 context.Context, arg1 ids.ID) ([]*avax.UTXO, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UTXOs", arg0, arg1) + ret0, _ := ret[0].([]*avax.UTXO) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UTXOs indicates an expected call of UTXOs. +func (mr *MockBuilderBackendMockRecorder) UTXOs(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UTXOs", reflect.TypeOf((*MockBuilderBackend)(nil).UTXOs), arg0, arg1) +} diff --git a/wallet/chain/x/mocks/mock_signer_backend.go b/wallet/chain/x/mocks/mock_signer_backend.go new file mode 100644 index 000000000000..0ac6e768bb70 --- /dev/null +++ b/wallet/chain/x/mocks/mock_signer_backend.go @@ -0,0 +1,57 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/ava-labs/avalanchego/wallet/chain/x (interfaces: SignerBackend) +// +// Generated by this command: +// +// mockgen -package=mocks -destination=wallet/chain/x/mocks/mock_signer_backend.go github.com/ava-labs/avalanchego/wallet/chain/x SignerBackend +// + +// Package mocks is a generated GoMock package. +package mocks + +import ( + context "context" + reflect "reflect" + + ids "github.com/ava-labs/avalanchego/ids" + avax "github.com/ava-labs/avalanchego/vms/components/avax" + gomock "go.uber.org/mock/gomock" +) + +// MockSignerBackend is a mock of SignerBackend interface. +type MockSignerBackend struct { + ctrl *gomock.Controller + recorder *MockSignerBackendMockRecorder +} + +// MockSignerBackendMockRecorder is the mock recorder for MockSignerBackend. +type MockSignerBackendMockRecorder struct { + mock *MockSignerBackend +} + +// NewMockSignerBackend creates a new mock instance. +func NewMockSignerBackend(ctrl *gomock.Controller) *MockSignerBackend { + mock := &MockSignerBackend{ctrl: ctrl} + mock.recorder = &MockSignerBackendMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockSignerBackend) EXPECT() *MockSignerBackendMockRecorder { + return m.recorder +} + +// GetUTXO mocks base method. +func (m *MockSignerBackend) GetUTXO(arg0 context.Context, arg1, arg2 ids.ID) (*avax.UTXO, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetUTXO", arg0, arg1, arg2) + ret0, _ := ret[0].(*avax.UTXO) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetUTXO indicates an expected call of GetUTXO. +func (mr *MockSignerBackendMockRecorder) GetUTXO(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUTXO", reflect.TypeOf((*MockSignerBackend)(nil).GetUTXO), arg0, arg1, arg2) +} From c40fe2bd227f9ad81dfbae41f9982159c2bf7117 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Tue, 30 Jan 2024 12:05:37 +0100 Subject: [PATCH 090/190] added some more txs to x-chain dynamic fees builder --- wallet/chain/x/builder.go | 40 +++++---- wallet/chain/x/builder_dynamic_fees.go | 120 +++++++++++++++++++++++++ 2 files changed, 144 insertions(+), 16 deletions(-) diff --git a/wallet/chain/x/builder.go b/wallet/chain/x/builder.go index 27932019e1f4..7b9b5e5cde45 100644 --- a/wallet/chain/x/builder.go +++ b/wallet/chain/x/builder.go @@ -306,7 +306,7 @@ func (b *builder) NewOperationTxMintFT( options ...common.Option, ) (*txs.OperationTx, error) { ops := common.NewOptions(options) - operations, err := b.mintFTs(outputs, ops) + operations, err := mintFTs(b.addrs, b.backend, outputs, ops) if err != nil { return nil, err } @@ -320,7 +320,7 @@ func (b *builder) NewOperationTxMintNFT( options ...common.Option, ) (*txs.OperationTx, error) { ops := common.NewOptions(options) - operations, err := b.mintNFTs(assetID, payload, owners, ops) + operations, err := mintNFTs(b.addrs, b.backend, assetID, payload, owners, ops) if err != nil { return nil, err } @@ -333,7 +333,7 @@ func (b *builder) NewOperationTxMintProperty( options ...common.Option, ) (*txs.OperationTx, error) { ops := common.NewOptions(options) - operations, err := b.mintProperty(assetID, owner, ops) + operations, err := mintProperty(b.addrs, b.backend, assetID, owner, ops) if err != nil { return nil, err } @@ -345,7 +345,7 @@ func (b *builder) NewOperationTxBurnProperty( options ...common.Option, ) (*txs.OperationTx, error) { ops := common.NewOptions(options) - operations, err := b.burnProperty(assetID, ops) + operations, err := burnProperty(b.addrs, b.backend, assetID, ops) if err != nil { return nil, err } @@ -635,19 +635,21 @@ func (b *builder) spend( return inputs, outputs, nil } -func (b *builder) mintFTs( +func mintFTs( + addresses set.Set[ids.ShortID], + backend BuilderBackend, outputs map[ids.ID]*secp256k1fx.TransferOutput, options *common.Options, ) ( operations []*txs.Operation, err error, ) { - utxos, err := b.backend.UTXOs(options.Context(), b.backend.BlockchainID()) + utxos, err := backend.UTXOs(options.Context(), backend.BlockchainID()) if err != nil { return nil, err } - addrs := options.Addresses(b.addrs) + addrs := options.Addresses(addresses) minIssuanceTime := options.MinIssuanceTime() for _, utxo := range utxos { @@ -696,7 +698,9 @@ func (b *builder) mintFTs( } // TODO: make this able to generate multiple NFT groups -func (b *builder) mintNFTs( +func mintNFTs( + addresses set.Set[ids.ShortID], + backend BuilderBackend, assetID ids.ID, payload []byte, owners []*secp256k1fx.OutputOwners, @@ -705,12 +709,12 @@ func (b *builder) mintNFTs( operations []*txs.Operation, err error, ) { - utxos, err := b.backend.UTXOs(options.Context(), b.backend.BlockchainID()) + utxos, err := backend.UTXOs(options.Context(), backend.BlockchainID()) if err != nil { return nil, err } - addrs := options.Addresses(b.addrs) + addrs := options.Addresses(addresses) minIssuanceTime := options.MinIssuanceTime() for _, utxo := range utxos { @@ -754,7 +758,9 @@ func (b *builder) mintNFTs( ) } -func (b *builder) mintProperty( +func mintProperty( + addresses set.Set[ids.ShortID], + backend BuilderBackend, assetID ids.ID, owner *secp256k1fx.OutputOwners, options *common.Options, @@ -762,12 +768,12 @@ func (b *builder) mintProperty( operations []*txs.Operation, err error, ) { - utxos, err := b.backend.UTXOs(options.Context(), b.backend.BlockchainID()) + utxos, err := backend.UTXOs(options.Context(), backend.BlockchainID()) if err != nil { return nil, err } - addrs := options.Addresses(b.addrs) + addrs := options.Addresses(addresses) minIssuanceTime := options.MinIssuanceTime() for _, utxo := range utxos { @@ -812,19 +818,21 @@ func (b *builder) mintProperty( ) } -func (b *builder) burnProperty( +func burnProperty( + addresses set.Set[ids.ShortID], + backend BuilderBackend, assetID ids.ID, options *common.Options, ) ( operations []*txs.Operation, err error, ) { - utxos, err := b.backend.UTXOs(options.Context(), b.backend.BlockchainID()) + utxos, err := backend.UTXOs(options.Context(), backend.BlockchainID()) if err != nil { return nil, err } - addrs := options.Addresses(b.addrs) + addrs := options.Addresses(addresses) minIssuanceTime := options.MinIssuanceTime() for _, utxo := range utxos { diff --git a/wallet/chain/x/builder_dynamic_fees.go b/wallet/chain/x/builder_dynamic_fees.go index ff7fc5d99547..82d2f949c247 100644 --- a/wallet/chain/x/builder_dynamic_fees.go +++ b/wallet/chain/x/builder_dynamic_fees.go @@ -152,6 +152,126 @@ func (b *DynamicFeesBuilder) NewCreateAssetTx( return utx, b.initCtx(utx) } +func (b *DynamicFeesBuilder) NewOperationTx( + operations []*txs.Operation, + unitFees, unitCaps commonfees.Dimensions, + options ...common.Option, +) (*txs.OperationTx, error) { + // 1. Build core transaction without utxos + ops := common.NewOptions(options) + codec := Parser.Codec() + txs.SortOperations(operations, codec) + + utx := &txs.OperationTx{ + BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ + NetworkID: b.backend.NetworkID(), + BlockchainID: b.backend.BlockchainID(), + Memo: ops.Memo(), + }}, + Ops: operations, + } + + // 2. Finance the tx by building the utxos (inputs, outputs and stakes) + toBurn := map[ids.ID]uint64{} // fees are calculated in financeTx + feesMan := commonfees.NewManager(unitFees) + feeCalc := &fees.Calculator{ + IsEForkActive: true, + Codec: Parser.Codec(), + FeeManager: feesMan, + ConsumedUnitsCap: unitCaps, + } + + // feesMan cumulates consumed units. Let's init it with utx filled so far + if err := feeCalc.OperationTx(utx); err != nil { + return nil, err + } + + inputs, changeOuts, err := b.financeTx(toBurn, feeCalc, ops) + if err != nil { + return nil, err + } + + utx.Ins = inputs + utx.Outs = changeOuts + + return utx, b.initCtx(utx) +} + +func (b *DynamicFeesBuilder) NewOperationTxMintFT( + outputs map[ids.ID]*secp256k1fx.TransferOutput, + unitFees, unitCaps commonfees.Dimensions, + options ...common.Option, +) (*txs.OperationTx, error) { + ops := common.NewOptions(options) + operations, err := mintFTs(b.addrs, b.backend, outputs, ops) + if err != nil { + return nil, err + } + return b.NewOperationTx( + operations, + unitFees, + unitCaps, + options..., + ) +} + +func (b *DynamicFeesBuilder) NewOperationTxMintNFT( + assetID ids.ID, + payload []byte, + owners []*secp256k1fx.OutputOwners, + unitFees, unitCaps commonfees.Dimensions, + options ...common.Option, +) (*txs.OperationTx, error) { + ops := common.NewOptions(options) + operations, err := mintNFTs(b.addrs, b.backend, assetID, payload, owners, ops) + if err != nil { + return nil, err + } + return b.NewOperationTx( + operations, + unitFees, + unitCaps, + options..., + ) +} + +func (b *DynamicFeesBuilder) NewOperationTxMintProperty( + assetID ids.ID, + owner *secp256k1fx.OutputOwners, + unitFees, unitCaps commonfees.Dimensions, + options ...common.Option, +) (*txs.OperationTx, error) { + ops := common.NewOptions(options) + operations, err := mintProperty(b.addrs, b.backend, assetID, owner, ops) + if err != nil { + return nil, err + } + return b.NewOperationTx( + operations, + unitFees, + unitCaps, + options..., + ) +} + +func (b *DynamicFeesBuilder) NewOperationTxBurnProperty( + assetID ids.ID, + unitFees, unitCaps commonfees.Dimensions, + options ...common.Option, +) (*txs.OperationTx, error) { + ops := common.NewOptions(options) + operations, err := burnProperty(b.addrs, b.backend, assetID, ops) + if err != nil { + return nil, err + } + return b.NewOperationTx( + operations, + unitFees, + unitCaps, + options..., + ) +} + func (b *DynamicFeesBuilder) NewImportTx( sourceChainID ids.ID, to *secp256k1fx.OutputOwners, From 68b3c8c459aefbe66841e274e3cc3d50a2df687d Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Wed, 31 Jan 2024 09:53:16 +0100 Subject: [PATCH 091/190] introduced fees tracking window --- vms/components/fees/window.go | 79 +++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 vms/components/fees/window.go diff --git a/vms/components/fees/window.go b/vms/components/fees/window.go new file mode 100644 index 000000000000..d6f80b9d9a86 --- /dev/null +++ b/vms/components/fees/window.go @@ -0,0 +1,79 @@ +// Copyright (C) 2023, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package fees + +import ( + "math" + + safemath "github.com/ava-labs/avalanchego/utils/math" +) + +const WindowSize = 10 + +type Window [WindowSize]uint64 + +// Roll rolls the uint64s consumed units within [consumptionWindow] over by [roll] places. +// For example, if there are 4 uint64 encoded in a 32 byte slice, rollWindow would +// have the following effect: +// Original: +// [1, 2, 3, 4] +// Roll = 0 +// [1, 2, 3, 4] +// Roll = 1 +// [2, 3, 4, 0] +// Roll = 2 +// [3, 4, 0, 0] +// Roll = 3 +// [4, 0, 0, 0] +// Roll >= 4 +// [0, 0, 0, 0] +// Assumes that [roll] is greater than or equal to 0 +func Roll(w Window, roll int) (Window, error) { + // Note: make allocates a zeroed array, so we are guaranteed + // that what we do not copy into, will be set to 0 + var res [WindowSize]uint64 + if roll > WindowSize { + return res, nil + } + copy(res[:], w[roll:]) + return res, nil +} + +// Sum sums [numUint64s] encoded in [window]. Assumes that the length of [window] +// is sufficient to contain [numUint64s] or else this function panics. +// If an overflow occurs, while summing the contents, the maximum uint64 value is returned. +func Sum(w Window) uint64 { + var ( + sum uint64 + overflow error + ) + for i := 0; i < WindowSize; i++ { + // If an overflow occurs while summing the elements of the window, return the maximum + // uint64 value immediately. + sum, overflow = safemath.Add64(sum, w[i]) + if overflow != nil { + return math.MaxUint64 + } + } + return sum +} + +// Update adds [unitsConsumed] in at index within [window]. +// Assumes that [index] has already been validated. +// If an overflow occurs, the maximum uint64 value is used. +func Update(w *Window, start int, unitsConsumed uint64) { + prevUnitsConsumed := w[start] + + totalUnitsConsumed, overflow := safemath.Add64(prevUnitsConsumed, unitsConsumed) + if overflow != nil { + totalUnitsConsumed = math.MaxUint64 + } + w[start] = totalUnitsConsumed +} + +func Last(w *Window) uint64 { + return w[len(w)-1] +} + +// TODO ABENEGIA: add Marshal/Unmarshal to bytes, or let the codec do that? From 81b4cf8304ce98b02c04e0c1df77899e7371b0cf Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Wed, 31 Jan 2024 10:27:43 +0100 Subject: [PATCH 092/190] wip:drafting unit fees update mechs --- vms/components/fees/dimensions.go | 32 +++++ vms/components/fees/manager.go | 150 +++++++++++++++----- vms/components/fees/window.go | 7 +- wallet/chain/x/builder_dynamic_fees_test.go | 32 ++--- 4 files changed, 168 insertions(+), 53 deletions(-) create mode 100644 vms/components/fees/dimensions.go diff --git a/vms/components/fees/dimensions.go b/vms/components/fees/dimensions.go new file mode 100644 index 000000000000..805521e3b136 --- /dev/null +++ b/vms/components/fees/dimensions.go @@ -0,0 +1,32 @@ +// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package fees + +import "github.com/ava-labs/avalanchego/utils/math" + +const ( + Bandwidth Dimension = 0 + UTXORead Dimension = 1 + UTXOWrite Dimension = 2 // includes delete + Compute Dimension = 3 // any other cost, tx-specific + + FeeDimensions = 4 +) + +type ( + Dimension int + Dimensions [FeeDimensions]uint64 +) + +func Add(lhs, rhs Dimensions) (Dimensions, error) { + var res Dimensions + for i := 0; i < FeeDimensions; i++ { + v, err := math.Add64(lhs[i], rhs[i]) + if err != nil { + return res, err + } + res[i] = v + } + return res, nil +} diff --git a/vms/components/fees/manager.go b/vms/components/fees/manager.go index cfcf2beab493..d17389dd1edb 100644 --- a/vms/components/fees/manager.go +++ b/vms/components/fees/manager.go @@ -5,42 +5,22 @@ package fees import ( "fmt" + "math" - "github.com/ava-labs/avalanchego/utils/math" + safemath "github.com/ava-labs/avalanchego/utils/math" ) // Fees are not dynamic yet. We'll add mechanism for fee updating iterativelly -const ( - Bandwidth Dimension = 0 - UTXORead Dimension = 1 - UTXOWrite Dimension = 2 // includes delete - Compute Dimension = 3 // any other cost, tx-specific - - FeeDimensions = 4 -) - -type ( - Dimension int - Dimensions [FeeDimensions]uint64 -) - -func Add(lhs, rhs Dimensions) (Dimensions, error) { - var res Dimensions - for i := 0; i < FeeDimensions; i++ { - v, err := math.Add64(lhs[i], rhs[i]) - if err != nil { - return res, err - } - res[i] = v - } - return res, nil -} - type Manager struct { // Avax denominated unit fees for all fee dimensions unitFees Dimensions + // cunsumed units window per each fee dimension. + windows [FeeDimensions]Window + + lastConsumed Dimensions + // cumulatedUnits helps aggregating the units consumed by a block // so that we can verify it's not too big/build it properly. cumulatedUnits Dimensions @@ -57,11 +37,11 @@ func (m *Manager) CalculateFee(units Dimensions) (uint64, error) { fee := uint64(0) for i := Dimension(0); i < FeeDimensions; i++ { - contribution, err := math.Mul64(m.unitFees[i], units[i]) + contribution, err := safemath.Mul64(m.unitFees[i], units[i]) if err != nil { return 0, err } - fee, err = math.Add64(contribution, fee) + fee, err = safemath.Add64(contribution, fee) if err != nil { return 0, err } @@ -75,7 +55,7 @@ func (m *Manager) CalculateFee(units Dimensions) (uint64, error) { func (m *Manager) CumulateUnits(units, bounds Dimensions) (bool, Dimension) { // Ensure we can consume (don't want partial update of values) for i := Dimension(0); i < FeeDimensions; i++ { - consumed, err := math.Add64(m.cumulatedUnits[i], units[i]) + consumed, err := safemath.Add64(m.cumulatedUnits[i], units[i]) if err != nil { return true, i } @@ -86,7 +66,7 @@ func (m *Manager) CumulateUnits(units, bounds Dimensions) (bool, Dimension) { // Commit to consumption for i := Dimension(0); i < FeeDimensions; i++ { - consumed, err := math.Add64(m.cumulatedUnits[i], units[i]) + consumed, err := safemath.Add64(m.cumulatedUnits[i], units[i]) if err != nil { return true, i } @@ -100,7 +80,7 @@ func (m *Manager) CumulateUnits(units, bounds Dimensions) (bool, Dimension) { func (m *Manager) RemoveUnits(unitsToRm Dimensions) error { var revertedUnits Dimensions for i := Dimension(0); i < FeeDimensions; i++ { - prev, err := math.Sub(m.cumulatedUnits[i], unitsToRm[i]) + prev, err := safemath.Sub(m.cumulatedUnits[i], unitsToRm[i]) if err != nil { return fmt.Errorf("%w: dimension %d", err, i) } @@ -114,3 +94,109 @@ func (m *Manager) RemoveUnits(unitsToRm Dimensions) error { func (m *Manager) GetCumulatedUnits() Dimensions { return m.cumulatedUnits } + +func (m *Manager) ComputeNext( + lastTime, + currTime int64, + targetUnits, + priceChangeDenominator, + minUnitPrice Dimensions, +) (*Manager, error) { + since := int((currTime - lastTime) / 1000 /*milliseconds per second*/) + nextManager := &Manager{} + for i := Bandwidth; i < FeeDimensions; i++ { + nextUnitPrice, nextUnitWindow, err := computeNextPriceWindow( + m.windows[i], + m.lastConsumed[i], + m.unitFees[i], + targetUnits[i], + priceChangeDenominator[i], + minUnitPrice[i], + since, + ) + if err != nil { + return nil, err + } + + nextManager.unitFees[i] = nextUnitPrice + nextManager.windows[i] = nextUnitWindow + + // TODO ABENEGIA: how about last consumed + + // start := dimensionStateLen * i + // binary.BigEndian.PutUint64(bytes[start:start+consts.Uint64Len], nextUnitPrice) + // copy(bytes[start+consts.Uint64Len:start+consts.Uint64Len+WindowSliceSize], nextUnitWindow[:]) + // // Usage must be set after block is processed (we leave as 0 for now) + } + return nextManager, nil +} + +func computeNextPriceWindow( + previous Window, + previousConsumed uint64, + previousPrice uint64, + target uint64, /* per window */ + changeDenom uint64, + minPrice uint64, + since int, /* seconds */ +) (uint64, Window, error) { + newRollupWindow, err := Roll(previous, since) + if err != nil { + return 0, Window{}, err + } + if since < WindowSize { + // add in the units used by the parent block in the correct place + // If the parent consumed units within the rollup window, add the consumed + // units in. + start := WindowSize - 1 - since + Update(&newRollupWindow, start, previousConsumed) + } + total := Sum(newRollupWindow) + + nextPrice := previousPrice + switch { + case total == target: + return nextPrice, newRollupWindow, nil + case total > target: + // If the parent block used more units than its target, the baseFee should increase. + delta := total - target + x := previousPrice * delta + y := x / target + baseDelta := y / changeDenom + if baseDelta < 1 { + baseDelta = 1 + } + n, over := safemath.Add64(nextPrice, baseDelta) + if over != nil { + nextPrice = math.MaxUint64 + } else { + nextPrice = n + } + case total < target: + // Otherwise if the parent block used less units than its target, the baseFee should decrease. + delta := target - total + x := previousPrice * delta + y := x / target + baseDelta := y / changeDenom + if baseDelta < 1 { + baseDelta = 1 + } + + // If [roll] is greater than [rollupWindow], apply the state transition to the base fee to account + // for the interval during which no blocks were produced. + // We use roll/rollupWindow, so that the transition is applied for every [rollupWindow] seconds + // that has elapsed between the parent and this block. + if since > WindowSize { + // Note: roll/rollupWindow must be greater than 1 since we've checked that roll > rollupWindow + baseDelta *= uint64(since / WindowSize) + } + n, under := safemath.Sub(nextPrice, baseDelta) + if under != nil { + nextPrice = 0 + } else { + nextPrice = n + } + } + nextPrice = safemath.Max(nextPrice, minPrice) + return nextPrice, newRollupWindow, nil +} diff --git a/vms/components/fees/window.go b/vms/components/fees/window.go index d6f80b9d9a86..a188551a76da 100644 --- a/vms/components/fees/window.go +++ b/vms/components/fees/window.go @@ -1,4 +1,4 @@ -// Copyright (C) 2023, Ava Labs, Inc. All rights reserved. +// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. // See the file LICENSE for licensing terms. package fees @@ -40,9 +40,8 @@ func Roll(w Window, roll int) (Window, error) { return res, nil } -// Sum sums [numUint64s] encoded in [window]. Assumes that the length of [window] -// is sufficient to contain [numUint64s] or else this function panics. -// If an overflow occurs, while summing the contents, the maximum uint64 value is returned. +// Sum sums [numUint64s] encoded in [window]. If an overflow occurs, +// while summing the contents, the maximum uint64 value is returned. func Sum(w Window) uint64 { var ( sum uint64 diff --git a/wallet/chain/x/builder_dynamic_fees_test.go b/wallet/chain/x/builder_dynamic_fees_test.go index 51936e002515..722777045f3f 100644 --- a/wallet/chain/x/builder_dynamic_fees_test.go +++ b/wallet/chain/x/builder_dynamic_fees_test.go @@ -55,9 +55,9 @@ func TestBaseTx(t *testing.T) { be := mocks.NewMockBuilderBackend(ctrl) var ( - utxosKey = testKeys[1] - utxoAddr = utxosKey.PublicKey().Address() - utxos, avaxAssetID, _ = testUTXOsList(utxosKey) + utxosKey = testKeys[1] + utxoAddr = utxosKey.PublicKey().Address() + utxos, avaxAssetID = testUTXOsList(utxosKey) outputsToMove = []*avax.TransferableOutput{{ Asset: avax.Asset{ID: avaxAssetID}, @@ -126,9 +126,9 @@ func TestCreateAssetTx(t *testing.T) { be := mocks.NewMockBuilderBackend(ctrl) var ( - utxosKey = testKeys[1] - utxoAddr = utxosKey.PublicKey().Address() - utxos, avaxAssetID, _ = testUTXOsList(utxosKey) + utxosKey = testKeys[1] + utxoAddr = utxosKey.PublicKey().Address() + utxos, avaxAssetID = testUTXOsList(utxosKey) assetName = "Team Rocket" symbol = "TR" @@ -237,10 +237,10 @@ func TestImportTx(t *testing.T) { be := mocks.NewMockBuilderBackend(ctrl) var ( - utxosKey = testKeys[1] - utxoAddr = utxosKey.PublicKey().Address() - sourceChainID = ids.GenerateTestID() - utxos, avaxAssetID, _ = testUTXOsList(utxosKey) + utxosKey = testKeys[1] + utxoAddr = utxosKey.PublicKey().Address() + sourceChainID = ids.GenerateTestID() + utxos, avaxAssetID = testUTXOsList(utxosKey) importKey = testKeys[0] importTo = &secp256k1fx.OutputOwners{ @@ -312,10 +312,10 @@ func TestExportTx(t *testing.T) { be := mocks.NewMockBuilderBackend(ctrl) var ( - utxosKey = testKeys[1] - utxoAddr = utxosKey.PublicKey().Address() - subnetID = ids.GenerateTestID() - utxos, avaxAssetID, _ = testUTXOsList(utxosKey) + utxosKey = testKeys[1] + utxoAddr = utxosKey.PublicKey().Address() + subnetID = ids.GenerateTestID() + utxos, avaxAssetID = testUTXOsList(utxosKey) exportedOutputs = []*avax.TransferableOutput{{ Asset: avax.Asset{ID: avaxAssetID}, @@ -380,7 +380,6 @@ func TestExportTx(t *testing.T) { func testUTXOsList(utxosKey *secp256k1.PrivateKey) ( []*avax.UTXO, ids.ID, // avaxAssetID, - ids.ID, // subnetAssetID ) { // Note: we avoid ids.GenerateTestNodeID here to make sure that UTXO IDs won't change // run by run. This simplifies checking what utxos are included in the built txs. @@ -472,6 +471,5 @@ func testUTXOsList(utxosKey *secp256k1.PrivateKey) ( }, }, }, - avaxAssetID, - subnetAssetID + avaxAssetID } From 4e4e3ec32af48ee8aeaac60632bb06577f10b983 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Wed, 31 Jan 2024 11:35:21 +0100 Subject: [PATCH 093/190] added windows UTs --- vms/components/fees/dimensions.go | 2 +- vms/components/fees/manager.go | 16 +++------ vms/components/fees/window.go | 14 ++++---- vms/components/fees/window_test.go | 54 ++++++++++++++++++++++++++++++ 4 files changed, 67 insertions(+), 19 deletions(-) create mode 100644 vms/components/fees/window_test.go diff --git a/vms/components/fees/dimensions.go b/vms/components/fees/dimensions.go index 805521e3b136..6165b45fc190 100644 --- a/vms/components/fees/dimensions.go +++ b/vms/components/fees/dimensions.go @@ -9,7 +9,7 @@ const ( Bandwidth Dimension = 0 UTXORead Dimension = 1 UTXOWrite Dimension = 2 // includes delete - Compute Dimension = 3 // any other cost, tx-specific + Compute Dimension = 3 // signatures checks, tx-specific FeeDimensions = 4 ) diff --git a/vms/components/fees/manager.go b/vms/components/fees/manager.go index d17389dd1edb..985306a0de21 100644 --- a/vms/components/fees/manager.go +++ b/vms/components/fees/manager.go @@ -105,7 +105,7 @@ func (m *Manager) ComputeNext( since := int((currTime - lastTime) / 1000 /*milliseconds per second*/) nextManager := &Manager{} for i := Bandwidth; i < FeeDimensions; i++ { - nextUnitPrice, nextUnitWindow, err := computeNextPriceWindow( + nextUnitPrice, nextUnitWindow := computeNextPriceWindow( m.windows[i], m.lastConsumed[i], m.unitFees[i], @@ -114,9 +114,6 @@ func (m *Manager) ComputeNext( minUnitPrice[i], since, ) - if err != nil { - return nil, err - } nextManager.unitFees[i] = nextUnitPrice nextManager.windows[i] = nextUnitWindow @@ -139,11 +136,8 @@ func computeNextPriceWindow( changeDenom uint64, minPrice uint64, since int, /* seconds */ -) (uint64, Window, error) { - newRollupWindow, err := Roll(previous, since) - if err != nil { - return 0, Window{}, err - } +) (uint64, Window) { + newRollupWindow := Roll(previous, since) if since < WindowSize { // add in the units used by the parent block in the correct place // If the parent consumed units within the rollup window, add the consumed @@ -156,7 +150,7 @@ func computeNextPriceWindow( nextPrice := previousPrice switch { case total == target: - return nextPrice, newRollupWindow, nil + return nextPrice, newRollupWindow case total > target: // If the parent block used more units than its target, the baseFee should increase. delta := total - target @@ -198,5 +192,5 @@ func computeNextPriceWindow( } } nextPrice = safemath.Max(nextPrice, minPrice) - return nextPrice, newRollupWindow, nil + return nextPrice, newRollupWindow } diff --git a/vms/components/fees/window.go b/vms/components/fees/window.go index a188551a76da..14a84c213834 100644 --- a/vms/components/fees/window.go +++ b/vms/components/fees/window.go @@ -29,18 +29,18 @@ type Window [WindowSize]uint64 // Roll >= 4 // [0, 0, 0, 0] // Assumes that [roll] is greater than or equal to 0 -func Roll(w Window, roll int) (Window, error) { +func Roll(w Window, roll int) Window { // Note: make allocates a zeroed array, so we are guaranteed // that what we do not copy into, will be set to 0 var res [WindowSize]uint64 if roll > WindowSize { - return res, nil + return res } copy(res[:], w[roll:]) - return res, nil + return res } -// Sum sums [numUint64s] encoded in [window]. If an overflow occurs, +// Sum sums the consumed units recorded in [window]. If an overflow occurs, // while summing the contents, the maximum uint64 value is returned. func Sum(w Window) uint64 { var ( @@ -61,14 +61,14 @@ func Sum(w Window) uint64 { // Update adds [unitsConsumed] in at index within [window]. // Assumes that [index] has already been validated. // If an overflow occurs, the maximum uint64 value is used. -func Update(w *Window, start int, unitsConsumed uint64) { - prevUnitsConsumed := w[start] +func Update(w *Window, idx int, unitsConsumed uint64) { + prevUnitsConsumed := w[idx] totalUnitsConsumed, overflow := safemath.Add64(prevUnitsConsumed, unitsConsumed) if overflow != nil { totalUnitsConsumed = math.MaxUint64 } - w[start] = totalUnitsConsumed + w[idx] = totalUnitsConsumed } func Last(w *Window) uint64 { diff --git a/vms/components/fees/window_test.go b/vms/components/fees/window_test.go new file mode 100644 index 000000000000..9297b81c6267 --- /dev/null +++ b/vms/components/fees/window_test.go @@ -0,0 +1,54 @@ +// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package fees + +import ( + "math" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestWindowRoll(t *testing.T) { + require := require.New(t) + + var win Window + for i := 0; i < WindowSize; i++ { + win[i] = uint64(i + 2024) + } + + for i := 0; i < WindowSize; i++ { + rolledWin := Roll(win, i) + + // check that first i elements in window are shited out and + // ovewritted by remaining WindowSize - i elements + require.Equal(rolledWin[0:WindowSize-i], win[i:WindowSize]) + + // check that trailing i elemnts of the rolled window are zero + require.Equal(rolledWin[WindowSize-i:], make([]uint64, i)) + } + + // check that overolling wipes all window out + overRolledWin := Roll(win, WindowSize+1) + require.Equal(overRolledWin, Window{}) +} + +func TestSum(t *testing.T) { + require := require.New(t) + + // no overflow case + var win Window + for i := 0; i < WindowSize; i++ { + win[i] = uint64(i + 1) + } + require.Equal(Sum(win), uint64(WindowSize*(WindowSize+1)/2)) + + // overflow case + Update(&win, 0, math.MaxUint64-1) + require.Equal(Sum(win), uint64(math.MaxUint64)) + + // another overflow case + Update(&win, 0, math.MaxUint64) + require.Equal(Sum(win), uint64(math.MaxUint64)) +} From 6bb5796a901f237b7ec88bf6c609bc95dacefb0d Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Wed, 31 Jan 2024 13:09:14 +0100 Subject: [PATCH 094/190] added ComputeNext fee manager UTs --- vms/components/fees/manager.go | 98 ++++++++--------- vms/components/fees/manager_test.go | 157 ++++++++++++++++++++++++++++ 2 files changed, 198 insertions(+), 57 deletions(-) create mode 100644 vms/components/fees/manager_test.go diff --git a/vms/components/fees/manager.go b/vms/components/fees/manager.go index 985306a0de21..9e44050d07ff 100644 --- a/vms/components/fees/manager.go +++ b/vms/components/fees/manager.go @@ -19,8 +19,6 @@ type Manager struct { // cunsumed units window per each fee dimension. windows [FeeDimensions]Window - lastConsumed Dimensions - // cumulatedUnits helps aggregating the units consumed by a block // so that we can verify it's not too big/build it properly. cumulatedUnits Dimensions @@ -101,13 +99,13 @@ func (m *Manager) ComputeNext( targetUnits, priceChangeDenominator, minUnitPrice Dimensions, -) (*Manager, error) { - since := int((currTime - lastTime) / 1000 /*milliseconds per second*/) +) *Manager { + since := int(currTime - lastTime) nextManager := &Manager{} - for i := Bandwidth; i < FeeDimensions; i++ { + for i := Dimension(0); i < FeeDimensions; i++ { nextUnitPrice, nextUnitWindow := computeNextPriceWindow( m.windows[i], - m.lastConsumed[i], + m.cumulatedUnits[i], m.unitFees[i], targetUnits[i], priceChangeDenominator[i], @@ -117,80 +115,66 @@ func (m *Manager) ComputeNext( nextManager.unitFees[i] = nextUnitPrice nextManager.windows[i] = nextUnitWindow - - // TODO ABENEGIA: how about last consumed - - // start := dimensionStateLen * i - // binary.BigEndian.PutUint64(bytes[start:start+consts.Uint64Len], nextUnitPrice) - // copy(bytes[start+consts.Uint64Len:start+consts.Uint64Len+WindowSliceSize], nextUnitWindow[:]) - // // Usage must be set after block is processed (we leave as 0 for now) + // unit consumed are zeroed in nextManager } - return nextManager, nil + return nextManager } func computeNextPriceWindow( - previous Window, - previousConsumed uint64, - previousPrice uint64, - target uint64, /* per window */ + current Window, + currentUnitsConsumed uint64, + currentUnitFee uint64, + target uint64, /* per window, must be non-zero */ changeDenom uint64, - minPrice uint64, + minUnitFee uint64, since int, /* seconds */ ) (uint64, Window) { - newRollupWindow := Roll(previous, since) + newRollupWindow := Roll(current, since) if since < WindowSize { // add in the units used by the parent block in the correct place // If the parent consumed units within the rollup window, add the consumed // units in. start := WindowSize - 1 - since - Update(&newRollupWindow, start, previousConsumed) + Update(&newRollupWindow, start, currentUnitsConsumed) } - total := Sum(newRollupWindow) - nextPrice := previousPrice + var ( + totalUnitsConsumed = Sum(newRollupWindow) + nextUnitFee = currentUnitFee + ) + switch { - case total == target: - return nextPrice, newRollupWindow - case total > target: + case totalUnitsConsumed == target: + return nextUnitFee, newRollupWindow + case totalUnitsConsumed > target: // If the parent block used more units than its target, the baseFee should increase. - delta := total - target - x := previousPrice * delta - y := x / target - baseDelta := y / changeDenom - if baseDelta < 1 { - baseDelta = 1 - } - n, over := safemath.Add64(nextPrice, baseDelta) + rawDelta := currentUnitFee * (totalUnitsConsumed - target) / target + delta := safemath.Max(rawDelta/changeDenom, 1) * changeDenom // price must change in increments on changeDenom + + var over error + nextUnitFee, over = safemath.Add64(nextUnitFee, delta) if over != nil { - nextPrice = math.MaxUint64 - } else { - nextPrice = n + nextUnitFee = math.MaxUint64 } - case total < target: + + case totalUnitsConsumed < target: // Otherwise if the parent block used less units than its target, the baseFee should decrease. - delta := target - total - x := previousPrice * delta - y := x / target - baseDelta := y / changeDenom - if baseDelta < 1 { - baseDelta = 1 - } + rawDelta := currentUnitFee * (target - totalUnitsConsumed) / target + delta := safemath.Max(rawDelta/changeDenom, 1) * changeDenom // price must change in increments on changeDenom - // If [roll] is greater than [rollupWindow], apply the state transition to the base fee to account - // for the interval during which no blocks were produced. - // We use roll/rollupWindow, so that the transition is applied for every [rollupWindow] seconds - // that has elapsed between the parent and this block. + // if we had no blocks for more than [WindowSize] seconds, we reduce fees even more, + // to try and account for all the low activity interval if since > WindowSize { - // Note: roll/rollupWindow must be greater than 1 since we've checked that roll > rollupWindow - baseDelta *= uint64(since / WindowSize) + delta *= uint64(since / WindowSize) } - n, under := safemath.Sub(nextPrice, baseDelta) + + var under error + nextUnitFee, under = safemath.Sub(nextUnitFee, delta) if under != nil { - nextPrice = 0 - } else { - nextPrice = n + nextUnitFee = 0 } } - nextPrice = safemath.Max(nextPrice, minPrice) - return nextPrice, newRollupWindow + + nextUnitFee = safemath.Max(nextUnitFee, minUnitFee) + return nextUnitFee, newRollupWindow } diff --git a/vms/components/fees/manager_test.go b/vms/components/fees/manager_test.go new file mode 100644 index 000000000000..6c963f8ffd45 --- /dev/null +++ b/vms/components/fees/manager_test.go @@ -0,0 +1,157 @@ +// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package fees + +import ( + "math" + "testing" + "time" + + "github.com/stretchr/testify/require" +) + +func TestComputeNextEmptyWindows(t *testing.T) { + require := require.New(t) + + var ( + initialUnitFees = Dimensions{1, 1, 1, 1} + consumedUnits = Dimensions{10, 25, 30, 2500} + targetComplexity = Dimensions{25, 25, 25, 25} + + // last block happened within Window + lastBlkTime = time.Now().Truncate(time.Second) + currBlkTime = lastBlkTime.Add(time.Second) + + priceChangeDenominator = Dimensions{1, 1, 2, 10} + minUnitFees = Dimensions{0, 0, 0, 0} + ) + + m := &Manager{ + unitFees: initialUnitFees, + windows: [FeeDimensions]Window{}, + cumulatedUnits: consumedUnits, + } + next := m.ComputeNext( + lastBlkTime.Unix(), + currBlkTime.Unix(), + targetComplexity, + priceChangeDenominator, + minUnitFees, + ) + + // Bandwidth units are below target, next unit fees are pushed to the minimum + require.Equal(minUnitFees[Bandwidth], next.unitFees[Bandwidth]) + + // UTXORead units are at target, next unit fees are kept equal + require.Equal(initialUnitFees[UTXORead], next.unitFees[UTXORead]) + + // UTXOWrite units are above target, next unit fees increased, proportionally to priceChangeDenominator + require.Equal(initialUnitFees[UTXOWrite]+priceChangeDenominator[UTXOWrite], next.unitFees[UTXOWrite]) + + // Compute units are above target, next unit fees increased, proportionally to priceChangeDenominator + require.Equal(initialUnitFees[Compute]+9*priceChangeDenominator[Compute], next.unitFees[Compute]) + + // next cumulated units are zeroed + require.Equal(Dimensions{}, next.cumulatedUnits) +} + +func TestComputeNextNonEmptyWindows(t *testing.T) { + require := require.New(t) + + var ( + initialUnitFees = Dimensions{1, 1, 1, 1} + consumedUnits = Dimensions{0, 0, 0, 0} + targetComplexity = Dimensions{25, 25, 25, 25} + + // last block happened within Window + lastBlkTime = time.Now().Truncate(time.Second) + currBlkTime = lastBlkTime.Add(time.Second) + + priceChangeDenominator = Dimensions{1, 1, 2, 10} + minUnitFees = Dimensions{0, 0, 0, 0} + ) + + m := &Manager{ + unitFees: initialUnitFees, + windows: [FeeDimensions]Window{ + {1, 1, 1, 2, 2, 3, 3, 4, 5, 0}, // increasing but overall below target + {0, 0, math.MaxUint64, 0, 0, 0, 0, 0, 0, 0}, // spike within window + {10, 20, 30, 40, 50, 35, 25, 15, 10, 10}, // decreasing but overall above target + {0, 0, 0, 0, 0, math.MaxUint64 / 2, math.MaxUint64 / 2, 0, 0, 0}, // again pretty spiky + }, + cumulatedUnits: consumedUnits, + } + next := m.ComputeNext( + lastBlkTime.Unix(), + currBlkTime.Unix(), + targetComplexity, + priceChangeDenominator, + minUnitFees, + ) + + // Bandwidth units are below target, next unit fees are pushed to the minimum + require.Equal(minUnitFees[Bandwidth], next.unitFees[Bandwidth]) + + // UTXORead units are at above target, due to spike in window. Next unit fees are increased + require.Equal(uint64(737869762948382064), next.unitFees[UTXORead]) + + // UTXOWrite units are above target, even if they are decreasing within the window. Next unit fees increased. + require.Equal(initialUnitFees[UTXOWrite]+4*priceChangeDenominator[UTXOWrite], next.unitFees[UTXOWrite]) + + // Compute units are above target, next unit fees increased, proportionally to priceChangeDenominator + require.Equal(uint64(737869762948382061), next.unitFees[Compute]) + + // next cumulated units are zeroed + require.Equal(Dimensions{}, next.cumulatedUnits) +} + +func TestComputeNextEdgeCases(t *testing.T) { + require := require.New(t) + + var ( + initialUnitFees = Dimensions{1, 2, 2, 2} + consumedUnits = Dimensions{0, 0, 0, 0} + targetComplexity = Dimensions{math.MaxUint64, 1, 1, 1} // a very skewed requirement for block complexity + + // last block happened within Window + lastBlkTime = time.Now().Truncate(time.Second) + currBlkTime = lastBlkTime.Add(time.Second) + + priceChangeDenominator = Dimensions{1, 1, 1, 1} + minUnitFees = Dimensions{1, 0, 0, 0} + ) + + m := &Manager{ + unitFees: initialUnitFees, + windows: [FeeDimensions]Window{ + {0, 0, 0, math.MaxUint64, 0, 0, 0, 0, 0, 0}, // a huge spike in the past, on the non-constrained dimension + {0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, // a small spike, but above the zero constrain set for this dimension + {}, + {}, + }, + cumulatedUnits: consumedUnits, + } + next := m.ComputeNext( + lastBlkTime.Unix(), + currBlkTime.Unix(), + targetComplexity, + priceChangeDenominator, + minUnitFees, + ) + + // Bandwidth units are below target, next unit fees are pushed to the minimum + require.Equal(minUnitFees[Bandwidth], next.unitFees[Bandwidth]) + + // UTXORead units are at above target, due to spike in window. Next unit fees are increased + require.Equal(initialUnitFees[UTXORead], next.unitFees[UTXORead]) + + // UTXOWrite units are above target, even if they are decreasing within the window. Next unit fees increased. + require.Equal(minUnitFees[UTXOWrite], next.unitFees[UTXOWrite]) + + // Compute units are above target, next unit fees increased, proportionally to priceChangeDenominator + require.Equal(minUnitFees[Compute], next.unitFees[Compute]) + + // next cumulated units are zeroed + require.Equal(Dimensions{}, next.cumulatedUnits) +} From cff5c2c3a528acb48eee97d63169c0358c7ef2fa Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Wed, 31 Jan 2024 15:24:22 +0100 Subject: [PATCH 095/190] nit --- vms/components/fees/dimensions.go | 5 + .../block/executor/proposal_block_test.go | 7 +- .../block/executor/standard_block_test.go | 10 +- .../block/executor/verifier_test.go | 11 +- .../txs/executor/atomic_tx_executor.go | 5 +- .../txs/executor/create_chain_test.go | 21 ++- .../txs/executor/create_subnet_test.go | 5 +- .../txs/executor/proposal_tx_executor.go | 7 +- .../executor/staker_tx_verification_test.go | 5 +- .../txs/executor/standard_tx_executor_test.go | 129 +++++++++--------- vms/platformvm/txs/fees/calculator.go | 3 - 11 files changed, 103 insertions(+), 105 deletions(-) diff --git a/vms/components/fees/dimensions.go b/vms/components/fees/dimensions.go index 6165b45fc190..6d5634cb9549 100644 --- a/vms/components/fees/dimensions.go +++ b/vms/components/fees/dimensions.go @@ -14,6 +14,11 @@ const ( FeeDimensions = 4 ) +var ( + EmptyUnitFees = Dimensions{} // helps avoiding reading unit fees from db for some pre E fork processing + EmptyUnitCaps = Dimensions{} // helps avoiding reading unit fees from db for some pre E fork processing +) + type ( Dimension int Dimensions [FeeDimensions]uint64 diff --git a/vms/platformvm/block/executor/proposal_block_test.go b/vms/platformvm/block/executor/proposal_block_test.go index 899c6ce54415..55cc0370db1e 100644 --- a/vms/platformvm/block/executor/proposal_block_test.go +++ b/vms/platformvm/block/executor/proposal_block_test.go @@ -26,8 +26,9 @@ import ( "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/fees" "github.com/ava-labs/avalanchego/vms/secp256k1fx" + + commonfees "github.com/ava-labs/avalanchego/vms/components/fees" ) func TestApricotProposalBlockTimeVerification(t *testing.T) { @@ -160,8 +161,8 @@ func TestBanffProposalBlockTimeVerification(t *testing.T) { onParentAccept := state.NewMockDiff(ctrl) onParentAccept.EXPECT().GetTimestamp().Return(parentTime).AnyTimes() - onParentAccept.EXPECT().GetUnitFees().Return(fees.EmptyUnitFees, nil).AnyTimes() - onParentAccept.EXPECT().GetBlockUnitCaps().Return(fees.EmptyUnitCaps, nil).AnyTimes() + onParentAccept.EXPECT().GetUnitFees().Return(commonfees.EmptyUnitFees, nil).AnyTimes() + onParentAccept.EXPECT().GetBlockUnitCaps().Return(commonfees.EmptyUnitCaps, 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 63424352cc5c..1bdcdd67e504 100644 --- a/vms/platformvm/block/executor/standard_block_test.go +++ b/vms/platformvm/block/executor/standard_block_test.go @@ -18,12 +18,12 @@ import ( "github.com/ava-labs/avalanchego/utils/constants" "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" "github.com/ava-labs/avalanchego/vms/components/avax" + commonfees "github.com/ava-labs/avalanchego/vms/components/fees" "github.com/ava-labs/avalanchego/vms/platformvm/block" "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/fees" "github.com/ava-labs/avalanchego/vms/secp256k1fx" ) @@ -57,8 +57,8 @@ 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().GetUnitFees().Return(fees.EmptyUnitFees, nil) - onParentAccept.EXPECT().GetBlockUnitCaps().Return(fees.EmptyUnitCaps, nil) + onParentAccept.EXPECT().GetUnitFees().Return(commonfees.EmptyUnitFees, nil) + onParentAccept.EXPECT().GetBlockUnitCaps().Return(commonfees.EmptyUnitCaps, nil) // wrong height apricotChildBlk, err := block.NewApricotStandardBlock( apricotParentBlk.ID(), @@ -152,8 +152,8 @@ func TestBanffStandardBlockTimeVerification(t *testing.T) { } utxoID := utxo.InputID() onParentAccept.EXPECT().GetUTXO(utxoID).Return(utxo, nil).AnyTimes() - onParentAccept.EXPECT().GetUnitFees().Return(fees.EmptyUnitFees, nil).AnyTimes() - onParentAccept.EXPECT().GetBlockUnitCaps().Return(fees.EmptyUnitCaps, nil).AnyTimes() + onParentAccept.EXPECT().GetUnitFees().Return(commonfees.EmptyUnitFees, nil).AnyTimes() + onParentAccept.EXPECT().GetBlockUnitCaps().Return(commonfees.EmptyUnitCaps, nil).AnyTimes() // Create the tx utx := &txs.CreateSubnetTx{ diff --git a/vms/platformvm/block/executor/verifier_test.go b/vms/platformvm/block/executor/verifier_test.go index b77c54ac90ba..c303caaeb17f 100644 --- a/vms/platformvm/block/executor/verifier_test.go +++ b/vms/platformvm/block/executor/verifier_test.go @@ -26,8 +26,9 @@ import ( "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/fees" "github.com/ava-labs/avalanchego/vms/platformvm/txs/mempool" + + commonfees "github.com/ava-labs/avalanchego/vms/components/fees" ) func TestVerifierVisitProposalBlock(t *testing.T) { @@ -286,8 +287,8 @@ func TestVerifierVisitStandardBlock(t *testing.T) { // Set expectations for dependencies. timestamp := time.Now() parentState.EXPECT().GetTimestamp().Return(timestamp).Times(1) - parentState.EXPECT().GetUnitFees().Return(fees.EmptyUnitFees, nil) - parentState.EXPECT().GetBlockUnitCaps().Return(fees.EmptyUnitCaps, nil) + parentState.EXPECT().GetUnitFees().Return(commonfees.EmptyUnitFees, nil) + parentState.EXPECT().GetBlockUnitCaps().Return(commonfees.EmptyUnitCaps, nil) parentStatelessBlk.EXPECT().Height().Return(uint64(1)).Times(1) mempool.EXPECT().Remove(apricotBlk.Txs()).Times(1) @@ -767,8 +768,8 @@ func TestVerifierVisitStandardBlockWithDuplicateInputs(t *testing.T) { timestamp := time.Now() parentStatelessBlk.EXPECT().Height().Return(uint64(1)).Times(1) parentState.EXPECT().GetTimestamp().Return(timestamp).Times(1) - parentState.EXPECT().GetUnitFees().Return(fees.EmptyUnitFees, nil) - parentState.EXPECT().GetBlockUnitCaps().Return(fees.EmptyUnitCaps, nil) + parentState.EXPECT().GetUnitFees().Return(commonfees.EmptyUnitFees, nil) + parentState.EXPECT().GetBlockUnitCaps().Return(commonfees.EmptyUnitCaps, nil) parentStatelessBlk.EXPECT().Parent().Return(grandParentID).Times(1) err = verifier.ApricotStandardBlock(blk) diff --git a/vms/platformvm/txs/executor/atomic_tx_executor.go b/vms/platformvm/txs/executor/atomic_tx_executor.go index fc266f1b040a..c0fbfdc07095 100644 --- a/vms/platformvm/txs/executor/atomic_tx_executor.go +++ b/vms/platformvm/txs/executor/atomic_tx_executor.go @@ -9,7 +9,6 @@ import ( "github.com/ava-labs/avalanchego/utils/set" "github.com/ava-labs/avalanchego/vms/platformvm/state" "github.com/ava-labs/avalanchego/vms/platformvm/txs" - "github.com/ava-labs/avalanchego/vms/platformvm/txs/fees" commonfees "github.com/ava-labs/avalanchego/vms/components/fees" ) @@ -103,8 +102,8 @@ func (e *AtomicTxExecutor) atomicTx(tx txs.UnsignedTx) error { executor := StandardTxExecutor{ Backend: e.Backend, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), + UnitCaps: commonfees.EmptyUnitCaps, State: e.OnAccept, Tx: e.Tx, } diff --git a/vms/platformvm/txs/executor/create_chain_test.go b/vms/platformvm/txs/executor/create_chain_test.go index b55b016f9e75..bd3850f9f356 100644 --- a/vms/platformvm/txs/executor/create_chain_test.go +++ b/vms/platformvm/txs/executor/create_chain_test.go @@ -18,7 +18,6 @@ import ( "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/platformvm/state" "github.com/ava-labs/avalanchego/vms/platformvm/txs" - "github.com/ava-labs/avalanchego/vms/platformvm/txs/fees" "github.com/ava-labs/avalanchego/vms/platformvm/utxo" "github.com/ava-labs/avalanchego/vms/secp256k1fx" @@ -51,8 +50,8 @@ func TestCreateChainTxInsufficientControlSigs(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), + UnitCaps: commonfees.EmptyUnitCaps, State: stateDiff, Tx: tx, } @@ -92,8 +91,8 @@ func TestCreateChainTxWrongControlSig(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), + UnitCaps: commonfees.EmptyUnitCaps, State: stateDiff, Tx: tx, } @@ -127,8 +126,8 @@ func TestCreateChainTxNoSuchSubnet(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), + UnitCaps: commonfees.EmptyUnitCaps, State: stateDiff, Tx: tx, } @@ -159,8 +158,8 @@ func TestCreateChainTxValid(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), + UnitCaps: commonfees.EmptyUnitCaps, State: stateDiff, Tx: tx, } @@ -232,8 +231,8 @@ func TestCreateChainTxAP3FeeChange(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), + UnitCaps: commonfees.EmptyUnitCaps, State: stateDiff, Tx: tx, } diff --git a/vms/platformvm/txs/executor/create_subnet_test.go b/vms/platformvm/txs/executor/create_subnet_test.go index f02f4e9d3260..69a142718d79 100644 --- a/vms/platformvm/txs/executor/create_subnet_test.go +++ b/vms/platformvm/txs/executor/create_subnet_test.go @@ -14,7 +14,6 @@ import ( "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/platformvm/state" "github.com/ava-labs/avalanchego/vms/platformvm/txs" - "github.com/ava-labs/avalanchego/vms/platformvm/txs/fees" "github.com/ava-labs/avalanchego/vms/platformvm/utxo" "github.com/ava-labs/avalanchego/vms/secp256k1fx" @@ -80,8 +79,8 @@ func TestCreateSubnetTxAP3FeeChange(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), + UnitCaps: commonfees.EmptyUnitCaps, State: stateDiff, Tx: tx, } diff --git a/vms/platformvm/txs/executor/proposal_tx_executor.go b/vms/platformvm/txs/executor/proposal_tx_executor.go index bbfbdeb5a338..335eb1ffb295 100644 --- a/vms/platformvm/txs/executor/proposal_tx_executor.go +++ b/vms/platformvm/txs/executor/proposal_tx_executor.go @@ -16,7 +16,6 @@ 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/fees" commonfees "github.com/ava-labs/avalanchego/vms/components/fees" ) @@ -119,7 +118,7 @@ func (e *ProposalTxExecutor) AddValidatorTx(tx *txs.AddValidatorTx) error { onAbortOuts, err := verifyAddValidatorTx( e.Backend, e.BlkFeeManager, - fees.EmptyUnitCaps, + commonfees.EmptyUnitCaps, e.OnCommitState, e.Tx, tx, @@ -168,7 +167,7 @@ func (e *ProposalTxExecutor) AddSubnetValidatorTx(tx *txs.AddSubnetValidatorTx) if err := verifyAddSubnetValidatorTx( e.Backend, e.BlkFeeManager, - fees.EmptyUnitCaps, + commonfees.EmptyUnitCaps, e.OnCommitState, e.Tx, tx, @@ -216,7 +215,7 @@ func (e *ProposalTxExecutor) AddDelegatorTx(tx *txs.AddDelegatorTx) error { onAbortOuts, err := verifyAddDelegatorTx( e.Backend, e.BlkFeeManager, - fees.EmptyUnitCaps, + commonfees.EmptyUnitCaps, e.OnCommitState, e.Tx, tx, diff --git a/vms/platformvm/txs/executor/staker_tx_verification_test.go b/vms/platformvm/txs/executor/staker_tx_verification_test.go index 009605fceac2..0724913931e9 100644 --- a/vms/platformvm/txs/executor/staker_tx_verification_test.go +++ b/vms/platformvm/txs/executor/staker_tx_verification_test.go @@ -23,7 +23,6 @@ import ( "github.com/ava-labs/avalanchego/vms/platformvm/config" "github.com/ava-labs/avalanchego/vms/platformvm/state" "github.com/ava-labs/avalanchego/vms/platformvm/txs" - "github.com/ava-labs/avalanchego/vms/platformvm/txs/fees" "github.com/ava-labs/avalanchego/vms/platformvm/utxo" "github.com/ava-labs/avalanchego/vms/secp256k1fx" @@ -603,13 +602,13 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { var ( backend = tt.backendF(ctrl) - feeManager = commonfees.NewManager(fees.EmptyUnitFees) + feeManager = commonfees.NewManager(commonfees.EmptyUnitFees) state = tt.stateF(ctrl) sTx = tt.sTxF() tx = tt.txF() ) - err := verifyAddPermissionlessValidatorTx(backend, feeManager, fees.EmptyUnitCaps, state, sTx, tx) + err := verifyAddPermissionlessValidatorTx(backend, feeManager, commonfees.EmptyUnitCaps, state, sTx, tx) require.ErrorIs(t, err, tt.expectedErr) }) } diff --git a/vms/platformvm/txs/executor/standard_tx_executor_test.go b/vms/platformvm/txs/executor/standard_tx_executor_test.go index 098ffeae7aca..9076bfabff7d 100644 --- a/vms/platformvm/txs/executor/standard_tx_executor_test.go +++ b/vms/platformvm/txs/executor/standard_tx_executor_test.go @@ -33,7 +33,6 @@ 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/fees" "github.com/ava-labs/avalanchego/vms/platformvm/utxo" "github.com/ava-labs/avalanchego/vms/secp256k1fx" "github.com/ava-labs/avalanchego/vms/types" @@ -94,8 +93,8 @@ func TestStandardTxExecutorAddValidatorTxEmptyID(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), + UnitCaps: commonfees.EmptyUnitCaps, State: stateDiff, Tx: tx, } @@ -352,8 +351,8 @@ func TestStandardTxExecutorAddDelegator(t *testing.T) { executor := StandardTxExecutor{ Backend: &freshTH.backend, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), + UnitCaps: commonfees.EmptyUnitCaps, State: onAcceptState, Tx: tx, } @@ -392,8 +391,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), + UnitCaps: commonfees.EmptyUnitCaps, State: onAcceptState, Tx: tx, } @@ -422,8 +421,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), + UnitCaps: commonfees.EmptyUnitCaps, State: onAcceptState, Tx: tx, } @@ -466,8 +465,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), + UnitCaps: commonfees.EmptyUnitCaps, State: onAcceptState, Tx: tx, } @@ -511,8 +510,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), + UnitCaps: commonfees.EmptyUnitCaps, State: onAcceptState, Tx: tx, } @@ -539,8 +538,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), + UnitCaps: commonfees.EmptyUnitCaps, State: onAcceptState, Tx: tx, } @@ -566,8 +565,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { require.NoError(err) executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), + UnitCaps: commonfees.EmptyUnitCaps, State: onAcceptState, Tx: tx, } @@ -596,8 +595,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), + UnitCaps: commonfees.EmptyUnitCaps, State: onAcceptState, Tx: tx, } @@ -654,8 +653,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), + UnitCaps: commonfees.EmptyUnitCaps, State: onAcceptState, Tx: duplicateSubnetTx, } @@ -693,8 +692,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), + UnitCaps: commonfees.EmptyUnitCaps, State: onAcceptState, Tx: tx, } @@ -728,8 +727,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), + UnitCaps: commonfees.EmptyUnitCaps, State: onAcceptState, Tx: tx, } @@ -761,8 +760,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), + UnitCaps: commonfees.EmptyUnitCaps, State: onAcceptState, Tx: tx, } @@ -804,8 +803,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), + UnitCaps: commonfees.EmptyUnitCaps, State: onAcceptState, Tx: tx, } @@ -841,8 +840,8 @@ func TestBanffStandardTxExecutorAddValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), + UnitCaps: commonfees.EmptyUnitCaps, State: onAcceptState, Tx: tx, } @@ -869,8 +868,8 @@ func TestBanffStandardTxExecutorAddValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), + UnitCaps: commonfees.EmptyUnitCaps, State: onAcceptState, Tx: tx, } @@ -910,8 +909,8 @@ func TestBanffStandardTxExecutorAddValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), + UnitCaps: commonfees.EmptyUnitCaps, State: onAcceptState, Tx: tx, } @@ -948,8 +947,8 @@ func TestBanffStandardTxExecutorAddValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), + UnitCaps: commonfees.EmptyUnitCaps, State: onAcceptState, Tx: tx, } @@ -985,8 +984,8 @@ func TestBanffStandardTxExecutorAddValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), + UnitCaps: commonfees.EmptyUnitCaps, State: onAcceptState, Tx: tx, } @@ -1764,8 +1763,8 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), + UnitCaps: commonfees.EmptyUnitCaps, Tx: env.tx, State: env.state, } @@ -1796,8 +1795,8 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), + UnitCaps: commonfees.EmptyUnitCaps, Tx: env.tx, State: env.state, } @@ -1829,8 +1828,8 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), + UnitCaps: commonfees.EmptyUnitCaps, Tx: env.tx, State: env.state, } @@ -1865,8 +1864,8 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), + UnitCaps: commonfees.EmptyUnitCaps, Tx: env.tx, State: env.state, } @@ -1899,8 +1898,8 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), + UnitCaps: commonfees.EmptyUnitCaps, Tx: env.tx, State: env.state, } @@ -1932,8 +1931,8 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), + UnitCaps: commonfees.EmptyUnitCaps, Tx: env.tx, State: env.state, } @@ -1967,8 +1966,8 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), + UnitCaps: commonfees.EmptyUnitCaps, Tx: env.tx, State: env.state, } @@ -2005,8 +2004,8 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), + UnitCaps: commonfees.EmptyUnitCaps, Tx: env.tx, State: env.state, } @@ -2167,8 +2166,8 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), + UnitCaps: commonfees.EmptyUnitCaps, Tx: env.tx, State: env.state, } @@ -2199,8 +2198,8 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), + UnitCaps: commonfees.EmptyUnitCaps, Tx: env.tx, State: env.state, } @@ -2233,8 +2232,8 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), + UnitCaps: commonfees.EmptyUnitCaps, Tx: env.tx, State: env.state, } @@ -2272,8 +2271,8 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), + UnitCaps: commonfees.EmptyUnitCaps, Tx: env.tx, State: env.state, } @@ -2316,8 +2315,8 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), + UnitCaps: commonfees.EmptyUnitCaps, Tx: env.tx, State: env.state, } diff --git a/vms/platformvm/txs/fees/calculator.go b/vms/platformvm/txs/fees/calculator.go index 2db218df6333..44a91482c8df 100644 --- a/vms/platformvm/txs/fees/calculator.go +++ b/vms/platformvm/txs/fees/calculator.go @@ -20,9 +20,6 @@ import ( var ( _ txs.Visitor = (*Calculator)(nil) - EmptyUnitFees = fees.Dimensions{} // helps avoiding reading unit fees from db for some pre E fork processing - EmptyUnitCaps = fees.Dimensions{} // helps avoiding reading unit fees from db for some pre E fork processing - // These are the default unit fees, used upon E-fork activation // TODO ABENEGIA: to be tuned DefaultUnitFees = fees.Dimensions{ From 80b91865c481f91a57992b4f12cc1e31c34bdc69 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Wed, 31 Jan 2024 15:39:47 +0100 Subject: [PATCH 096/190] passed windows in fee manager ctor --- tests/e2e/p/workflow.go | 2 +- vms/avm/block/executor/block.go | 2 +- vms/avm/block/executor/manager.go | 2 +- vms/avm/txs/fees/calculator_test.go | 10 +- vms/avm/vm.go | 2 +- vms/components/fees/dimensions.go | 1 + vms/components/fees/manager.go | 3 +- vms/platformvm/block/builder/builder.go | 4 +- vms/platformvm/block/builder/helpers_test.go | 2 +- vms/platformvm/block/executor/helpers_test.go | 2 +- vms/platformvm/block/executor/manager.go | 2 +- vms/platformvm/block/executor/verifier.go | 2 +- vms/platformvm/txs/builder/builder.go | 20 +-- .../txs/executor/atomic_tx_executor.go | 2 +- .../txs/executor/create_chain_test.go | 10 +- .../txs/executor/create_subnet_test.go | 2 +- vms/platformvm/txs/executor/helpers_test.go | 2 +- .../executor/staker_tx_verification_test.go | 7 +- .../txs/executor/standard_tx_executor_test.go | 131 +++++++++--------- vms/platformvm/txs/fees/calculator_test.go | 28 ++-- vms/platformvm/utxo/handler_test.go | 16 +-- wallet/chain/p/builder_dynamic_fees.go | 24 ++-- wallet/chain/p/builder_dynamic_fees_test.go | 24 ++-- wallet/chain/x/builder_dynamic_fees.go | 10 +- wallet/chain/x/builder_dynamic_fees_test.go | 8 +- 25 files changed, 159 insertions(+), 159 deletions(-) diff --git a/tests/e2e/p/workflow.go b/tests/e2e/p/workflow.go index 3dc34afdf9de..7279cdf860ba 100644 --- a/tests/e2e/p/workflow.go +++ b/tests/e2e/p/workflow.go @@ -147,7 +147,7 @@ var _ = e2e.DescribePChain("[Workflow]", func() { // retrieve fees paid for the tx feeCalc := fees.Calculator{ IsEForkActive: true, - FeeManager: commonfees.NewManager(unitFees), + FeeManager: commonfees.NewManager(unitFees, commonfees.EmptyWindows), ConsumedUnitsCap: unitCaps, Credentials: tx.Creds, } diff --git a/vms/avm/block/executor/block.go b/vms/avm/block/executor/block.go index 7874d199f55b..b3c4e2d1e283 100644 --- a/vms/avm/block/executor/block.go +++ b/vms/avm/block/executor/block.go @@ -86,7 +86,7 @@ func (b *Block) Verify(context.Context) error { return err } - feeManager := fees.NewManager(unitFees) + feeManager := fees.NewManager(unitFees, fees.EmptyWindows) for _, tx := range txs { err := tx.Unsigned.Visit(&executor.SyntacticVerifier{ Backend: b.manager.backend, diff --git a/vms/avm/block/executor/manager.go b/vms/avm/block/executor/manager.go index 0f4cb6ba1bdd..7863022b8cdc 100644 --- a/vms/avm/block/executor/manager.go +++ b/vms/avm/block/executor/manager.go @@ -160,7 +160,7 @@ func (m *manager) VerifyTx(tx *txs.Tx) error { err = tx.Unsigned.Visit(&executor.SyntacticVerifier{ Backend: m.backend, - BlkFeeManager: fees.NewManager(unitFees), + BlkFeeManager: fees.NewManager(unitFees, fees.EmptyWindows), UnitCaps: unitCaps, BlkTimestamp: m.state.GetTimestamp(), Tx: tx, diff --git a/vms/avm/txs/fees/calculator_test.go b/vms/avm/txs/fees/calculator_test.go index f2ccc7b3ccf5..6e3d99bae0e6 100644 --- a/vms/avm/txs/fees/calculator_test.go +++ b/vms/avm/txs/fees/calculator_test.go @@ -153,7 +153,7 @@ func TestBaseTxFees(t *testing.T) { IsEForkActive: cfg.IsEForkActivated(chainTime), Config: cfg, Codec: codec, - FeeManager: fees.NewManager(testUnitFees), + FeeManager: fees.NewManager(testUnitFees, fees.EmptyWindows), ConsumedUnitsCap: consumedUnitCaps, Credentials: sTx.Creds, } @@ -274,7 +274,7 @@ func TestCreateAssetTxFees(t *testing.T) { IsEForkActive: cfg.IsEForkActivated(chainTime), Config: cfg, Codec: codec, - FeeManager: fees.NewManager(testUnitFees), + FeeManager: fees.NewManager(testUnitFees, fees.EmptyWindows), ConsumedUnitsCap: consumedUnitCaps, Credentials: sTx.Creds, } @@ -395,7 +395,7 @@ func TestOperationTxFees(t *testing.T) { IsEForkActive: cfg.IsEForkActivated(chainTime), Config: cfg, Codec: codec, - FeeManager: fees.NewManager(testUnitFees), + FeeManager: fees.NewManager(testUnitFees, fees.EmptyWindows), ConsumedUnitsCap: consumedUnitCaps, Credentials: sTx.Creds, } @@ -512,7 +512,7 @@ func TestImportTxFees(t *testing.T) { IsEForkActive: cfg.IsEForkActivated(chainTime), Config: cfg, Codec: codec, - FeeManager: fees.NewManager(testUnitFees), + FeeManager: fees.NewManager(testUnitFees, fees.EmptyWindows), ConsumedUnitsCap: consumedUnitCaps, Credentials: sTx.Creds, } @@ -619,7 +619,7 @@ func TestExportTxFees(t *testing.T) { IsEForkActive: cfg.IsEForkActivated(chainTime), Config: cfg, Codec: codec, - FeeManager: fees.NewManager(testUnitFees), + FeeManager: fees.NewManager(testUnitFees, fees.EmptyWindows), ConsumedUnitsCap: consumedUnitCaps, Credentials: sTx.Creds, } diff --git a/vms/avm/vm.go b/vms/avm/vm.go index 5bd1776b1ecf..6c2ffc1262f9 100644 --- a/vms/avm/vm.go +++ b/vms/avm/vm.go @@ -502,7 +502,7 @@ func (vm *VM) ParseTx(_ context.Context, bytes []byte) (snowstorm.Tx, error) { err = tx.Unsigned.Visit(&txexecutor.SyntacticVerifier{ Backend: vm.txBackend, - BlkFeeManager: fees.NewManager(unitFees), + BlkFeeManager: fees.NewManager(unitFees, fees.EmptyWindows), UnitCaps: unitCaps, BlkTimestamp: vm.state.GetTimestamp(), Tx: tx, diff --git a/vms/components/fees/dimensions.go b/vms/components/fees/dimensions.go index 6d5634cb9549..b8050be15dc1 100644 --- a/vms/components/fees/dimensions.go +++ b/vms/components/fees/dimensions.go @@ -17,6 +17,7 @@ const ( var ( EmptyUnitFees = Dimensions{} // helps avoiding reading unit fees from db for some pre E fork processing EmptyUnitCaps = Dimensions{} // helps avoiding reading unit fees from db for some pre E fork processing + EmptyWindows = [FeeDimensions]Window{} ) type ( diff --git a/vms/components/fees/manager.go b/vms/components/fees/manager.go index 9e44050d07ff..b6c9afbd3e9f 100644 --- a/vms/components/fees/manager.go +++ b/vms/components/fees/manager.go @@ -24,9 +24,10 @@ type Manager struct { cumulatedUnits Dimensions } -func NewManager(unitFees Dimensions) *Manager { +func NewManager(unitFees Dimensions, windows [FeeDimensions]Window) *Manager { return &Manager{ unitFees: unitFees, + windows: windows, } } diff --git a/vms/platformvm/block/builder/builder.go b/vms/platformvm/block/builder/builder.go index 0a4af120ba54..07061501669e 100644 --- a/vms/platformvm/block/builder/builder.go +++ b/vms/platformvm/block/builder/builder.go @@ -17,13 +17,13 @@ import ( "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/fees" "github.com/ava-labs/avalanchego/vms/platformvm/block" "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/mempool" + "github.com/ava-labs/avalanchego/vms/components/fees" blockexecutor "github.com/ava-labs/avalanchego/vms/platformvm/block/executor" txbuilder "github.com/ava-labs/avalanchego/vms/platformvm/txs/builder" txexecutor "github.com/ava-labs/avalanchego/vms/platformvm/txs/executor" @@ -386,7 +386,7 @@ func packBlockTxs( executor := &txexecutor.StandardTxExecutor{ Backend: backend, - BlkFeeManager: fees.NewManager(unitFees), + BlkFeeManager: fees.NewManager(unitFees, fees.EmptyWindows), UnitCaps: unitCaps, State: txDiff, Tx: tx, diff --git a/vms/platformvm/block/builder/helpers_test.go b/vms/platformvm/block/builder/helpers_test.go index 3d9e1ebe7a04..72ed6b86691b 100644 --- a/vms/platformvm/block/builder/helpers_test.go +++ b/vms/platformvm/block/builder/helpers_test.go @@ -263,7 +263,7 @@ func addSubnet(t *testing.T, env *environment) { executor := txexecutor.StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(unitFees), + BlkFeeManager: fees.NewManager(unitFees, fees.EmptyWindows), UnitCaps: unitCaps, State: stateDiff, Tx: testSubnet1, diff --git a/vms/platformvm/block/executor/helpers_test.go b/vms/platformvm/block/executor/helpers_test.go index ebf951c62a2f..969052177377 100644 --- a/vms/platformvm/block/executor/helpers_test.go +++ b/vms/platformvm/block/executor/helpers_test.go @@ -286,7 +286,7 @@ func addSubnet(env *environment) { executor := executor.StandardTxExecutor{ Backend: env.backend, - BlkFeeManager: fees.NewManager(unitFees), + BlkFeeManager: fees.NewManager(unitFees, fees.EmptyWindows), UnitCaps: unitCaps, State: stateDiff, Tx: testSubnet1, diff --git a/vms/platformvm/block/executor/manager.go b/vms/platformvm/block/executor/manager.go index fe2cbdf10a44..5f9555d5bde8 100644 --- a/vms/platformvm/block/executor/manager.go +++ b/vms/platformvm/block/executor/manager.go @@ -155,7 +155,7 @@ func (m *manager) VerifyTx(tx *txs.Tx) error { err = tx.Unsigned.Visit(&executor.StandardTxExecutor{ Backend: m.txExecutorBackend, - BlkFeeManager: fees.NewManager(unitFees), + BlkFeeManager: fees.NewManager(unitFees, fees.EmptyWindows), UnitCaps: unitCaps, State: stateDiff, Tx: tx, diff --git a/vms/platformvm/block/executor/verifier.go b/vms/platformvm/block/executor/verifier.go index 8fad999b4119..0ff6cbf85c8c 100644 --- a/vms/platformvm/block/executor/verifier.go +++ b/vms/platformvm/block/executor/verifier.go @@ -449,7 +449,7 @@ func (v *verifier) processStandardTxs(txs []*txs.Tx, state state.Diff, parentID if err != nil { return nil, nil, nil, err } - feeManager := fees.NewManager(unitFees) + feeManager := fees.NewManager(unitFees, fees.EmptyWindows) unitCaps, err := state.GetBlockUnitCaps() if err != nil { diff --git a/vms/platformvm/txs/builder/builder.go b/vms/platformvm/txs/builder/builder.go index 3b2ecb1f71d9..5addb88ce20c 100644 --- a/vms/platformvm/txs/builder/builder.go +++ b/vms/platformvm/txs/builder/builder.go @@ -328,7 +328,7 @@ func (b *builder) NewImportTx( utx.BaseTx.Outs = outs feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, - FeeManager: commonfees.NewManager(unitFees), + FeeManager: commonfees.NewManager(unitFees, commonfees.EmptyWindows), ConsumedUnitsCap: unitCaps, Credentials: txs.EmptyCredentials(signers), } @@ -494,7 +494,7 @@ func (b *builder) NewExportTx( feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, - FeeManager: commonfees.NewManager(unitFees), + FeeManager: commonfees.NewManager(unitFees, commonfees.EmptyWindows), ConsumedUnitsCap: unitCaps, Credentials: txs.EmptyCredentials(signers), } @@ -589,7 +589,7 @@ func (b *builder) NewCreateChainTx( feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, - FeeManager: commonfees.NewManager(unitFees), + FeeManager: commonfees.NewManager(unitFees, commonfees.EmptyWindows), ConsumedUnitsCap: unitCaps, Credentials: txs.EmptyCredentials(signers), } @@ -673,7 +673,7 @@ func (b *builder) NewCreateSubnetTx( feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, - FeeManager: commonfees.NewManager(unitFees), + FeeManager: commonfees.NewManager(unitFees, commonfees.EmptyWindows), ConsumedUnitsCap: unitCaps, Credentials: txs.EmptyCredentials(signers), } @@ -766,7 +766,7 @@ func (b *builder) NewAddValidatorTx( feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, - FeeManager: commonfees.NewManager(unitFees), + FeeManager: commonfees.NewManager(unitFees, commonfees.EmptyWindows), ConsumedUnitsCap: unitCaps, Credentials: txs.EmptyCredentials(signers), } @@ -857,7 +857,7 @@ func (b *builder) NewAddDelegatorTx( feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, - FeeManager: commonfees.NewManager(unitFees), + FeeManager: commonfees.NewManager(unitFees, commonfees.EmptyWindows), ConsumedUnitsCap: unitCaps, Credentials: txs.EmptyCredentials(signers), } @@ -949,7 +949,7 @@ func (b *builder) NewAddSubnetValidatorTx( feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, - FeeManager: commonfees.NewManager(unitFees), + FeeManager: commonfees.NewManager(unitFees, commonfees.EmptyWindows), ConsumedUnitsCap: unitCaps, Credentials: txs.EmptyCredentials(signers), } @@ -1031,7 +1031,7 @@ func (b *builder) NewRemoveSubnetValidatorTx( feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, - FeeManager: commonfees.NewManager(unitFees), + FeeManager: commonfees.NewManager(unitFees, commonfees.EmptyWindows), ConsumedUnitsCap: unitCaps, Credentials: txs.EmptyCredentials(signers), } @@ -1127,7 +1127,7 @@ func (b *builder) NewTransferSubnetOwnershipTx( feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, - FeeManager: commonfees.NewManager(unitFees), + FeeManager: commonfees.NewManager(unitFees, commonfees.EmptyWindows), ConsumedUnitsCap: unitCaps, Credentials: txs.EmptyCredentials(signers), } @@ -1203,7 +1203,7 @@ func (b *builder) NewBaseTx( feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, - FeeManager: commonfees.NewManager(unitFees), + FeeManager: commonfees.NewManager(unitFees, commonfees.EmptyWindows), ConsumedUnitsCap: unitCaps, Credentials: txs.EmptyCredentials(signers), } diff --git a/vms/platformvm/txs/executor/atomic_tx_executor.go b/vms/platformvm/txs/executor/atomic_tx_executor.go index c0fbfdc07095..a4095f0310d5 100644 --- a/vms/platformvm/txs/executor/atomic_tx_executor.go +++ b/vms/platformvm/txs/executor/atomic_tx_executor.go @@ -102,7 +102,7 @@ func (e *AtomicTxExecutor) atomicTx(tx txs.UnsignedTx) error { executor := StandardTxExecutor{ Backend: e.Backend, - BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), + BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees, commonfees.EmptyWindows), UnitCaps: commonfees.EmptyUnitCaps, State: e.OnAccept, Tx: e.Tx, diff --git a/vms/platformvm/txs/executor/create_chain_test.go b/vms/platformvm/txs/executor/create_chain_test.go index bd3850f9f356..5cc8e037002f 100644 --- a/vms/platformvm/txs/executor/create_chain_test.go +++ b/vms/platformvm/txs/executor/create_chain_test.go @@ -50,7 +50,7 @@ func TestCreateChainTxInsufficientControlSigs(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), + BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees, commonfees.EmptyWindows), UnitCaps: commonfees.EmptyUnitCaps, State: stateDiff, Tx: tx, @@ -91,7 +91,7 @@ func TestCreateChainTxWrongControlSig(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), + BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees, commonfees.EmptyWindows), UnitCaps: commonfees.EmptyUnitCaps, State: stateDiff, Tx: tx, @@ -126,7 +126,7 @@ func TestCreateChainTxNoSuchSubnet(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), + BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees, commonfees.EmptyWindows), UnitCaps: commonfees.EmptyUnitCaps, State: stateDiff, Tx: tx, @@ -158,7 +158,7 @@ func TestCreateChainTxValid(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), + BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees, commonfees.EmptyWindows), UnitCaps: commonfees.EmptyUnitCaps, State: stateDiff, Tx: tx, @@ -231,7 +231,7 @@ func TestCreateChainTxAP3FeeChange(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), + BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees, commonfees.EmptyWindows), UnitCaps: commonfees.EmptyUnitCaps, State: stateDiff, Tx: tx, diff --git a/vms/platformvm/txs/executor/create_subnet_test.go b/vms/platformvm/txs/executor/create_subnet_test.go index 69a142718d79..7041f0f84c2a 100644 --- a/vms/platformvm/txs/executor/create_subnet_test.go +++ b/vms/platformvm/txs/executor/create_subnet_test.go @@ -79,7 +79,7 @@ func TestCreateSubnetTxAP3FeeChange(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), + BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees, commonfees.EmptyWindows), UnitCaps: commonfees.EmptyUnitCaps, State: stateDiff, Tx: tx, diff --git a/vms/platformvm/txs/executor/helpers_test.go b/vms/platformvm/txs/executor/helpers_test.go index 7ff5db6e1353..0b2123293f23 100644 --- a/vms/platformvm/txs/executor/helpers_test.go +++ b/vms/platformvm/txs/executor/helpers_test.go @@ -237,7 +237,7 @@ func addSubnet( executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(unitFees), + BlkFeeManager: fees.NewManager(unitFees, fees.EmptyWindows), UnitCaps: unitCaps, State: stateDiff, Tx: testSubnet1, diff --git a/vms/platformvm/txs/executor/staker_tx_verification_test.go b/vms/platformvm/txs/executor/staker_tx_verification_test.go index 0724913931e9..9de443943a71 100644 --- a/vms/platformvm/txs/executor/staker_tx_verification_test.go +++ b/vms/platformvm/txs/executor/staker_tx_verification_test.go @@ -19,14 +19,13 @@ import ( "github.com/ava-labs/avalanchego/utils/constants" "github.com/ava-labs/avalanchego/utils/timer/mockable" "github.com/ava-labs/avalanchego/vms/components/avax" + "github.com/ava-labs/avalanchego/vms/components/fees" "github.com/ava-labs/avalanchego/vms/components/verify" "github.com/ava-labs/avalanchego/vms/platformvm/config" "github.com/ava-labs/avalanchego/vms/platformvm/state" "github.com/ava-labs/avalanchego/vms/platformvm/txs" "github.com/ava-labs/avalanchego/vms/platformvm/utxo" "github.com/ava-labs/avalanchego/vms/secp256k1fx" - - commonfees "github.com/ava-labs/avalanchego/vms/components/fees" ) func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { @@ -602,13 +601,13 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { var ( backend = tt.backendF(ctrl) - feeManager = commonfees.NewManager(commonfees.EmptyUnitFees) + feeManager = fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows) state = tt.stateF(ctrl) sTx = tt.sTxF() tx = tt.txF() ) - err := verifyAddPermissionlessValidatorTx(backend, feeManager, commonfees.EmptyUnitCaps, state, sTx, tx) + err := verifyAddPermissionlessValidatorTx(backend, feeManager, fees.EmptyUnitCaps, state, sTx, tx) require.ErrorIs(t, err, tt.expectedErr) }) } diff --git a/vms/platformvm/txs/executor/standard_tx_executor_test.go b/vms/platformvm/txs/executor/standard_tx_executor_test.go index 9076bfabff7d..40cd8b463134 100644 --- a/vms/platformvm/txs/executor/standard_tx_executor_test.go +++ b/vms/platformvm/txs/executor/standard_tx_executor_test.go @@ -25,6 +25,7 @@ import ( "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/fees" "github.com/ava-labs/avalanchego/vms/components/verify" "github.com/ava-labs/avalanchego/vms/platformvm/config" "github.com/ava-labs/avalanchego/vms/platformvm/fx" @@ -36,8 +37,6 @@ import ( "github.com/ava-labs/avalanchego/vms/platformvm/utxo" "github.com/ava-labs/avalanchego/vms/secp256k1fx" "github.com/ava-labs/avalanchego/vms/types" - - commonfees "github.com/ava-labs/avalanchego/vms/components/fees" ) // This tests that the math performed during TransformSubnetTx execution can @@ -93,8 +92,8 @@ func TestStandardTxExecutorAddValidatorTxEmptyID(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), - UnitCaps: commonfees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), + UnitCaps: fees.EmptyUnitCaps, State: stateDiff, Tx: tx, } @@ -351,8 +350,8 @@ func TestStandardTxExecutorAddDelegator(t *testing.T) { executor := StandardTxExecutor{ Backend: &freshTH.backend, - BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), - UnitCaps: commonfees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), + UnitCaps: fees.EmptyUnitCaps, State: onAcceptState, Tx: tx, } @@ -391,8 +390,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), - UnitCaps: commonfees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), + UnitCaps: fees.EmptyUnitCaps, State: onAcceptState, Tx: tx, } @@ -421,8 +420,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), - UnitCaps: commonfees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), + UnitCaps: fees.EmptyUnitCaps, State: onAcceptState, Tx: tx, } @@ -465,8 +464,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), - UnitCaps: commonfees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), + UnitCaps: fees.EmptyUnitCaps, State: onAcceptState, Tx: tx, } @@ -510,8 +509,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), - UnitCaps: commonfees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), + UnitCaps: fees.EmptyUnitCaps, State: onAcceptState, Tx: tx, } @@ -538,8 +537,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), - UnitCaps: commonfees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), + UnitCaps: fees.EmptyUnitCaps, State: onAcceptState, Tx: tx, } @@ -565,8 +564,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { require.NoError(err) executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), - UnitCaps: commonfees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), + UnitCaps: fees.EmptyUnitCaps, State: onAcceptState, Tx: tx, } @@ -595,8 +594,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), - UnitCaps: commonfees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), + UnitCaps: fees.EmptyUnitCaps, State: onAcceptState, Tx: tx, } @@ -653,8 +652,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), - UnitCaps: commonfees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), + UnitCaps: fees.EmptyUnitCaps, State: onAcceptState, Tx: duplicateSubnetTx, } @@ -692,8 +691,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), - UnitCaps: commonfees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), + UnitCaps: fees.EmptyUnitCaps, State: onAcceptState, Tx: tx, } @@ -727,8 +726,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), - UnitCaps: commonfees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), + UnitCaps: fees.EmptyUnitCaps, State: onAcceptState, Tx: tx, } @@ -760,8 +759,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), - UnitCaps: commonfees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), + UnitCaps: fees.EmptyUnitCaps, State: onAcceptState, Tx: tx, } @@ -803,8 +802,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), - UnitCaps: commonfees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), + UnitCaps: fees.EmptyUnitCaps, State: onAcceptState, Tx: tx, } @@ -840,8 +839,8 @@ func TestBanffStandardTxExecutorAddValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), - UnitCaps: commonfees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), + UnitCaps: fees.EmptyUnitCaps, State: onAcceptState, Tx: tx, } @@ -868,8 +867,8 @@ func TestBanffStandardTxExecutorAddValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), - UnitCaps: commonfees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), + UnitCaps: fees.EmptyUnitCaps, State: onAcceptState, Tx: tx, } @@ -909,8 +908,8 @@ func TestBanffStandardTxExecutorAddValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), - UnitCaps: commonfees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), + UnitCaps: fees.EmptyUnitCaps, State: onAcceptState, Tx: tx, } @@ -947,8 +946,8 @@ func TestBanffStandardTxExecutorAddValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), - UnitCaps: commonfees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), + UnitCaps: fees.EmptyUnitCaps, State: onAcceptState, Tx: tx, } @@ -984,8 +983,8 @@ func TestBanffStandardTxExecutorAddValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), - UnitCaps: commonfees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), + UnitCaps: fees.EmptyUnitCaps, State: onAcceptState, Tx: tx, } @@ -1763,8 +1762,8 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), - UnitCaps: commonfees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), + UnitCaps: fees.EmptyUnitCaps, Tx: env.tx, State: env.state, } @@ -1795,8 +1794,8 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), - UnitCaps: commonfees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), + UnitCaps: fees.EmptyUnitCaps, Tx: env.tx, State: env.state, } @@ -1828,8 +1827,8 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), - UnitCaps: commonfees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), + UnitCaps: fees.EmptyUnitCaps, Tx: env.tx, State: env.state, } @@ -1864,8 +1863,8 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), - UnitCaps: commonfees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), + UnitCaps: fees.EmptyUnitCaps, Tx: env.tx, State: env.state, } @@ -1898,8 +1897,8 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), - UnitCaps: commonfees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), + UnitCaps: fees.EmptyUnitCaps, Tx: env.tx, State: env.state, } @@ -1931,8 +1930,8 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), - UnitCaps: commonfees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), + UnitCaps: fees.EmptyUnitCaps, Tx: env.tx, State: env.state, } @@ -1966,8 +1965,8 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), - UnitCaps: commonfees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), + UnitCaps: fees.EmptyUnitCaps, Tx: env.tx, State: env.state, } @@ -2004,8 +2003,8 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), - UnitCaps: commonfees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), + UnitCaps: fees.EmptyUnitCaps, Tx: env.tx, State: env.state, } @@ -2166,8 +2165,8 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), - UnitCaps: commonfees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), + UnitCaps: fees.EmptyUnitCaps, Tx: env.tx, State: env.state, } @@ -2198,8 +2197,8 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), - UnitCaps: commonfees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), + UnitCaps: fees.EmptyUnitCaps, Tx: env.tx, State: env.state, } @@ -2232,8 +2231,8 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), - UnitCaps: commonfees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), + UnitCaps: fees.EmptyUnitCaps, Tx: env.tx, State: env.state, } @@ -2271,8 +2270,8 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), - UnitCaps: commonfees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), + UnitCaps: fees.EmptyUnitCaps, Tx: env.tx, State: env.state, } @@ -2315,8 +2314,8 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees), - UnitCaps: commonfees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), + UnitCaps: fees.EmptyUnitCaps, Tx: env.tx, State: env.state, } diff --git a/vms/platformvm/txs/fees/calculator_test.go b/vms/platformvm/txs/fees/calculator_test.go index fcde6cb205ab..890424aa54f3 100644 --- a/vms/platformvm/txs/fees/calculator_test.go +++ b/vms/platformvm/txs/fees/calculator_test.go @@ -123,7 +123,7 @@ func TestAddAndRemoveFees(t *testing.T) { fc := &Calculator{ IsEForkActive: true, - FeeManager: fees.NewManager(testUnitFees), + FeeManager: fees.NewManager(testUnitFees, fees.EmptyWindows), ConsumedUnitsCap: testBlockMaxConsumedUnits, } @@ -337,7 +337,7 @@ func TestAddValidatorTxFees(t *testing.T) { IsEForkActive: cfg.IsEForkActivated(chainTime), Config: cfg, ChainTime: chainTime, - FeeManager: fees.NewManager(testUnitFees), + FeeManager: fees.NewManager(testUnitFees, fees.EmptyWindows), ConsumedUnitsCap: consumedUnitCaps, Credentials: sTx.Creds, } @@ -450,7 +450,7 @@ func TestAddSubnetValidatorTxFees(t *testing.T) { IsEForkActive: cfg.IsEForkActivated(chainTime), Config: cfg, ChainTime: chainTime, - FeeManager: fees.NewManager(testUnitFees), + FeeManager: fees.NewManager(testUnitFees, fees.EmptyWindows), ConsumedUnitsCap: consumedUnitCaps, Credentials: sTx.Creds, } @@ -564,7 +564,7 @@ func TestAddDelegatorTxFees(t *testing.T) { IsEForkActive: cfg.IsEForkActivated(chainTime), Config: cfg, ChainTime: chainTime, - FeeManager: fees.NewManager(testUnitFees), + FeeManager: fees.NewManager(testUnitFees, fees.EmptyWindows), ConsumedUnitsCap: consumedUnitCaps, Credentials: sTx.Creds, } @@ -672,7 +672,7 @@ func TestCreateChainTxFees(t *testing.T) { IsEForkActive: cfg.IsEForkActivated(chainTime), Config: cfg, ChainTime: chainTime, - FeeManager: fees.NewManager(testUnitFees), + FeeManager: fees.NewManager(testUnitFees, fees.EmptyWindows), ConsumedUnitsCap: consumedUnitCaps, Credentials: sTx.Creds, } @@ -778,7 +778,7 @@ func TestCreateSubnetTxFees(t *testing.T) { IsEForkActive: cfg.IsEForkActivated(chainTime), Config: cfg, ChainTime: chainTime, - FeeManager: fees.NewManager(testUnitFees), + FeeManager: fees.NewManager(testUnitFees, fees.EmptyWindows), ConsumedUnitsCap: consumedUnitCaps, Credentials: sTx.Creds, } @@ -883,7 +883,7 @@ func TestRemoveSubnetValidatorTxFees(t *testing.T) { IsEForkActive: cfg.IsEForkActivated(chainTime), Config: cfg, ChainTime: chainTime, - FeeManager: fees.NewManager(testUnitFees), + FeeManager: fees.NewManager(testUnitFees, fees.EmptyWindows), ConsumedUnitsCap: consumedUnitCaps, Credentials: sTx.Creds, } @@ -1000,7 +1000,7 @@ func TestTransformSubnetTxFees(t *testing.T) { IsEForkActive: cfg.IsEForkActivated(chainTime), Config: cfg, ChainTime: chainTime, - FeeManager: fees.NewManager(testUnitFees), + FeeManager: fees.NewManager(testUnitFees, fees.EmptyWindows), ConsumedUnitsCap: consumedUnitCaps, Credentials: sTx.Creds, } @@ -1113,7 +1113,7 @@ func TestTransferSubnetOwnershipTxFees(t *testing.T) { IsEForkActive: cfg.IsEForkActivated(chainTime), Config: cfg, ChainTime: chainTime, - FeeManager: fees.NewManager(testUnitFees), + FeeManager: fees.NewManager(testUnitFees, fees.EmptyWindows), ConsumedUnitsCap: consumedUnitCaps, Credentials: sTx.Creds, } @@ -1235,7 +1235,7 @@ func TestAddPermissionlessValidatorTxFees(t *testing.T) { IsEForkActive: cfg.IsEForkActivated(chainTime), Config: cfg, ChainTime: chainTime, - FeeManager: fees.NewManager(testUnitFees), + FeeManager: fees.NewManager(testUnitFees, fees.EmptyWindows), ConsumedUnitsCap: consumedUnitCaps, Credentials: sTx.Creds, } @@ -1352,7 +1352,7 @@ func TestAddPermissionlessDelegatorTxFees(t *testing.T) { IsEForkActive: cfg.IsEForkActivated(chainTime), Config: cfg, ChainTime: chainTime, - FeeManager: fees.NewManager(testUnitFees), + FeeManager: fees.NewManager(testUnitFees, fees.EmptyWindows), ConsumedUnitsCap: consumedUnitCaps, Credentials: sTx.Creds, } @@ -1452,7 +1452,7 @@ func TestBaseTxFees(t *testing.T) { IsEForkActive: cfg.IsEForkActivated(chainTime), Config: cfg, ChainTime: chainTime, - FeeManager: fees.NewManager(testUnitFees), + FeeManager: fees.NewManager(testUnitFees, fees.EmptyWindows), ConsumedUnitsCap: consumedUnitCaps, Credentials: sTx.Creds, } @@ -1566,7 +1566,7 @@ func TestImportTxFees(t *testing.T) { IsEForkActive: cfg.IsEForkActivated(chainTime), Config: cfg, ChainTime: chainTime, - FeeManager: fees.NewManager(testUnitFees), + FeeManager: fees.NewManager(testUnitFees, fees.EmptyWindows), ConsumedUnitsCap: consumedUnitCaps, Credentials: sTx.Creds, } @@ -1670,7 +1670,7 @@ func TestExportTxFees(t *testing.T) { IsEForkActive: cfg.IsEForkActivated(chainTime), Config: cfg, ChainTime: chainTime, - FeeManager: fees.NewManager(testUnitFees), + FeeManager: fees.NewManager(testUnitFees, fees.EmptyWindows), ConsumedUnitsCap: consumedUnitCaps, Credentials: sTx.Creds, } diff --git a/vms/platformvm/utxo/handler_test.go b/vms/platformvm/utxo/handler_test.go index cc9a30cb5b8c..15e5cf0b5d8a 100644 --- a/vms/platformvm/utxo/handler_test.go +++ b/vms/platformvm/utxo/handler_test.go @@ -235,7 +235,7 @@ func TestVerifyFinanceTx(t *testing.T) { checksF: func(t *testing.T, uTx txs.UnsignedTx, ins []*avax.TransferableInput, outs, staked []*avax.TransferableOutput) { r := require.New(t) - fm := commonfees.NewManager(testUnitFees) + fm := commonfees.NewManager(testUnitFees, commonfees.EmptyWindows) calc := &fees.Calculator{ IsEForkActive: true, FeeManager: fm, @@ -316,7 +316,7 @@ func TestVerifyFinanceTx(t *testing.T) { checksF: func(t *testing.T, uTx txs.UnsignedTx, ins []*avax.TransferableInput, outs, staked []*avax.TransferableOutput) { r := require.New(t) - fm := commonfees.NewManager(testUnitFees) + fm := commonfees.NewManager(testUnitFees, commonfees.EmptyWindows) calc := &fees.Calculator{ IsEForkActive: true, FeeManager: fm, @@ -399,7 +399,7 @@ func TestVerifyFinanceTx(t *testing.T) { checksF: func(t *testing.T, uTx txs.UnsignedTx, ins []*avax.TransferableInput, outs, staked []*avax.TransferableOutput) { r := require.New(t) - fm := commonfees.NewManager(testUnitFees) + fm := commonfees.NewManager(testUnitFees, commonfees.EmptyWindows) calc := &fees.Calculator{ IsEForkActive: true, FeeManager: fm, @@ -477,7 +477,7 @@ func TestVerifyFinanceTx(t *testing.T) { checksF: func(t *testing.T, uTx txs.UnsignedTx, ins []*avax.TransferableInput, outs, staked []*avax.TransferableOutput) { r := require.New(t) - fm := commonfees.NewManager(testUnitFees) + fm := commonfees.NewManager(testUnitFees, commonfees.EmptyWindows) calc := &fees.Calculator{ IsEForkActive: true, FeeManager: fm, @@ -546,7 +546,7 @@ func TestVerifyFinanceTx(t *testing.T) { checksF: func(t *testing.T, uTx txs.UnsignedTx, ins []*avax.TransferableInput, outs, staked []*avax.TransferableOutput) { r := require.New(t) - fm := commonfees.NewManager(testUnitFees) + fm := commonfees.NewManager(testUnitFees, commonfees.EmptyWindows) calc := &fees.Calculator{ IsEForkActive: true, FeeManager: fm, @@ -616,7 +616,7 @@ func TestVerifyFinanceTx(t *testing.T) { checksF: func(t *testing.T, uTx txs.UnsignedTx, ins []*avax.TransferableInput, outs, staked []*avax.TransferableOutput) { r := require.New(t) - fm := commonfees.NewManager(testUnitFees) + fm := commonfees.NewManager(testUnitFees, commonfees.EmptyWindows) calc := &fees.Calculator{ IsEForkActive: true, FeeManager: fm, @@ -664,7 +664,7 @@ func TestVerifyFinanceTx(t *testing.T) { checksF: func(t *testing.T, uTx txs.UnsignedTx, ins []*avax.TransferableInput, outs, staked []*avax.TransferableOutput) { r := require.New(t) - fm := commonfees.NewManager(testUnitFees) + fm := commonfees.NewManager(testUnitFees, commonfees.EmptyWindows) calc := &fees.Calculator{ IsEForkActive: true, FeeManager: fm, @@ -689,7 +689,7 @@ func TestVerifyFinanceTx(t *testing.T) { uTx := test.uTxF(t) - fm := commonfees.NewManager(testUnitFees) + fm := commonfees.NewManager(testUnitFees, commonfees.EmptyWindows) feeCalc := &fees.Calculator{ IsEForkActive: true, FeeManager: fm, diff --git a/wallet/chain/p/builder_dynamic_fees.go b/wallet/chain/p/builder_dynamic_fees.go index 2a0e9c9469cb..043c4497ceca 100644 --- a/wallet/chain/p/builder_dynamic_fees.go +++ b/wallet/chain/p/builder_dynamic_fees.go @@ -66,7 +66,7 @@ func (b *DynamicFeesBuilder) NewBaseTx( toBurn[assetID] = amountToBurn } - feesMan := commonfees.NewManager(unitFees) + feesMan := commonfees.NewManager(unitFees, commonfees.EmptyWindows) feeCalc := &fees.Calculator{ IsEForkActive: true, FeeManager: feesMan, @@ -117,7 +117,7 @@ func (b *DynamicFeesBuilder) NewAddValidatorTx( } toBurn := map[ids.ID]uint64{} // fees are calculated in financeTx - feesMan := commonfees.NewManager(unitFees) + feesMan := commonfees.NewManager(unitFees, commonfees.EmptyWindows) feeCalc := &fees.Calculator{ IsEForkActive: true, FeeManager: feesMan, @@ -167,7 +167,7 @@ func (b *DynamicFeesBuilder) NewAddSubnetValidatorTx( toStake := map[ids.ID]uint64{} toBurn := map[ids.ID]uint64{} // fees are calculated in financeTx - feesMan := commonfees.NewManager(unitFees) + feesMan := commonfees.NewManager(unitFees, commonfees.EmptyWindows) feeCalc := &fees.Calculator{ IsEForkActive: true, FeeManager: feesMan, @@ -222,7 +222,7 @@ func (b *DynamicFeesBuilder) NewRemoveSubnetValidatorTx( toStake := map[ids.ID]uint64{} toBurn := map[ids.ID]uint64{} // fees are calculated in financeTx - feesMan := commonfees.NewManager(unitFees) + feesMan := commonfees.NewManager(unitFees, commonfees.EmptyWindows) feeCalc := &fees.Calculator{ IsEForkActive: true, FeeManager: feesMan, @@ -274,7 +274,7 @@ func (b *DynamicFeesBuilder) NewAddDelegatorTx( } toBurn := map[ids.ID]uint64{} // fees are calculated in financeTx - feesMan := commonfees.NewManager(unitFees) + feesMan := commonfees.NewManager(unitFees, commonfees.EmptyWindows) feeCalc := &fees.Calculator{ IsEForkActive: true, FeeManager: feesMan, @@ -334,7 +334,7 @@ func (b *DynamicFeesBuilder) NewCreateChainTx( toStake := map[ids.ID]uint64{} toBurn := map[ids.ID]uint64{} // fees are calculated in financeTx - feesMan := commonfees.NewManager(unitFees) + feesMan := commonfees.NewManager(unitFees, commonfees.EmptyWindows) feeCalc := &fees.Calculator{ IsEForkActive: true, FeeManager: feesMan, @@ -383,7 +383,7 @@ func (b *DynamicFeesBuilder) NewCreateSubnetTx( toStake := map[ids.ID]uint64{} toBurn := map[ids.ID]uint64{} // fees are calculated in financeTx - feesMan := commonfees.NewManager(unitFees) + feesMan := commonfees.NewManager(unitFees, commonfees.EmptyWindows) feeCalc := &fees.Calculator{ IsEForkActive: true, FeeManager: feesMan, @@ -498,7 +498,7 @@ func (b *DynamicFeesBuilder) NewImportTx( } // 3. Finance fees as much as possible with imported, Avax-denominated UTXOs - feesMan := commonfees.NewManager(unitFees) + feesMan := commonfees.NewManager(unitFees, commonfees.EmptyWindows) feeCalc := &fees.Calculator{ IsEForkActive: true, FeeManager: feesMan, @@ -611,7 +611,7 @@ func (b *DynamicFeesBuilder) NewExportTx( toBurn[assetID] = amountToBurn } - feesMan := commonfees.NewManager(unitFees) + feesMan := commonfees.NewManager(unitFees, commonfees.EmptyWindows) feeCalc := &fees.Calculator{ IsEForkActive: true, FeeManager: feesMan, @@ -689,7 +689,7 @@ func (b *DynamicFeesBuilder) NewTransformSubnetTx( assetID: maxSupply - initialSupply, } // fees are calculated in financeTx - feesMan := commonfees.NewManager(unitFees) + feesMan := commonfees.NewManager(unitFees, commonfees.EmptyWindows) feeCalc := &fees.Calculator{ IsEForkActive: true, FeeManager: feesMan, @@ -751,7 +751,7 @@ func (b *DynamicFeesBuilder) NewAddPermissionlessValidatorTx( } toBurn := map[ids.ID]uint64{} // fees are calculated in financeTx - feesMan := commonfees.NewManager(unitFees) + feesMan := commonfees.NewManager(unitFees, commonfees.EmptyWindows) feeCalc := &fees.Calculator{ IsEForkActive: true, FeeManager: feesMan, @@ -802,7 +802,7 @@ func (b *DynamicFeesBuilder) NewAddPermissionlessDelegatorTx( } toBurn := map[ids.ID]uint64{} // fees are calculated in financeTx - feesMan := commonfees.NewManager(unitFees) + feesMan := commonfees.NewManager(unitFees, commonfees.EmptyWindows) feeCalc := &fees.Calculator{ IsEForkActive: true, FeeManager: feesMan, diff --git a/wallet/chain/p/builder_dynamic_fees_test.go b/wallet/chain/p/builder_dynamic_fees_test.go index b08f992f2b30..9702ac0112d7 100644 --- a/wallet/chain/p/builder_dynamic_fees_test.go +++ b/wallet/chain/p/builder_dynamic_fees_test.go @@ -102,7 +102,7 @@ func TestBaseTx(t *testing.T) { fc := &fees.Calculator{ IsEForkActive: true, - FeeManager: commonfees.NewManager(testUnitFees), + FeeManager: commonfees.NewManager(testUnitFees, commonfees.EmptyWindows), ConsumedUnitsCap: testBlockMaxConsumedUnits, Credentials: tx.Creds, } @@ -173,7 +173,7 @@ func TestAddValidatorTx(t *testing.T) { fc := &fees.Calculator{ IsEForkActive: true, - FeeManager: commonfees.NewManager(testUnitFees), + FeeManager: commonfees.NewManager(testUnitFees, commonfees.EmptyWindows), ConsumedUnitsCap: testBlockMaxConsumedUnits, Credentials: tx.Creds, } @@ -251,7 +251,7 @@ func TestAddSubnetValidatorTx(t *testing.T) { fc := &fees.Calculator{ IsEForkActive: true, - FeeManager: commonfees.NewManager(testUnitFees), + FeeManager: commonfees.NewManager(testUnitFees, commonfees.EmptyWindows), ConsumedUnitsCap: testBlockMaxConsumedUnits, Credentials: tx.Creds, } @@ -321,7 +321,7 @@ func TestRemoveSubnetValidatorTx(t *testing.T) { fc := &fees.Calculator{ IsEForkActive: true, - FeeManager: commonfees.NewManager(testUnitFees), + FeeManager: commonfees.NewManager(testUnitFees, commonfees.EmptyWindows), ConsumedUnitsCap: testBlockMaxConsumedUnits, Credentials: tx.Creds, } @@ -390,7 +390,7 @@ func TestAddDelegatorTx(t *testing.T) { fc := &fees.Calculator{ IsEForkActive: true, - FeeManager: commonfees.NewManager(testUnitFees), + FeeManager: commonfees.NewManager(testUnitFees, commonfees.EmptyWindows), ConsumedUnitsCap: testBlockMaxConsumedUnits, Credentials: tx.Creds, } @@ -472,7 +472,7 @@ func TestCreateChainTx(t *testing.T) { fc := &fees.Calculator{ IsEForkActive: true, - FeeManager: commonfees.NewManager(testUnitFees), + FeeManager: commonfees.NewManager(testUnitFees, commonfees.EmptyWindows), ConsumedUnitsCap: testBlockMaxConsumedUnits, Credentials: tx.Creds, } @@ -535,7 +535,7 @@ func TestCreateSubnetTx(t *testing.T) { fc := &fees.Calculator{ IsEForkActive: true, - FeeManager: commonfees.NewManager(testUnitFees), + FeeManager: commonfees.NewManager(testUnitFees, commonfees.EmptyWindows), ConsumedUnitsCap: testBlockMaxConsumedUnits, Credentials: tx.Creds, } @@ -606,7 +606,7 @@ func TestImportTx(t *testing.T) { fc := &fees.Calculator{ IsEForkActive: true, - FeeManager: commonfees.NewManager(testUnitFees), + FeeManager: commonfees.NewManager(testUnitFees, commonfees.EmptyWindows), ConsumedUnitsCap: testBlockMaxConsumedUnits, Credentials: tx.Creds, } @@ -677,7 +677,7 @@ func TestExportTx(t *testing.T) { fc := &fees.Calculator{ IsEForkActive: true, - FeeManager: commonfees.NewManager(testUnitFees), + FeeManager: commonfees.NewManager(testUnitFees, commonfees.EmptyWindows), ConsumedUnitsCap: testBlockMaxConsumedUnits, Credentials: tx.Creds, } @@ -765,7 +765,7 @@ func TestTransformSubnetTx(t *testing.T) { fc := &fees.Calculator{ IsEForkActive: true, - FeeManager: commonfees.NewManager(testUnitFees), + FeeManager: commonfees.NewManager(testUnitFees, commonfees.EmptyWindows), ConsumedUnitsCap: testBlockMaxConsumedUnits, Credentials: tx.Creds, } @@ -851,7 +851,7 @@ func TestAddPermissionlessValidatorTx(t *testing.T) { fc := &fees.Calculator{ IsEForkActive: true, - FeeManager: commonfees.NewManager(testUnitFees), + FeeManager: commonfees.NewManager(testUnitFees, commonfees.EmptyWindows), ConsumedUnitsCap: testBlockMaxConsumedUnits, Credentials: tx.Creds, } @@ -927,7 +927,7 @@ func TestAddPermissionlessDelegatorTx(t *testing.T) { fc := &fees.Calculator{ IsEForkActive: true, - FeeManager: commonfees.NewManager(testUnitFees), + FeeManager: commonfees.NewManager(testUnitFees, commonfees.EmptyWindows), ConsumedUnitsCap: testBlockMaxConsumedUnits, Credentials: tx.Creds, } diff --git a/wallet/chain/x/builder_dynamic_fees.go b/wallet/chain/x/builder_dynamic_fees.go index 82d2f949c247..3ff382c17af0 100644 --- a/wallet/chain/x/builder_dynamic_fees.go +++ b/wallet/chain/x/builder_dynamic_fees.go @@ -64,7 +64,7 @@ func (b *DynamicFeesBuilder) NewBaseTx( toBurn[assetID] = amountToBurn } - feesMan := commonfees.NewManager(unitFees) + feesMan := commonfees.NewManager(unitFees, commonfees.EmptyWindows) feeCalc := &fees.Calculator{ IsEForkActive: true, Codec: Parser.Codec(), @@ -128,7 +128,7 @@ func (b *DynamicFeesBuilder) NewCreateAssetTx( // 2. Finance the tx by building the utxos (inputs, outputs and stakes) toBurn := map[ids.ID]uint64{} // fees are calculated in financeTx - feesMan := commonfees.NewManager(unitFees) + feesMan := commonfees.NewManager(unitFees, commonfees.EmptyWindows) feeCalc := &fees.Calculator{ IsEForkActive: true, Codec: Parser.Codec(), @@ -173,7 +173,7 @@ func (b *DynamicFeesBuilder) NewOperationTx( // 2. Finance the tx by building the utxos (inputs, outputs and stakes) toBurn := map[ids.ID]uint64{} // fees are calculated in financeTx - feesMan := commonfees.NewManager(unitFees) + feesMan := commonfees.NewManager(unitFees, commonfees.EmptyWindows) feeCalc := &fees.Calculator{ IsEForkActive: true, Codec: Parser.Codec(), @@ -364,7 +364,7 @@ func (b *DynamicFeesBuilder) NewImportTx( } // 3. Finance fees as much as possible with imported, Avax-denominated UTXOs - feesMan := commonfees.NewManager(unitFees) + feesMan := commonfees.NewManager(unitFees, commonfees.EmptyWindows) feeCalc := &fees.Calculator{ IsEForkActive: true, Codec: Parser.Codec(), @@ -476,7 +476,7 @@ func (b *DynamicFeesBuilder) NewExportTx( toBurn[assetID] = amountToBurn } - feesMan := commonfees.NewManager(unitFees) + feesMan := commonfees.NewManager(unitFees, commonfees.EmptyWindows) feeCalc := &fees.Calculator{ IsEForkActive: true, Codec: Parser.Codec(), diff --git a/wallet/chain/x/builder_dynamic_fees_test.go b/wallet/chain/x/builder_dynamic_fees_test.go index 722777045f3f..cfa7c48b8dcb 100644 --- a/wallet/chain/x/builder_dynamic_fees_test.go +++ b/wallet/chain/x/builder_dynamic_fees_test.go @@ -104,7 +104,7 @@ func TestBaseTx(t *testing.T) { fc := &fees.Calculator{ IsEForkActive: true, Codec: Parser.Codec(), - FeeManager: commonfees.NewManager(testUnitFees), + FeeManager: commonfees.NewManager(testUnitFees, commonfees.EmptyWindows), ConsumedUnitsCap: testBlockMaxConsumedUnits, Credentials: tx.Creds, } @@ -216,7 +216,7 @@ func TestCreateAssetTx(t *testing.T) { fc := &fees.Calculator{ IsEForkActive: true, Codec: Parser.Codec(), - FeeManager: commonfees.NewManager(testUnitFees), + FeeManager: commonfees.NewManager(testUnitFees, commonfees.EmptyWindows), ConsumedUnitsCap: testBlockMaxConsumedUnits, Credentials: tx.Creds, } @@ -289,7 +289,7 @@ func TestImportTx(t *testing.T) { fc := &fees.Calculator{ IsEForkActive: true, Codec: Parser.Codec(), - FeeManager: commonfees.NewManager(testUnitFees), + FeeManager: commonfees.NewManager(testUnitFees, commonfees.EmptyWindows), ConsumedUnitsCap: testBlockMaxConsumedUnits, Credentials: tx.Creds, } @@ -362,7 +362,7 @@ func TestExportTx(t *testing.T) { fc := &fees.Calculator{ IsEForkActive: true, Codec: Parser.Codec(), - FeeManager: commonfees.NewManager(testUnitFees), + FeeManager: commonfees.NewManager(testUnitFees, commonfees.EmptyWindows), ConsumedUnitsCap: testBlockMaxConsumedUnits, Credentials: tx.Creds, } From 1606c8302016c4a626fc9fb940584b495e5dec3d Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Wed, 31 Jan 2024 16:51:36 +0100 Subject: [PATCH 097/190] wip: persisting dynamic unit fees and windows --- vms/components/fees/manager.go | 6 +- vms/platformvm/block/builder/builder.go | 10 +- vms/platformvm/block/builder/helpers_test.go | 5 +- vms/platformvm/block/executor/helpers_test.go | 6 +- vms/platformvm/block/executor/manager.go | 9 +- .../block/executor/proposal_block_test.go | 1 + .../block/executor/standard_block_test.go | 6 +- vms/platformvm/block/executor/verifier.go | 10 +- .../block/executor/verifier_test.go | 4 + vms/platformvm/state/diff.go | 11 ++ vms/platformvm/state/mock_state.go | 59 ++++++++ vms/platformvm/state/state.go | 21 ++- vms/platformvm/txs/builder/builder.go | 140 ++++++++++++++---- vms/platformvm/txs/executor/helpers_test.go | 5 +- 14 files changed, 248 insertions(+), 45 deletions(-) diff --git a/vms/components/fees/manager.go b/vms/components/fees/manager.go index b6c9afbd3e9f..efb61a078865 100644 --- a/vms/components/fees/manager.go +++ b/vms/components/fees/manager.go @@ -10,21 +10,21 @@ import ( safemath "github.com/ava-labs/avalanchego/utils/math" ) -// Fees are not dynamic yet. We'll add mechanism for fee updating iterativelly +type Windows [FeeDimensions]Window type Manager struct { // Avax denominated unit fees for all fee dimensions unitFees Dimensions // cunsumed units window per each fee dimension. - windows [FeeDimensions]Window + windows Windows // cumulatedUnits helps aggregating the units consumed by a block // so that we can verify it's not too big/build it properly. cumulatedUnits Dimensions } -func NewManager(unitFees Dimensions, windows [FeeDimensions]Window) *Manager { +func NewManager(unitFees Dimensions, windows Windows) *Manager { return &Manager{ unitFees: unitFees, windows: windows, diff --git a/vms/platformvm/block/builder/builder.go b/vms/platformvm/block/builder/builder.go index 07061501669e..cf3c28b984a6 100644 --- a/vms/platformvm/block/builder/builder.go +++ b/vms/platformvm/block/builder/builder.go @@ -379,14 +379,22 @@ func packBlockTxs( if err != nil { return nil, err } + + // TODO ABENEGIA: this should probably be a config quantity, related to forks + // but not really dynamically changing much over time unitCaps, err := txDiff.GetBlockUnitCaps() if err != nil { return nil, err } + unitWindows, err := txDiff.GetConsumedUnitsWindows() + if err != nil { + return nil, err + } + executor := &txexecutor.StandardTxExecutor{ Backend: backend, - BlkFeeManager: fees.NewManager(unitFees, fees.EmptyWindows), + BlkFeeManager: fees.NewManager(unitFees, unitWindows), UnitCaps: unitCaps, State: txDiff, Tx: tx, diff --git a/vms/platformvm/block/builder/helpers_test.go b/vms/platformvm/block/builder/helpers_test.go index 72ed6b86691b..4152bc27ab92 100644 --- a/vms/platformvm/block/builder/helpers_test.go +++ b/vms/platformvm/block/builder/helpers_test.go @@ -261,9 +261,12 @@ func addSubnet(t *testing.T, env *environment) { unitCaps, err := env.state.GetBlockUnitCaps() require.NoError(err) + unitWindows, err := env.state.GetConsumedUnitsWindows() + require.NoError(err) + executor := txexecutor.StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(unitFees, fees.EmptyWindows), + BlkFeeManager: fees.NewManager(unitFees, unitWindows), UnitCaps: unitCaps, State: stateDiff, Tx: testSubnet1, diff --git a/vms/platformvm/block/executor/helpers_test.go b/vms/platformvm/block/executor/helpers_test.go index 969052177377..c9f82a182da3 100644 --- a/vms/platformvm/block/executor/helpers_test.go +++ b/vms/platformvm/block/executor/helpers_test.go @@ -283,10 +283,14 @@ func addSubnet(env *environment) { if err != nil { panic(err) } + unitWindows, err := env.state.GetConsumedUnitsWindows() + if err != nil { + panic(err) + } executor := executor.StandardTxExecutor{ Backend: env.backend, - BlkFeeManager: fees.NewManager(unitFees, fees.EmptyWindows), + BlkFeeManager: fees.NewManager(unitFees, unitWindows), UnitCaps: unitCaps, State: stateDiff, Tx: testSubnet1, diff --git a/vms/platformvm/block/executor/manager.go b/vms/platformvm/block/executor/manager.go index 5f9555d5bde8..d179a576da8f 100644 --- a/vms/platformvm/block/executor/manager.go +++ b/vms/platformvm/block/executor/manager.go @@ -148,14 +148,21 @@ func (m *manager) VerifyTx(tx *txs.Tx) error { return err } + // TODO ABENEGIA: this should probably be a config quantity, related to forks + // but not really dynamically changing much over time unitCaps, err := stateDiff.GetBlockUnitCaps() if err != nil { return err } + unitWindows, err := stateDiff.GetConsumedUnitsWindows() + if err != nil { + return err + } + err = tx.Unsigned.Visit(&executor.StandardTxExecutor{ Backend: m.txExecutorBackend, - BlkFeeManager: fees.NewManager(unitFees, fees.EmptyWindows), + BlkFeeManager: fees.NewManager(unitFees, unitWindows), UnitCaps: unitCaps, State: stateDiff, Tx: tx, diff --git a/vms/platformvm/block/executor/proposal_block_test.go b/vms/platformvm/block/executor/proposal_block_test.go index 55cc0370db1e..4e8224df845c 100644 --- a/vms/platformvm/block/executor/proposal_block_test.go +++ b/vms/platformvm/block/executor/proposal_block_test.go @@ -164,6 +164,7 @@ func TestBanffProposalBlockTimeVerification(t *testing.T) { onParentAccept.EXPECT().GetUnitFees().Return(commonfees.EmptyUnitFees, nil).AnyTimes() onParentAccept.EXPECT().GetBlockUnitCaps().Return(commonfees.EmptyUnitCaps, nil).AnyTimes() onParentAccept.EXPECT().GetCurrentSupply(constants.PrimaryNetworkID).Return(uint64(1000), nil).AnyTimes() + onParentAccept.EXPECT().GetConsumedUnitsWindows().Return(commonfees.EmptyWindows, nil).AnyTimes() env.blkManager.(*manager).blkIDToState[parentID] = &blockState{ statelessBlock: banffParentBlk, diff --git a/vms/platformvm/block/executor/standard_block_test.go b/vms/platformvm/block/executor/standard_block_test.go index 1bdcdd67e504..9f29487809af 100644 --- a/vms/platformvm/block/executor/standard_block_test.go +++ b/vms/platformvm/block/executor/standard_block_test.go @@ -18,13 +18,14 @@ import ( "github.com/ava-labs/avalanchego/utils/constants" "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" "github.com/ava-labs/avalanchego/vms/components/avax" - commonfees "github.com/ava-labs/avalanchego/vms/components/fees" "github.com/ava-labs/avalanchego/vms/platformvm/block" "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/secp256k1fx" + + commonfees "github.com/ava-labs/avalanchego/vms/components/fees" ) func TestApricotStandardBlockTimeVerification(t *testing.T) { @@ -59,6 +60,8 @@ func TestApricotStandardBlockTimeVerification(t *testing.T) { onParentAccept.EXPECT().GetTimestamp().Return(chainTime).AnyTimes() onParentAccept.EXPECT().GetUnitFees().Return(commonfees.EmptyUnitFees, nil) onParentAccept.EXPECT().GetBlockUnitCaps().Return(commonfees.EmptyUnitCaps, nil) + onParentAccept.EXPECT().GetConsumedUnitsWindows().Return(commonfees.EmptyWindows, nil) + // wrong height apricotChildBlk, err := block.NewApricotStandardBlock( apricotParentBlk.ID(), @@ -154,6 +157,7 @@ func TestBanffStandardBlockTimeVerification(t *testing.T) { onParentAccept.EXPECT().GetUTXO(utxoID).Return(utxo, nil).AnyTimes() onParentAccept.EXPECT().GetUnitFees().Return(commonfees.EmptyUnitFees, nil).AnyTimes() onParentAccept.EXPECT().GetBlockUnitCaps().Return(commonfees.EmptyUnitCaps, nil).AnyTimes() + onParentAccept.EXPECT().GetConsumedUnitsWindows().Return(commonfees.EmptyWindows, 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 0ff6cbf85c8c..6dcb4106c4ae 100644 --- a/vms/platformvm/block/executor/verifier.go +++ b/vms/platformvm/block/executor/verifier.go @@ -449,13 +449,21 @@ func (v *verifier) processStandardTxs(txs []*txs.Tx, state state.Diff, parentID if err != nil { return nil, nil, nil, err } - feeManager := fees.NewManager(unitFees, fees.EmptyWindows) + // TODO ABENEGIA: this should probably be a config quantity, related to forks + // but not really dynamically changing much over time unitCaps, err := state.GetBlockUnitCaps() if err != nil { return nil, nil, nil, err } + unitWindows, err := state.GetConsumedUnitsWindows() + if err != nil { + return nil, nil, nil, err + } + + feeManager := fees.NewManager(unitFees, unitWindows) + for _, tx := range txs { txExecutor := executor.StandardTxExecutor{ Backend: v.txExecutorBackend, diff --git a/vms/platformvm/block/executor/verifier_test.go b/vms/platformvm/block/executor/verifier_test.go index c303caaeb17f..e025847d38b6 100644 --- a/vms/platformvm/block/executor/verifier_test.go +++ b/vms/platformvm/block/executor/verifier_test.go @@ -289,6 +289,8 @@ func TestVerifierVisitStandardBlock(t *testing.T) { parentState.EXPECT().GetTimestamp().Return(timestamp).Times(1) parentState.EXPECT().GetUnitFees().Return(commonfees.EmptyUnitFees, nil) parentState.EXPECT().GetBlockUnitCaps().Return(commonfees.EmptyUnitCaps, nil) + parentState.EXPECT().GetConsumedUnitsWindows().Return(commonfees.EmptyWindows, nil) + parentStatelessBlk.EXPECT().Height().Return(uint64(1)).Times(1) mempool.EXPECT().Remove(apricotBlk.Txs()).Times(1) @@ -770,6 +772,8 @@ func TestVerifierVisitStandardBlockWithDuplicateInputs(t *testing.T) { parentState.EXPECT().GetTimestamp().Return(timestamp).Times(1) parentState.EXPECT().GetUnitFees().Return(commonfees.EmptyUnitFees, nil) parentState.EXPECT().GetBlockUnitCaps().Return(commonfees.EmptyUnitCaps, nil) + parentState.EXPECT().GetConsumedUnitsWindows().Return(commonfees.EmptyWindows, nil) + parentStatelessBlk.EXPECT().Parent().Return(grandParentID).Times(1) err = verifier.ApricotStandardBlock(blk) diff --git a/vms/platformvm/state/diff.go b/vms/platformvm/state/diff.go index d6fa41fcbe01..a5dc0aa08756 100644 --- a/vms/platformvm/state/diff.go +++ b/vms/platformvm/state/diff.go @@ -90,6 +90,7 @@ func NewDiffOn(parentState Chain) (Diff, error) { }) } +// TODO ABENEGIA: fix method with dynamic fees func (d *diff) GetUnitFees() (commonfees.Dimensions, error) { parentState, ok := d.stateVersions.GetState(d.parentID) if !ok { @@ -98,6 +99,7 @@ func (d *diff) GetUnitFees() (commonfees.Dimensions, error) { return parentState.GetUnitFees() } +// TODO ABENEGIA: fix method with dynamic fees func (d *diff) GetBlockUnitCaps() (commonfees.Dimensions, error) { parentState, ok := d.stateVersions.GetState(d.parentID) if !ok { @@ -106,6 +108,15 @@ func (d *diff) GetBlockUnitCaps() (commonfees.Dimensions, error) { return parentState.GetBlockUnitCaps() } +// TODO ABENEGIA: fix method with dynamic fees +func (d *diff) GetConsumedUnitsWindows() (commonfees.Windows, error) { + parentState, ok := d.stateVersions.GetState(d.parentID) + if !ok { + return commonfees.Windows{}, fmt.Errorf("%w: %s", ErrMissingParentState, d.parentID) + } + return parentState.GetConsumedUnitsWindows() +} + func (d *diff) GetTimestamp() time.Time { return d.timestamp } diff --git a/vms/platformvm/state/mock_state.go b/vms/platformvm/state/mock_state.go index 573127bdbe32..92648658bbed 100644 --- a/vms/platformvm/state/mock_state.go +++ b/vms/platformvm/state/mock_state.go @@ -198,6 +198,21 @@ func (mr *MockChainMockRecorder) GetBlockUnitCaps() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBlockUnitCaps", reflect.TypeOf((*MockChain)(nil).GetBlockUnitCaps)) } +// GetConsumedUnitsWindows mocks base method. +func (m *MockChain) GetConsumedUnitsWindows() (fees.Windows, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetConsumedUnitsWindows") + ret0, _ := ret[0].(fees.Windows) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetConsumedUnitsWindows indicates an expected call of GetConsumedUnitsWindows. +func (mr *MockChainMockRecorder) GetConsumedUnitsWindows() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetConsumedUnitsWindows", reflect.TypeOf((*MockChain)(nil).GetConsumedUnitsWindows)) +} + // GetCurrentDelegatorIterator mocks base method. func (m *MockChain) GetCurrentDelegatorIterator(arg0 ids.ID, arg1 ids.NodeID) (StakerIterator, error) { m.ctrl.T.Helper() @@ -690,6 +705,21 @@ func (mr *MockDiffMockRecorder) GetBlockUnitCaps() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBlockUnitCaps", reflect.TypeOf((*MockDiff)(nil).GetBlockUnitCaps)) } +// GetConsumedUnitsWindows mocks base method. +func (m *MockDiff) GetConsumedUnitsWindows() (fees.Windows, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetConsumedUnitsWindows") + ret0, _ := ret[0].(fees.Windows) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetConsumedUnitsWindows indicates an expected call of GetConsumedUnitsWindows. +func (mr *MockDiffMockRecorder) GetConsumedUnitsWindows() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetConsumedUnitsWindows", reflect.TypeOf((*MockDiff)(nil).GetConsumedUnitsWindows)) +} + // GetCurrentDelegatorIterator mocks base method. func (m *MockDiff) GetCurrentDelegatorIterator(arg0 ids.ID, arg1 ids.NodeID) (StakerIterator, error) { m.ctrl.T.Helper() @@ -1307,6 +1337,21 @@ func (mr *MockStateMockRecorder) GetChains(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetChains", reflect.TypeOf((*MockState)(nil).GetChains), arg0) } +// GetConsumedUnitsWindows mocks base method. +func (m *MockState) GetConsumedUnitsWindows() (fees.Windows, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetConsumedUnitsWindows") + ret0, _ := ret[0].(fees.Windows) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetConsumedUnitsWindows indicates an expected call of GetConsumedUnitsWindows. +func (mr *MockStateMockRecorder) GetConsumedUnitsWindows() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetConsumedUnitsWindows", reflect.TypeOf((*MockState)(nil).GetConsumedUnitsWindows)) +} + // GetCurrentDelegatorIterator mocks base method. func (m *MockState) GetCurrentDelegatorIterator(arg0 ids.ID, arg1 ids.NodeID) (StakerIterator, error) { m.ctrl.T.Helper() @@ -1683,6 +1728,20 @@ func (mr *MockStateMockRecorder) SetBlockUnitCaps(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetBlockUnitCaps", reflect.TypeOf((*MockState)(nil).SetBlockUnitCaps), arg0) } +// SetConsumedUnitsWindows mocks base method. +func (m *MockState) SetConsumedUnitsWindows(arg0 fees.Windows) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetConsumedUnitsWindows", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// SetConsumedUnitsWindows indicates an expected call of SetConsumedUnitsWindows. +func (mr *MockStateMockRecorder) SetConsumedUnitsWindows(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetConsumedUnitsWindows", reflect.TypeOf((*MockState)(nil).SetConsumedUnitsWindows), 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 f2374098c68b..0eae75783056 100644 --- a/vms/platformvm/state/state.go +++ b/vms/platformvm/state/state.go @@ -102,9 +102,9 @@ type Chain interface { avax.UTXOGetter avax.UTXODeleter - // at this iteration we don't need to reset these, we are just metering GetUnitFees() (commonfees.Dimensions, error) GetBlockUnitCaps() (commonfees.Dimensions, error) + GetConsumedUnitsWindows() (commonfees.Windows, error) GetTimestamp() time.Time SetTimestamp(tm time.Time) @@ -150,6 +150,7 @@ type State interface { // At this iteration these getters are helpful for UTs only SetUnitFees(uf commonfees.Dimensions) error SetBlockUnitCaps(caps commonfees.Dimensions) error + SetConsumedUnitsWindows(windows commonfees.Windows) error // ApplyValidatorWeightDiffs iterates from [startHeight] towards the genesis // block until it has applied all of the diffs up to and including @@ -386,10 +387,11 @@ type state struct { indexedHeights *heightRange singletonDB database.Database - // multifees data are not persisted at this stage. We just meter for now, - // we'll revisit when we'll introduce dynamic fees - unitFees commonfees.Dimensions - blockUnitCaps commonfees.Dimensions + // TODO ABENEGIA: handle persistence of these attributes + // Maybe blockUnitCaps is an exception, since it should be a fork related quantity + unitFees commonfees.Dimensions + blockUnitCaps commonfees.Dimensions + consumedUnitsWindows commonfees.Windows } // heightRange is used to track which heights are safe to use the native DB @@ -1114,6 +1116,15 @@ func (s *state) SetBlockUnitCaps(caps commonfees.Dimensions) error { return nil } +func (s *state) GetConsumedUnitsWindows() (commonfees.Windows, error) { + return s.consumedUnitsWindows, nil +} + +func (s *state) SetConsumedUnitsWindows(windows commonfees.Windows) error { + s.consumedUnitsWindows = windows + return nil +} + func (s *state) GetTimestamp() time.Time { return s.timestamp } diff --git a/vms/platformvm/txs/builder/builder.go b/vms/platformvm/txs/builder/builder.go index 5addb88ce20c..44c0655e8dd0 100644 --- a/vms/platformvm/txs/builder/builder.go +++ b/vms/platformvm/txs/builder/builder.go @@ -311,24 +311,32 @@ func (b *builder) NewImportTx( ) if isEForkActive { var ( - unitFees commonfees.Dimensions - unitCaps commonfees.Dimensions + unitFees commonfees.Dimensions + unitCaps commonfees.Dimensions + unitWindows commonfees.Windows ) unitFees, err = b.state.GetUnitFees() if err != nil { return nil, err } + // TODO ABENEGIA: this should probably be a config quantity, related to forks + // but not really dynamically changing much over time unitCaps, err = b.state.GetBlockUnitCaps() if err != nil { return nil, err } + unitWindows, err = b.state.GetConsumedUnitsWindows() + if err != nil { + return nil, err + } + // while outs are not ordered we add them to get current fees. We'll fix ordering later on utx.BaseTx.Outs = outs feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, - FeeManager: commonfees.NewManager(unitFees, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(unitFees, unitWindows), ConsumedUnitsCap: unitCaps, Credentials: txs.EmptyCredentials(signers), } @@ -479,22 +487,30 @@ func (b *builder) NewExportTx( ) if isEForkActive { var ( - unitFees commonfees.Dimensions - unitCaps commonfees.Dimensions + unitFees commonfees.Dimensions + unitCaps commonfees.Dimensions + unitWindows commonfees.Windows ) unitFees, err = b.state.GetUnitFees() if err != nil { return nil, err } + // TODO ABENEGIA: this should probably be a config quantity, related to forks + // but not really dynamically changing much over time unitCaps, err = b.state.GetBlockUnitCaps() if err != nil { return nil, err } + unitWindows, err = b.state.GetConsumedUnitsWindows() + if err != nil { + return nil, err + } + feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, - FeeManager: commonfees.NewManager(unitFees, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(unitFees, unitWindows), ConsumedUnitsCap: unitCaps, Credentials: txs.EmptyCredentials(signers), } @@ -574,22 +590,30 @@ func (b *builder) NewCreateChainTx( ) if isEForkActive { var ( - unitFees commonfees.Dimensions - unitCaps commonfees.Dimensions + unitFees commonfees.Dimensions + unitCaps commonfees.Dimensions + unitWindows commonfees.Windows ) unitFees, err = b.state.GetUnitFees() if err != nil { return nil, err } + // TODO ABENEGIA: this should probably be a config quantity, related to forks + // but not really dynamically changing much over time unitCaps, err = b.state.GetBlockUnitCaps() if err != nil { return nil, err } + unitWindows, err = b.state.GetConsumedUnitsWindows() + if err != nil { + return nil, err + } + feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, - FeeManager: commonfees.NewManager(unitFees, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(unitFees, unitWindows), ConsumedUnitsCap: unitCaps, Credentials: txs.EmptyCredentials(signers), } @@ -658,22 +682,30 @@ func (b *builder) NewCreateSubnetTx( ) if isEForkActive { var ( - unitFees commonfees.Dimensions - unitCaps commonfees.Dimensions + unitFees commonfees.Dimensions + unitCaps commonfees.Dimensions + unitWindows commonfees.Windows ) unitFees, err = b.state.GetUnitFees() if err != nil { return nil, err } + // TODO ABENEGIA: this should probably be a config quantity, related to forks + // but not really dynamically changing much over time unitCaps, err = b.state.GetBlockUnitCaps() if err != nil { return nil, err } + unitWindows, err = b.state.GetConsumedUnitsWindows() + if err != nil { + return nil, err + } + feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, - FeeManager: commonfees.NewManager(unitFees, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(unitFees, unitWindows), ConsumedUnitsCap: unitCaps, Credentials: txs.EmptyCredentials(signers), } @@ -751,22 +783,30 @@ func (b *builder) NewAddValidatorTx( ) if isEForkActive { var ( - unitFees commonfees.Dimensions - unitCaps commonfees.Dimensions + unitFees commonfees.Dimensions + unitCaps commonfees.Dimensions + unitWindows commonfees.Windows ) unitFees, err = b.state.GetUnitFees() if err != nil { return nil, err } + // TODO ABENEGIA: this should probably be a config quantity, related to forks + // but not really dynamically changing much over time unitCaps, err = b.state.GetBlockUnitCaps() if err != nil { return nil, err } + unitWindows, err = b.state.GetConsumedUnitsWindows() + if err != nil { + return nil, err + } + feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, - FeeManager: commonfees.NewManager(unitFees, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(unitFees, unitWindows), ConsumedUnitsCap: unitCaps, Credentials: txs.EmptyCredentials(signers), } @@ -842,22 +882,30 @@ func (b *builder) NewAddDelegatorTx( ) if isEForkActive { var ( - unitFees commonfees.Dimensions - unitCaps commonfees.Dimensions + unitFees commonfees.Dimensions + unitCaps commonfees.Dimensions + unitWindows commonfees.Windows ) unitFees, err = b.state.GetUnitFees() if err != nil { return nil, err } + // TODO ABENEGIA: this should probably be a config quantity, related to forks + // but not really dynamically changing much over time unitCaps, err = b.state.GetBlockUnitCaps() if err != nil { return nil, err } + unitWindows, err = b.state.GetConsumedUnitsWindows() + if err != nil { + return nil, err + } + feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, - FeeManager: commonfees.NewManager(unitFees, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(unitFees, unitWindows), ConsumedUnitsCap: unitCaps, Credentials: txs.EmptyCredentials(signers), } @@ -934,22 +982,30 @@ func (b *builder) NewAddSubnetValidatorTx( ) if isEForkActive { var ( - unitFees commonfees.Dimensions - unitCaps commonfees.Dimensions + unitFees commonfees.Dimensions + unitCaps commonfees.Dimensions + unitWindows commonfees.Windows ) unitFees, err = b.state.GetUnitFees() if err != nil { return nil, err } + // TODO ABENEGIA: this should probably be a config quantity, related to forks + // but not really dynamically changing much over time unitCaps, err = b.state.GetBlockUnitCaps() if err != nil { return nil, err } + unitWindows, err = b.state.GetConsumedUnitsWindows() + if err != nil { + return nil, err + } + feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, - FeeManager: commonfees.NewManager(unitFees, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(unitFees, unitWindows), ConsumedUnitsCap: unitCaps, Credentials: txs.EmptyCredentials(signers), } @@ -1016,22 +1072,30 @@ func (b *builder) NewRemoveSubnetValidatorTx( ) if isEForkActive { var ( - unitFees commonfees.Dimensions - unitCaps commonfees.Dimensions + unitFees commonfees.Dimensions + unitCaps commonfees.Dimensions + unitWindows commonfees.Windows ) unitFees, err = b.state.GetUnitFees() if err != nil { return nil, err } + // TODO ABENEGIA: this should probably be a config quantity, related to forks + // but not really dynamically changing much over time unitCaps, err = b.state.GetBlockUnitCaps() if err != nil { return nil, err } + unitWindows, err = b.state.GetConsumedUnitsWindows() + if err != nil { + return nil, err + } + feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, - FeeManager: commonfees.NewManager(unitFees, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(unitFees, unitWindows), ConsumedUnitsCap: unitCaps, Credentials: txs.EmptyCredentials(signers), } @@ -1112,22 +1176,30 @@ func (b *builder) NewTransferSubnetOwnershipTx( ) if isEForkActive { var ( - unitFees commonfees.Dimensions - unitCaps commonfees.Dimensions + unitFees commonfees.Dimensions + unitCaps commonfees.Dimensions + unitWindows commonfees.Windows ) unitFees, err = b.state.GetUnitFees() if err != nil { return nil, err } + // TODO ABENEGIA: this should probably be a config quantity, related to forks + // but not really dynamically changing much over time unitCaps, err = b.state.GetBlockUnitCaps() if err != nil { return nil, err } + unitWindows, err = b.state.GetConsumedUnitsWindows() + if err != nil { + return nil, err + } + feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, - FeeManager: commonfees.NewManager(unitFees, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(unitFees, unitWindows), ConsumedUnitsCap: unitCaps, Credentials: txs.EmptyCredentials(signers), } @@ -1188,22 +1260,30 @@ func (b *builder) NewBaseTx( ) if isEForkActive { var ( - unitFees commonfees.Dimensions - unitCaps commonfees.Dimensions + unitFees commonfees.Dimensions + unitCaps commonfees.Dimensions + unitWindows commonfees.Windows ) unitFees, err = b.state.GetUnitFees() if err != nil { return nil, err } + // TODO ABENEGIA: this should probably be a config quantity, related to forks + // but not really dynamically changing much over time unitCaps, err = b.state.GetBlockUnitCaps() if err != nil { return nil, err } + unitWindows, err = b.state.GetConsumedUnitsWindows() + if err != nil { + return nil, err + } + feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, - FeeManager: commonfees.NewManager(unitFees, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(unitFees, unitWindows), ConsumedUnitsCap: unitCaps, Credentials: txs.EmptyCredentials(signers), } diff --git a/vms/platformvm/txs/executor/helpers_test.go b/vms/platformvm/txs/executor/helpers_test.go index 0b2123293f23..7799d7dc4c9e 100644 --- a/vms/platformvm/txs/executor/helpers_test.go +++ b/vms/platformvm/txs/executor/helpers_test.go @@ -235,9 +235,12 @@ func addSubnet( unitCaps, err := env.state.GetBlockUnitCaps() require.NoError(err) + unitWindows, err := env.state.GetConsumedUnitsWindows() + require.NoError(err) + executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(unitFees, fees.EmptyWindows), + BlkFeeManager: fees.NewManager(unitFees, unitWindows), UnitCaps: unitCaps, State: stateDiff, Tx: testSubnet1, From 66443116dfbf3425d6fa24b97bc643b2d2d1f42b Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 1 Feb 2024 11:04:56 +0100 Subject: [PATCH 098/190] wip: introducing dynamic fees config --- vms/platformvm/block/builder/builder.go | 9 +- vms/platformvm/block/builder/helpers_test.go | 5 +- vms/platformvm/block/executor/helpers_test.go | 6 +- vms/platformvm/block/executor/manager.go | 10 +- .../block/executor/proposal_block_test.go | 1 - .../block/executor/standard_block_test.go | 2 - vms/platformvm/block/executor/verifier.go | 10 +- .../block/executor/verifier_test.go | 2 - vms/platformvm/config/config.go | 5 + vms/platformvm/config/dynamic_fees_config.go | 98 +++++++++++ vms/platformvm/service.go | 5 +- vms/platformvm/service_test.go | 41 ++--- vms/platformvm/state/diff.go | 12 +- vms/platformvm/state/mock_state.go | 59 ------- vms/platformvm/state/state.go | 16 +- vms/platformvm/txs/builder/builder.go | 154 +++++------------- vms/platformvm/txs/executor/helpers_test.go | 5 +- vms/platformvm/txs/fees/calculator.go | 23 +-- 18 files changed, 179 insertions(+), 284 deletions(-) create mode 100644 vms/platformvm/config/dynamic_fees_config.go diff --git a/vms/platformvm/block/builder/builder.go b/vms/platformvm/block/builder/builder.go index cf3c28b984a6..647b45a861bf 100644 --- a/vms/platformvm/block/builder/builder.go +++ b/vms/platformvm/block/builder/builder.go @@ -380,13 +380,6 @@ func packBlockTxs( return nil, err } - // TODO ABENEGIA: this should probably be a config quantity, related to forks - // but not really dynamically changing much over time - unitCaps, err := txDiff.GetBlockUnitCaps() - if err != nil { - return nil, err - } - unitWindows, err := txDiff.GetConsumedUnitsWindows() if err != nil { return nil, err @@ -395,7 +388,7 @@ func packBlockTxs( executor := &txexecutor.StandardTxExecutor{ Backend: backend, BlkFeeManager: fees.NewManager(unitFees, unitWindows), - UnitCaps: unitCaps, + UnitCaps: backend.Config.GetDynamicFeesConfig().BlockUnitsCap, State: txDiff, Tx: tx, } diff --git a/vms/platformvm/block/builder/helpers_test.go b/vms/platformvm/block/builder/helpers_test.go index 4152bc27ab92..b99e418c5d55 100644 --- a/vms/platformvm/block/builder/helpers_test.go +++ b/vms/platformvm/block/builder/helpers_test.go @@ -258,16 +258,13 @@ func addSubnet(t *testing.T, env *environment) { unitFees, err := env.state.GetUnitFees() require.NoError(err) - unitCaps, err := env.state.GetBlockUnitCaps() - require.NoError(err) - unitWindows, err := env.state.GetConsumedUnitsWindows() require.NoError(err) executor := txexecutor.StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: fees.NewManager(unitFees, unitWindows), - UnitCaps: unitCaps, + UnitCaps: env.backend.Config.GetDynamicFeesConfig().BlockUnitsCap, State: stateDiff, Tx: testSubnet1, } diff --git a/vms/platformvm/block/executor/helpers_test.go b/vms/platformvm/block/executor/helpers_test.go index c9f82a182da3..0627c744d7ed 100644 --- a/vms/platformvm/block/executor/helpers_test.go +++ b/vms/platformvm/block/executor/helpers_test.go @@ -279,10 +279,6 @@ func addSubnet(env *environment) { if err != nil { panic(err) } - unitCaps, err := env.state.GetBlockUnitCaps() - if err != nil { - panic(err) - } unitWindows, err := env.state.GetConsumedUnitsWindows() if err != nil { panic(err) @@ -291,7 +287,7 @@ func addSubnet(env *environment) { executor := executor.StandardTxExecutor{ Backend: env.backend, BlkFeeManager: fees.NewManager(unitFees, unitWindows), - UnitCaps: unitCaps, + UnitCaps: env.backend.Config.GetDynamicFeesConfig().BlockUnitsCap, State: stateDiff, Tx: testSubnet1, } diff --git a/vms/platformvm/block/executor/manager.go b/vms/platformvm/block/executor/manager.go index d179a576da8f..a611a28a25ab 100644 --- a/vms/platformvm/block/executor/manager.go +++ b/vms/platformvm/block/executor/manager.go @@ -147,14 +147,6 @@ func (m *manager) VerifyTx(tx *txs.Tx) error { if err != nil { return err } - - // TODO ABENEGIA: this should probably be a config quantity, related to forks - // but not really dynamically changing much over time - unitCaps, err := stateDiff.GetBlockUnitCaps() - if err != nil { - return err - } - unitWindows, err := stateDiff.GetConsumedUnitsWindows() if err != nil { return err @@ -163,7 +155,7 @@ func (m *manager) VerifyTx(tx *txs.Tx) error { err = tx.Unsigned.Visit(&executor.StandardTxExecutor{ Backend: m.txExecutorBackend, BlkFeeManager: fees.NewManager(unitFees, unitWindows), - UnitCaps: unitCaps, + UnitCaps: m.txExecutorBackend.Config.GetDynamicFeesConfig().BlockUnitsCap, State: stateDiff, Tx: tx, }) diff --git a/vms/platformvm/block/executor/proposal_block_test.go b/vms/platformvm/block/executor/proposal_block_test.go index 4e8224df845c..681672fe9c41 100644 --- a/vms/platformvm/block/executor/proposal_block_test.go +++ b/vms/platformvm/block/executor/proposal_block_test.go @@ -162,7 +162,6 @@ func TestBanffProposalBlockTimeVerification(t *testing.T) { onParentAccept := state.NewMockDiff(ctrl) onParentAccept.EXPECT().GetTimestamp().Return(parentTime).AnyTimes() onParentAccept.EXPECT().GetUnitFees().Return(commonfees.EmptyUnitFees, nil).AnyTimes() - onParentAccept.EXPECT().GetBlockUnitCaps().Return(commonfees.EmptyUnitCaps, nil).AnyTimes() onParentAccept.EXPECT().GetCurrentSupply(constants.PrimaryNetworkID).Return(uint64(1000), nil).AnyTimes() onParentAccept.EXPECT().GetConsumedUnitsWindows().Return(commonfees.EmptyWindows, nil).AnyTimes() diff --git a/vms/platformvm/block/executor/standard_block_test.go b/vms/platformvm/block/executor/standard_block_test.go index 9f29487809af..06247d8b04ae 100644 --- a/vms/platformvm/block/executor/standard_block_test.go +++ b/vms/platformvm/block/executor/standard_block_test.go @@ -59,7 +59,6 @@ func TestApricotStandardBlockTimeVerification(t *testing.T) { env.mockedState.EXPECT().GetTimestamp().Return(chainTime).AnyTimes() onParentAccept.EXPECT().GetTimestamp().Return(chainTime).AnyTimes() onParentAccept.EXPECT().GetUnitFees().Return(commonfees.EmptyUnitFees, nil) - onParentAccept.EXPECT().GetBlockUnitCaps().Return(commonfees.EmptyUnitCaps, nil) onParentAccept.EXPECT().GetConsumedUnitsWindows().Return(commonfees.EmptyWindows, nil) // wrong height @@ -156,7 +155,6 @@ func TestBanffStandardBlockTimeVerification(t *testing.T) { utxoID := utxo.InputID() onParentAccept.EXPECT().GetUTXO(utxoID).Return(utxo, nil).AnyTimes() onParentAccept.EXPECT().GetUnitFees().Return(commonfees.EmptyUnitFees, nil).AnyTimes() - onParentAccept.EXPECT().GetBlockUnitCaps().Return(commonfees.EmptyUnitCaps, nil).AnyTimes() onParentAccept.EXPECT().GetConsumedUnitsWindows().Return(commonfees.EmptyWindows, nil).AnyTimes() // Create the tx diff --git a/vms/platformvm/block/executor/verifier.go b/vms/platformvm/block/executor/verifier.go index 6dcb4106c4ae..b62fafc1f118 100644 --- a/vms/platformvm/block/executor/verifier.go +++ b/vms/platformvm/block/executor/verifier.go @@ -449,14 +449,6 @@ func (v *verifier) processStandardTxs(txs []*txs.Tx, state state.Diff, parentID if err != nil { return nil, nil, nil, err } - - // TODO ABENEGIA: this should probably be a config quantity, related to forks - // but not really dynamically changing much over time - unitCaps, err := state.GetBlockUnitCaps() - if err != nil { - return nil, nil, nil, err - } - unitWindows, err := state.GetConsumedUnitsWindows() if err != nil { return nil, nil, nil, err @@ -468,7 +460,7 @@ func (v *verifier) processStandardTxs(txs []*txs.Tx, state state.Diff, parentID txExecutor := executor.StandardTxExecutor{ Backend: v.txExecutorBackend, BlkFeeManager: feeManager, - UnitCaps: unitCaps, + UnitCaps: v.txExecutorBackend.Config.GetDynamicFeesConfig().BlockUnitsCap, State: state, Tx: tx, } diff --git a/vms/platformvm/block/executor/verifier_test.go b/vms/platformvm/block/executor/verifier_test.go index e025847d38b6..87caf1adeee4 100644 --- a/vms/platformvm/block/executor/verifier_test.go +++ b/vms/platformvm/block/executor/verifier_test.go @@ -288,7 +288,6 @@ func TestVerifierVisitStandardBlock(t *testing.T) { timestamp := time.Now() parentState.EXPECT().GetTimestamp().Return(timestamp).Times(1) parentState.EXPECT().GetUnitFees().Return(commonfees.EmptyUnitFees, nil) - parentState.EXPECT().GetBlockUnitCaps().Return(commonfees.EmptyUnitCaps, nil) parentState.EXPECT().GetConsumedUnitsWindows().Return(commonfees.EmptyWindows, nil) parentStatelessBlk.EXPECT().Height().Return(uint64(1)).Times(1) @@ -771,7 +770,6 @@ func TestVerifierVisitStandardBlockWithDuplicateInputs(t *testing.T) { parentStatelessBlk.EXPECT().Height().Return(uint64(1)).Times(1) parentState.EXPECT().GetTimestamp().Return(timestamp).Times(1) parentState.EXPECT().GetUnitFees().Return(commonfees.EmptyUnitFees, nil) - parentState.EXPECT().GetBlockUnitCaps().Return(commonfees.EmptyUnitCaps, nil) parentState.EXPECT().GetConsumedUnitsWindows().Return(commonfees.EmptyWindows, nil) parentStatelessBlk.EXPECT().Parent().Return(grandParentID).Times(1) diff --git a/vms/platformvm/config/config.go b/vms/platformvm/config/config.go index aca79f446024..d61913ae306e 100644 --- a/vms/platformvm/config/config.go +++ b/vms/platformvm/config/config.go @@ -158,6 +158,11 @@ func (c *Config) GetCreateSubnetTxFee(timestamp time.Time) uint64 { return c.CreateAssetTxFee } +// TODO ABENEGIA: consider structuring this method to handle forks (or is it YAGNI?) +func (*Config) GetDynamicFeesConfig() DynamicFeesConfig { + return EForkDynamicFeesConfig +} + // Create the blockchain described in [tx], but only if this node is a member of // the subnet that validates the chain func (c *Config) CreateChain(chainID ids.ID, tx *txs.CreateChainTx) { diff --git a/vms/platformvm/config/dynamic_fees_config.go b/vms/platformvm/config/dynamic_fees_config.go new file mode 100644 index 000000000000..551e02de7f6f --- /dev/null +++ b/vms/platformvm/config/dynamic_fees_config.go @@ -0,0 +1,98 @@ +// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package config + +import ( + "fmt" + "math" + + commonfees "github.com/ava-labs/avalanchego/vms/components/fees" +) + +// Dynamic fees configs become relevant with dynamic fees introduction in E-fork +// We cannot easily include then in Config since they do not come from genesis +// They don't feel like an execution config either, since we need a fork upgrade +// to update them (testing is a different story). +// I am setting them in a separate config object, but will access it via Config +// so to have fork control over which dynamic fees is picked + +func init() { + if err := EForkDynamicFeesConfig.validate(); err != nil { + panic(err) + } +} + +// EForkDynamicFeesConfig to be tuned TODO ABENEGIA +var EForkDynamicFeesConfig = DynamicFeesConfig{ + InitialUnitFees: commonfees.Dimensions{ + 1, + 2, + 3, + 4, + }, + + BlockUnitsCap: commonfees.Dimensions{ + math.MaxUint64, + math.MaxUint64, + math.MaxUint64, + math.MaxUint64, + }, + + BlockUnitsTarget: commonfees.Dimensions{ + 1, + 1, + 1, + 1, + }, +} + +type DynamicFeesConfig struct { + // InitialUnitFees contains, per each fee dimension, the + // unit fees valid as soon as fork introducing dynamic fees + // activates. Unit fees will be then updated by the dynamic fees algo. + InitialUnitFees commonfees.Dimensions + + // MinUnitFees contains, per each fee dimension, the + // minimal unit fees enforced by the dynamic fees algo. + MinUnitFees commonfees.Dimensions + + // FeesChangeDenominator contains, per each fee dimension, the + // minimal unit fees change + FeesChangeDenominator commonfees.Dimensions + + // BlockUnitsCap contains, per each fee dimension, the + // maximal complexity a valid P-chain block can host + BlockUnitsCap commonfees.Dimensions + + // BlockUnitsTarget contains, per each fee dimension, the + // preferred block complexity that the dynamic fee algo + // strive to converge to + BlockUnitsTarget commonfees.Dimensions +} + +func (c *DynamicFeesConfig) validate() error { + for i := commonfees.Dimension(0); i < commonfees.FeeDimensions; i++ { + if c.InitialUnitFees[i] < c.MinUnitFees[i] { + return fmt.Errorf("dimension %d, initial unit fee %d smaller than minimal unit fee %d", + i, + c.InitialUnitFees[i], + c.MinUnitFees[i], + ) + } + + if c.BlockUnitsTarget[i] > c.BlockUnitsCap[i] { + return fmt.Errorf("dimension %d, block target units %d larger than block units cap %d", + i, + c.BlockUnitsTarget[i], + c.BlockUnitsCap[i], + ) + } + + if c.BlockUnitsTarget[i] == 0 { + return fmt.Errorf("dimension %d, block target units set to zero", i) + } + } + + return nil +} diff --git a/vms/platformvm/service.go b/vms/platformvm/service.go index 2a211dd738f6..6d77a4478b01 100644 --- a/vms/platformvm/service.go +++ b/vms/platformvm/service.go @@ -2848,9 +2848,8 @@ func (s *Service) GetBlockUnitsCap(_ *http.Request, _ *struct{}, reply *GetBlock s.vm.ctx.Lock.Lock() defer s.vm.ctx.Lock.Unlock() - var err error - reply.MaxUnits, err = s.vm.state.GetBlockUnitCaps() - return err + reply.MaxUnits = s.vm.Config.GetDynamicFeesConfig().BlockUnitsCap + return nil } func (s *Service) getAPIUptime(staker *state.Staker) (*json.Float32, error) { diff --git a/vms/platformvm/service_test.go b/vms/platformvm/service_test.go index 3700384068c4..b646160c171c 100644 --- a/vms/platformvm/service_test.go +++ b/vms/platformvm/service_test.go @@ -1043,30 +1043,31 @@ func TestGetUnitFees(t *testing.T) { require.Equal(updatedUnitFees, reply.UnitFees) } -func TestGetBlockUnitsCap(t *testing.T) { - require := require.New(t) - service, _ := defaultService(t) +// TODO ABENEGIA: rethink the way to pull up this stuff +// func TestGetBlockUnitsCap(t *testing.T) { +// require := require.New(t) +// service, _ := defaultService(t) - reply := GetBlockUnitsCapReply{} - require.NoError(service.GetBlockUnitsCap(nil, nil, &reply)) +// reply := GetBlockUnitsCapReply{} +// require.NoError(service.GetBlockUnitsCap(nil, nil, &reply)) - service.vm.ctx.Lock.Lock() +// service.vm.ctx.Lock.Lock() - unitCaps, err := service.vm.state.GetBlockUnitCaps() - require.NoError(err) +// unitCaps, err := service.vm.state.GetBlockUnitCaps() +// require.NoError(err) - require.Equal(unitCaps, reply.MaxUnits) +// require.Equal(unitCaps, reply.MaxUnits) - updatedUnitCaps := commonfees.Dimensions{ - 123, - 456, - 789, - 1011, - } - require.NoError(service.vm.state.SetBlockUnitCaps(updatedUnitCaps)) +// updatedUnitCaps := commonfees.Dimensions{ +// 123, +// 456, +// 789, +// 1011, +// } +// require.NoError(service.vm.state.SetBlockUnitCaps(updatedUnitCaps)) - service.vm.ctx.Lock.Unlock() +// service.vm.ctx.Lock.Unlock() - require.NoError(service.GetBlockUnitsCap(nil, nil, &reply)) - require.Equal(updatedUnitCaps, reply.MaxUnits) -} +// require.NoError(service.GetBlockUnitsCap(nil, nil, &reply)) +// require.Equal(updatedUnitCaps, reply.MaxUnits) +// } diff --git a/vms/platformvm/state/diff.go b/vms/platformvm/state/diff.go index a5dc0aa08756..69b2309b835a 100644 --- a/vms/platformvm/state/diff.go +++ b/vms/platformvm/state/diff.go @@ -11,10 +11,11 @@ import ( "github.com/ava-labs/avalanchego/database" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/vms/components/avax" - commonfees "github.com/ava-labs/avalanchego/vms/components/fees" "github.com/ava-labs/avalanchego/vms/platformvm/fx" "github.com/ava-labs/avalanchego/vms/platformvm/status" "github.com/ava-labs/avalanchego/vms/platformvm/txs" + + commonfees "github.com/ava-labs/avalanchego/vms/components/fees" ) var ( @@ -99,15 +100,6 @@ func (d *diff) GetUnitFees() (commonfees.Dimensions, error) { return parentState.GetUnitFees() } -// TODO ABENEGIA: fix method with dynamic fees -func (d *diff) GetBlockUnitCaps() (commonfees.Dimensions, error) { - parentState, ok := d.stateVersions.GetState(d.parentID) - if !ok { - return commonfees.Dimensions{}, fmt.Errorf("%w: %s", ErrMissingParentState, d.parentID) - } - return parentState.GetBlockUnitCaps() -} - // TODO ABENEGIA: fix method with dynamic fees func (d *diff) GetConsumedUnitsWindows() (commonfees.Windows, error) { parentState, ok := d.stateVersions.GetState(d.parentID) diff --git a/vms/platformvm/state/mock_state.go b/vms/platformvm/state/mock_state.go index 92648658bbed..329754b98d5d 100644 --- a/vms/platformvm/state/mock_state.go +++ b/vms/platformvm/state/mock_state.go @@ -183,21 +183,6 @@ func (mr *MockChainMockRecorder) DeleteUTXO(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteUTXO", reflect.TypeOf((*MockChain)(nil).DeleteUTXO), arg0) } -// GetBlockUnitCaps mocks base method. -func (m *MockChain) GetBlockUnitCaps() (fees.Dimensions, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetBlockUnitCaps") - ret0, _ := ret[0].(fees.Dimensions) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetBlockUnitCaps indicates an expected call of GetBlockUnitCaps. -func (mr *MockChainMockRecorder) GetBlockUnitCaps() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBlockUnitCaps", reflect.TypeOf((*MockChain)(nil).GetBlockUnitCaps)) -} - // GetConsumedUnitsWindows mocks base method. func (m *MockChain) GetConsumedUnitsWindows() (fees.Windows, error) { m.ctrl.T.Helper() @@ -690,21 +675,6 @@ func (mr *MockDiffMockRecorder) DeleteUTXO(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteUTXO", reflect.TypeOf((*MockDiff)(nil).DeleteUTXO), arg0) } -// GetBlockUnitCaps mocks base method. -func (m *MockDiff) GetBlockUnitCaps() (fees.Dimensions, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetBlockUnitCaps") - ret0, _ := ret[0].(fees.Dimensions) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetBlockUnitCaps indicates an expected call of GetBlockUnitCaps. -func (mr *MockDiffMockRecorder) GetBlockUnitCaps() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBlockUnitCaps", reflect.TypeOf((*MockDiff)(nil).GetBlockUnitCaps)) -} - // GetConsumedUnitsWindows mocks base method. func (m *MockDiff) GetConsumedUnitsWindows() (fees.Windows, error) { m.ctrl.T.Helper() @@ -1307,21 +1277,6 @@ func (mr *MockStateMockRecorder) GetBlockIDAtHeight(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBlockIDAtHeight", reflect.TypeOf((*MockState)(nil).GetBlockIDAtHeight), arg0) } -// GetBlockUnitCaps mocks base method. -func (m *MockState) GetBlockUnitCaps() (fees.Dimensions, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetBlockUnitCaps") - ret0, _ := ret[0].(fees.Dimensions) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetBlockUnitCaps indicates an expected call of GetBlockUnitCaps. -func (mr *MockStateMockRecorder) GetBlockUnitCaps() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBlockUnitCaps", reflect.TypeOf((*MockState)(nil).GetBlockUnitCaps)) -} - // GetChains mocks base method. func (m *MockState) GetChains(arg0 ids.ID) ([]*txs.Tx, error) { m.ctrl.T.Helper() @@ -1714,20 +1669,6 @@ func (mr *MockStateMockRecorder) PutPendingValidator(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PutPendingValidator", reflect.TypeOf((*MockState)(nil).PutPendingValidator), arg0) } -// SetBlockUnitCaps mocks base method. -func (m *MockState) SetBlockUnitCaps(arg0 fees.Dimensions) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SetBlockUnitCaps", arg0) - ret0, _ := ret[0].(error) - return ret0 -} - -// SetBlockUnitCaps indicates an expected call of SetBlockUnitCaps. -func (mr *MockStateMockRecorder) SetBlockUnitCaps(arg0 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetBlockUnitCaps", reflect.TypeOf((*MockState)(nil).SetBlockUnitCaps), arg0) -} - // SetConsumedUnitsWindows mocks base method. func (m *MockState) SetConsumedUnitsWindows(arg0 fees.Windows) error { m.ctrl.T.Helper() diff --git a/vms/platformvm/state/state.go b/vms/platformvm/state/state.go index 0eae75783056..cceb50c33145 100644 --- a/vms/platformvm/state/state.go +++ b/vms/platformvm/state/state.go @@ -44,7 +44,6 @@ 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/fees" safemath "github.com/ava-labs/avalanchego/utils/math" commonfees "github.com/ava-labs/avalanchego/vms/components/fees" @@ -103,7 +102,6 @@ type Chain interface { avax.UTXODeleter GetUnitFees() (commonfees.Dimensions, error) - GetBlockUnitCaps() (commonfees.Dimensions, error) GetConsumedUnitsWindows() (commonfees.Windows, error) GetTimestamp() time.Time @@ -149,7 +147,6 @@ type State interface { // At this iteration these getters are helpful for UTs only SetUnitFees(uf commonfees.Dimensions) error - SetBlockUnitCaps(caps commonfees.Dimensions) error SetConsumedUnitsWindows(windows commonfees.Windows) error // ApplyValidatorWeightDiffs iterates from [startHeight] towards the genesis @@ -390,7 +387,6 @@ type state struct { // TODO ABENEGIA: handle persistence of these attributes // Maybe blockUnitCaps is an exception, since it should be a fork related quantity unitFees commonfees.Dimensions - blockUnitCaps commonfees.Dimensions consumedUnitsWindows commonfees.Windows } @@ -722,8 +718,7 @@ func newState( singletonDB: prefixdb.New(SingletonPrefix, baseDB), - unitFees: fees.DefaultUnitFees, - blockUnitCaps: fees.DefaultBlockMaxConsumedUnits, + unitFees: cfg.GetDynamicFeesConfig().InitialUnitFees, }, nil } @@ -1107,15 +1102,6 @@ func (s *state) SetUnitFees(uf commonfees.Dimensions) error { return nil } -func (s *state) GetBlockUnitCaps() (commonfees.Dimensions, error) { - return s.blockUnitCaps, nil -} - -func (s *state) SetBlockUnitCaps(caps commonfees.Dimensions) error { - s.blockUnitCaps = caps - return nil -} - func (s *state) GetConsumedUnitsWindows() (commonfees.Windows, error) { return s.consumedUnitsWindows, nil } diff --git a/vms/platformvm/txs/builder/builder.go b/vms/platformvm/txs/builder/builder.go index 44c0655e8dd0..dd709a44915e 100644 --- a/vms/platformvm/txs/builder/builder.go +++ b/vms/platformvm/txs/builder/builder.go @@ -311,22 +311,15 @@ func (b *builder) NewImportTx( ) if isEForkActive { var ( - unitFees commonfees.Dimensions - unitCaps commonfees.Dimensions - unitWindows commonfees.Windows + dynamicFeesConfig = b.cfg.GetDynamicFeesConfig() + unitFees commonfees.Dimensions + unitWindows commonfees.Windows ) - unitFees, err = b.state.GetUnitFees() - if err != nil { - return nil, err - } - // TODO ABENEGIA: this should probably be a config quantity, related to forks - // but not really dynamically changing much over time - unitCaps, err = b.state.GetBlockUnitCaps() + unitFees, err = b.state.GetUnitFees() if err != nil { return nil, err } - unitWindows, err = b.state.GetConsumedUnitsWindows() if err != nil { return nil, err @@ -337,7 +330,7 @@ func (b *builder) NewImportTx( feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, FeeManager: commonfees.NewManager(unitFees, unitWindows), - ConsumedUnitsCap: unitCaps, + ConsumedUnitsCap: dynamicFeesConfig.BlockUnitsCap, Credentials: txs.EmptyCredentials(signers), } @@ -487,22 +480,15 @@ func (b *builder) NewExportTx( ) if isEForkActive { var ( - unitFees commonfees.Dimensions - unitCaps commonfees.Dimensions - unitWindows commonfees.Windows + dynamicFeesConfig = b.cfg.GetDynamicFeesConfig() + unitFees commonfees.Dimensions + unitWindows commonfees.Windows ) unitFees, err = b.state.GetUnitFees() if err != nil { return nil, err } - // TODO ABENEGIA: this should probably be a config quantity, related to forks - // but not really dynamically changing much over time - unitCaps, err = b.state.GetBlockUnitCaps() - if err != nil { - return nil, err - } - unitWindows, err = b.state.GetConsumedUnitsWindows() if err != nil { return nil, err @@ -511,7 +497,7 @@ func (b *builder) NewExportTx( feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, FeeManager: commonfees.NewManager(unitFees, unitWindows), - ConsumedUnitsCap: unitCaps, + ConsumedUnitsCap: dynamicFeesConfig.BlockUnitsCap, Credentials: txs.EmptyCredentials(signers), } @@ -590,22 +576,15 @@ func (b *builder) NewCreateChainTx( ) if isEForkActive { var ( - unitFees commonfees.Dimensions - unitCaps commonfees.Dimensions - unitWindows commonfees.Windows + dynamicFeesConfig = b.cfg.GetDynamicFeesConfig() + unitFees commonfees.Dimensions + unitWindows commonfees.Windows ) unitFees, err = b.state.GetUnitFees() if err != nil { return nil, err } - // TODO ABENEGIA: this should probably be a config quantity, related to forks - // but not really dynamically changing much over time - unitCaps, err = b.state.GetBlockUnitCaps() - if err != nil { - return nil, err - } - unitWindows, err = b.state.GetConsumedUnitsWindows() if err != nil { return nil, err @@ -614,7 +593,7 @@ func (b *builder) NewCreateChainTx( feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, FeeManager: commonfees.NewManager(unitFees, unitWindows), - ConsumedUnitsCap: unitCaps, + ConsumedUnitsCap: dynamicFeesConfig.BlockUnitsCap, Credentials: txs.EmptyCredentials(signers), } @@ -682,22 +661,15 @@ func (b *builder) NewCreateSubnetTx( ) if isEForkActive { var ( - unitFees commonfees.Dimensions - unitCaps commonfees.Dimensions - unitWindows commonfees.Windows + dynamicFeesConfig = b.cfg.GetDynamicFeesConfig() + unitFees commonfees.Dimensions + unitWindows commonfees.Windows ) unitFees, err = b.state.GetUnitFees() if err != nil { return nil, err } - // TODO ABENEGIA: this should probably be a config quantity, related to forks - // but not really dynamically changing much over time - unitCaps, err = b.state.GetBlockUnitCaps() - if err != nil { - return nil, err - } - unitWindows, err = b.state.GetConsumedUnitsWindows() if err != nil { return nil, err @@ -706,7 +678,7 @@ func (b *builder) NewCreateSubnetTx( feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, FeeManager: commonfees.NewManager(unitFees, unitWindows), - ConsumedUnitsCap: unitCaps, + ConsumedUnitsCap: dynamicFeesConfig.BlockUnitsCap, Credentials: txs.EmptyCredentials(signers), } @@ -783,22 +755,15 @@ func (b *builder) NewAddValidatorTx( ) if isEForkActive { var ( - unitFees commonfees.Dimensions - unitCaps commonfees.Dimensions - unitWindows commonfees.Windows + dynamicFeesConfig = b.cfg.GetDynamicFeesConfig() + unitFees commonfees.Dimensions + unitWindows commonfees.Windows ) unitFees, err = b.state.GetUnitFees() if err != nil { return nil, err } - // TODO ABENEGIA: this should probably be a config quantity, related to forks - // but not really dynamically changing much over time - unitCaps, err = b.state.GetBlockUnitCaps() - if err != nil { - return nil, err - } - unitWindows, err = b.state.GetConsumedUnitsWindows() if err != nil { return nil, err @@ -807,7 +772,7 @@ func (b *builder) NewAddValidatorTx( feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, FeeManager: commonfees.NewManager(unitFees, unitWindows), - ConsumedUnitsCap: unitCaps, + ConsumedUnitsCap: dynamicFeesConfig.BlockUnitsCap, Credentials: txs.EmptyCredentials(signers), } @@ -882,22 +847,15 @@ func (b *builder) NewAddDelegatorTx( ) if isEForkActive { var ( - unitFees commonfees.Dimensions - unitCaps commonfees.Dimensions - unitWindows commonfees.Windows + dynamicFeesConfig = b.cfg.GetDynamicFeesConfig() + unitFees commonfees.Dimensions + unitWindows commonfees.Windows ) unitFees, err = b.state.GetUnitFees() if err != nil { return nil, err } - // TODO ABENEGIA: this should probably be a config quantity, related to forks - // but not really dynamically changing much over time - unitCaps, err = b.state.GetBlockUnitCaps() - if err != nil { - return nil, err - } - unitWindows, err = b.state.GetConsumedUnitsWindows() if err != nil { return nil, err @@ -906,7 +864,7 @@ func (b *builder) NewAddDelegatorTx( feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, FeeManager: commonfees.NewManager(unitFees, unitWindows), - ConsumedUnitsCap: unitCaps, + ConsumedUnitsCap: dynamicFeesConfig.BlockUnitsCap, Credentials: txs.EmptyCredentials(signers), } @@ -982,22 +940,15 @@ func (b *builder) NewAddSubnetValidatorTx( ) if isEForkActive { var ( - unitFees commonfees.Dimensions - unitCaps commonfees.Dimensions - unitWindows commonfees.Windows + dynamicFeesConfig = b.cfg.GetDynamicFeesConfig() + unitFees commonfees.Dimensions + unitWindows commonfees.Windows ) unitFees, err = b.state.GetUnitFees() if err != nil { return nil, err } - // TODO ABENEGIA: this should probably be a config quantity, related to forks - // but not really dynamically changing much over time - unitCaps, err = b.state.GetBlockUnitCaps() - if err != nil { - return nil, err - } - unitWindows, err = b.state.GetConsumedUnitsWindows() if err != nil { return nil, err @@ -1006,7 +957,7 @@ func (b *builder) NewAddSubnetValidatorTx( feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, FeeManager: commonfees.NewManager(unitFees, unitWindows), - ConsumedUnitsCap: unitCaps, + ConsumedUnitsCap: dynamicFeesConfig.BlockUnitsCap, Credentials: txs.EmptyCredentials(signers), } @@ -1072,22 +1023,15 @@ func (b *builder) NewRemoveSubnetValidatorTx( ) if isEForkActive { var ( - unitFees commonfees.Dimensions - unitCaps commonfees.Dimensions - unitWindows commonfees.Windows + dynamicFeesConfig = b.cfg.GetDynamicFeesConfig() + unitFees commonfees.Dimensions + unitWindows commonfees.Windows ) unitFees, err = b.state.GetUnitFees() if err != nil { return nil, err } - // TODO ABENEGIA: this should probably be a config quantity, related to forks - // but not really dynamically changing much over time - unitCaps, err = b.state.GetBlockUnitCaps() - if err != nil { - return nil, err - } - unitWindows, err = b.state.GetConsumedUnitsWindows() if err != nil { return nil, err @@ -1096,7 +1040,7 @@ func (b *builder) NewRemoveSubnetValidatorTx( feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, FeeManager: commonfees.NewManager(unitFees, unitWindows), - ConsumedUnitsCap: unitCaps, + ConsumedUnitsCap: dynamicFeesConfig.BlockUnitsCap, Credentials: txs.EmptyCredentials(signers), } @@ -1176,22 +1120,15 @@ func (b *builder) NewTransferSubnetOwnershipTx( ) if isEForkActive { var ( - unitFees commonfees.Dimensions - unitCaps commonfees.Dimensions - unitWindows commonfees.Windows + dynamicFeesConfig = b.cfg.GetDynamicFeesConfig() + unitFees commonfees.Dimensions + unitWindows commonfees.Windows ) - unitFees, err = b.state.GetUnitFees() - if err != nil { - return nil, err - } - // TODO ABENEGIA: this should probably be a config quantity, related to forks - // but not really dynamically changing much over time - unitCaps, err = b.state.GetBlockUnitCaps() + unitFees, err = b.state.GetUnitFees() if err != nil { return nil, err } - unitWindows, err = b.state.GetConsumedUnitsWindows() if err != nil { return nil, err @@ -1200,7 +1137,7 @@ func (b *builder) NewTransferSubnetOwnershipTx( feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, FeeManager: commonfees.NewManager(unitFees, unitWindows), - ConsumedUnitsCap: unitCaps, + ConsumedUnitsCap: dynamicFeesConfig.BlockUnitsCap, Credentials: txs.EmptyCredentials(signers), } @@ -1260,22 +1197,15 @@ func (b *builder) NewBaseTx( ) if isEForkActive { var ( - unitFees commonfees.Dimensions - unitCaps commonfees.Dimensions - unitWindows commonfees.Windows + dynamicFeesConfig = b.cfg.GetDynamicFeesConfig() + unitFees commonfees.Dimensions + unitWindows commonfees.Windows ) unitFees, err = b.state.GetUnitFees() if err != nil { return nil, err } - // TODO ABENEGIA: this should probably be a config quantity, related to forks - // but not really dynamically changing much over time - unitCaps, err = b.state.GetBlockUnitCaps() - if err != nil { - return nil, err - } - unitWindows, err = b.state.GetConsumedUnitsWindows() if err != nil { return nil, err @@ -1284,7 +1214,7 @@ func (b *builder) NewBaseTx( feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, FeeManager: commonfees.NewManager(unitFees, unitWindows), - ConsumedUnitsCap: unitCaps, + ConsumedUnitsCap: dynamicFeesConfig.BlockUnitsCap, Credentials: txs.EmptyCredentials(signers), } diff --git a/vms/platformvm/txs/executor/helpers_test.go b/vms/platformvm/txs/executor/helpers_test.go index 7799d7dc4c9e..bfc04a09d78c 100644 --- a/vms/platformvm/txs/executor/helpers_test.go +++ b/vms/platformvm/txs/executor/helpers_test.go @@ -232,16 +232,13 @@ func addSubnet( unitFees, err := env.state.GetUnitFees() require.NoError(err) - unitCaps, err := env.state.GetBlockUnitCaps() - require.NoError(err) - unitWindows, err := env.state.GetConsumedUnitsWindows() require.NoError(err) executor := StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: fees.NewManager(unitFees, unitWindows), - UnitCaps: unitCaps, + UnitCaps: env.backend.Config.GetDynamicFeesConfig().BlockUnitsCap, State: stateDiff, Tx: testSubnet1, } diff --git a/vms/platformvm/txs/fees/calculator.go b/vms/platformvm/txs/fees/calculator.go index 44a91482c8df..e7bdbbe00f4d 100644 --- a/vms/platformvm/txs/fees/calculator.go +++ b/vms/platformvm/txs/fees/calculator.go @@ -6,7 +6,6 @@ package fees import ( "errors" "fmt" - "math" "time" "github.com/ava-labs/avalanchego/utils/constants" @@ -20,30 +19,12 @@ import ( var ( _ txs.Visitor = (*Calculator)(nil) - // These are the default unit fees, used upon E-fork activation - // TODO ABENEGIA: to be tuned - DefaultUnitFees = fees.Dimensions{ - 1, - 2, - 3, - 4, - } - - // These are the default caps for units consumed in a block, used upon E-fork activation - // TODO ABENEGIA: to be tuned - DefaultBlockMaxConsumedUnits = fees.Dimensions{ - math.MaxUint64, - math.MaxUint64, - math.MaxUint64, - math.MaxUint64, - } - errFailedFeeCalculation = errors.New("failed fee calculation") errFailedConsumedUnitsCumulation = errors.New("failed cumulating consumed units") ) type Calculator struct { - // setup, to be filled before visitor methods are called + // setup IsEForkActive bool // Pre E-fork inputs @@ -54,7 +35,7 @@ type Calculator struct { FeeManager *fees.Manager ConsumedUnitsCap fees.Dimensions - // inputs, to be filled before visitor methods are called + // common inputs Credentials []verify.Verifiable // outputs of visitor execution From 2315dc1076532b68f50e97bbf59a753ce764d266 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 1 Feb 2024 13:28:19 +0100 Subject: [PATCH 099/190] wip: introducing unit fees update --- vms/components/fees/manager.go | 10 +- vms/platformvm/block/builder/builder.go | 13 +- vms/platformvm/block/builder/helpers_test.go | 8 +- vms/platformvm/block/executor/helpers_test.go | 10 +- vms/platformvm/block/executor/manager.go | 26 ++-- .../block/executor/proposal_block_test.go | 5 +- .../block/executor/standard_block_test.go | 8 +- vms/platformvm/block/executor/verifier.go | 41 ++++-- .../block/executor/verifier_test.go | 14 +- vms/platformvm/config/dynamic_fees_config.go | 11 ++ vms/platformvm/service.go | 5 +- vms/platformvm/service_test.go | 5 +- vms/platformvm/state/diff.go | 29 ++-- vms/platformvm/state/mock_state.go | 90 ++++++++---- vms/platformvm/state/state.go | 26 ++-- vms/platformvm/txs/builder/builder.go | 130 +++--------------- vms/platformvm/txs/executor/helpers_test.go | 7 +- 17 files changed, 197 insertions(+), 241 deletions(-) diff --git a/vms/components/fees/manager.go b/vms/components/fees/manager.go index efb61a078865..5e56c0947d26 100644 --- a/vms/components/fees/manager.go +++ b/vms/components/fees/manager.go @@ -16,7 +16,7 @@ type Manager struct { // Avax denominated unit fees for all fee dimensions unitFees Dimensions - // cunsumed units window per each fee dimension. + // consumed units window per each fee dimension. windows Windows // cumulatedUnits helps aggregating the units consumed by a block @@ -31,6 +31,14 @@ func NewManager(unitFees Dimensions, windows Windows) *Manager { } } +func (m *Manager) GetUnitFees() Dimensions { + return m.unitFees +} + +func (m *Manager) GetFeeWindows() Windows { + return m.windows +} + // CalculateFee must be a stateless method func (m *Manager) CalculateFee(units Dimensions) (uint64, error) { fee := uint64(0) diff --git a/vms/platformvm/block/builder/builder.go b/vms/platformvm/block/builder/builder.go index 647b45a861bf..57025a2e80c9 100644 --- a/vms/platformvm/block/builder/builder.go +++ b/vms/platformvm/block/builder/builder.go @@ -353,6 +353,9 @@ func packBlockTxs( } var ( + unitFees = stateDiff.GetUnitFees() + unitWindows = stateDiff.GetConsumedUnitsWindows() + blockTxs []*txs.Tx inputs set.Set[ids.ID] ) @@ -375,16 +378,6 @@ func packBlockTxs( return nil, err } - unitFees, err := txDiff.GetUnitFees() - if err != nil { - return nil, err - } - - unitWindows, err := txDiff.GetConsumedUnitsWindows() - if err != nil { - return nil, err - } - executor := &txexecutor.StandardTxExecutor{ Backend: backend, BlkFeeManager: fees.NewManager(unitFees, unitWindows), diff --git a/vms/platformvm/block/builder/helpers_test.go b/vms/platformvm/block/builder/helpers_test.go index b99e418c5d55..dd43b00cebba 100644 --- a/vms/platformvm/block/builder/helpers_test.go +++ b/vms/platformvm/block/builder/helpers_test.go @@ -255,12 +255,8 @@ func addSubnet(t *testing.T, env *environment) { stateDiff, err := state.NewDiff(genesisID, env.blkManager) require.NoError(err) - unitFees, err := env.state.GetUnitFees() - require.NoError(err) - - unitWindows, err := env.state.GetConsumedUnitsWindows() - require.NoError(err) - + unitFees := env.state.GetUnitFees() + unitWindows := env.state.GetConsumedUnitsWindows() executor := txexecutor.StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: fees.NewManager(unitFees, unitWindows), diff --git a/vms/platformvm/block/executor/helpers_test.go b/vms/platformvm/block/executor/helpers_test.go index 0627c744d7ed..147e9ebbdfb0 100644 --- a/vms/platformvm/block/executor/helpers_test.go +++ b/vms/platformvm/block/executor/helpers_test.go @@ -275,14 +275,8 @@ func addSubnet(env *environment) { panic(err) } - unitFees, err := env.state.GetUnitFees() - if err != nil { - panic(err) - } - unitWindows, err := env.state.GetConsumedUnitsWindows() - if err != nil { - panic(err) - } + unitFees := env.state.GetUnitFees() + unitWindows := env.state.GetConsumedUnitsWindows() executor := executor.StandardTxExecutor{ Backend: env.backend, diff --git a/vms/platformvm/block/executor/manager.go b/vms/platformvm/block/executor/manager.go index a611a28a25ab..f3284e9217f0 100644 --- a/vms/platformvm/block/executor/manager.go +++ b/vms/platformvm/block/executor/manager.go @@ -143,19 +143,25 @@ func (m *manager) VerifyTx(tx *txs.Tx) error { return err } - unitFees, err := stateDiff.GetUnitFees() - if err != nil { - return err - } - unitWindows, err := stateDiff.GetConsumedUnitsWindows() - if err != nil { - return err - } + var ( + feesCfg = m.txExecutorBackend.Config.GetDynamicFeesConfig() + unitFees = stateDiff.GetUnitFees() + unitWindows = stateDiff.GetConsumedUnitsWindows() + ) + + parentFeeManager := fees.NewManager(unitFees, unitWindows) + feeManager := parentFeeManager.ComputeNext( + stateDiff.GetTimestamp().Unix(), + nextBlkTime.Unix(), + feesCfg.BlockUnitsTarget, + feesCfg.FeesChangeDenominator, + feesCfg.MinUnitFees, + ) err = tx.Unsigned.Visit(&executor.StandardTxExecutor{ Backend: m.txExecutorBackend, - BlkFeeManager: fees.NewManager(unitFees, unitWindows), - UnitCaps: m.txExecutorBackend.Config.GetDynamicFeesConfig().BlockUnitsCap, + BlkFeeManager: feeManager, + UnitCaps: feesCfg.BlockUnitsCap, State: stateDiff, Tx: tx, }) diff --git a/vms/platformvm/block/executor/proposal_block_test.go b/vms/platformvm/block/executor/proposal_block_test.go index 681672fe9c41..c092558fcf69 100644 --- a/vms/platformvm/block/executor/proposal_block_test.go +++ b/vms/platformvm/block/executor/proposal_block_test.go @@ -27,8 +27,6 @@ import ( "github.com/ava-labs/avalanchego/vms/platformvm/txs" "github.com/ava-labs/avalanchego/vms/platformvm/txs/executor" "github.com/ava-labs/avalanchego/vms/secp256k1fx" - - commonfees "github.com/ava-labs/avalanchego/vms/components/fees" ) func TestApricotProposalBlockTimeVerification(t *testing.T) { @@ -142,6 +140,7 @@ func TestBanffProposalBlockTimeVerification(t *testing.T) { env.clk.Set(defaultGenesisTime) env.config.BanffTime = time.Time{} // activate Banff env.config.DurangoTime = mockable.MaxTime // deactivate Durango + env.config.EForkTime = mockable.MaxTime // create parentBlock. It's a standard one for simplicity parentTime := defaultGenesisTime @@ -161,9 +160,7 @@ func TestBanffProposalBlockTimeVerification(t *testing.T) { onParentAccept := state.NewMockDiff(ctrl) onParentAccept.EXPECT().GetTimestamp().Return(parentTime).AnyTimes() - onParentAccept.EXPECT().GetUnitFees().Return(commonfees.EmptyUnitFees, nil).AnyTimes() onParentAccept.EXPECT().GetCurrentSupply(constants.PrimaryNetworkID).Return(uint64(1000), nil).AnyTimes() - onParentAccept.EXPECT().GetConsumedUnitsWindows().Return(commonfees.EmptyWindows, nil).AnyTimes() env.blkManager.(*manager).blkIDToState[parentID] = &blockState{ statelessBlock: banffParentBlk, diff --git a/vms/platformvm/block/executor/standard_block_test.go b/vms/platformvm/block/executor/standard_block_test.go index 06247d8b04ae..a83d4c8d5b85 100644 --- a/vms/platformvm/block/executor/standard_block_test.go +++ b/vms/platformvm/block/executor/standard_block_test.go @@ -58,8 +58,6 @@ 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().GetUnitFees().Return(commonfees.EmptyUnitFees, nil) - onParentAccept.EXPECT().GetConsumedUnitsWindows().Return(commonfees.EmptyWindows, nil) // wrong height apricotChildBlk, err := block.NewApricotStandardBlock( @@ -91,6 +89,8 @@ func TestBanffStandardBlockTimeVerification(t *testing.T) { now := env.clk.Time() env.clk.Set(now) env.config.BanffTime = time.Time{} // activate Banff + env.config.DurangoTime = time.Time{} + env.config.EForkTime = time.Time{} // setup and store parent block // it's a standard block for simplicity @@ -154,8 +154,8 @@ func TestBanffStandardBlockTimeVerification(t *testing.T) { } utxoID := utxo.InputID() onParentAccept.EXPECT().GetUTXO(utxoID).Return(utxo, nil).AnyTimes() - onParentAccept.EXPECT().GetUnitFees().Return(commonfees.EmptyUnitFees, nil).AnyTimes() - onParentAccept.EXPECT().GetConsumedUnitsWindows().Return(commonfees.EmptyWindows, nil).AnyTimes() + onParentAccept.EXPECT().GetUnitFees().Return(commonfees.EmptyUnitFees).AnyTimes() + onParentAccept.EXPECT().GetConsumedUnitsWindows().Return(commonfees.EmptyWindows).AnyTimes() // Create the tx utx := &txs.CreateSubnetTx{ diff --git a/vms/platformvm/block/executor/verifier.go b/vms/platformvm/block/executor/verifier.go index b62fafc1f118..fa249066263e 100644 --- a/vms/platformvm/block/executor/verifier.go +++ b/vms/platformvm/block/executor/verifier.go @@ -6,6 +6,7 @@ package executor import ( "errors" "fmt" + "time" "github.com/ava-labs/avalanchego/chains/atomic" "github.com/ava-labs/avalanchego/ids" @@ -72,7 +73,7 @@ func (v *verifier) BanffProposalBlock(b *block.BanffProposalBlock) error { return err } - inputs, atomicRequests, onAcceptFunc, err := v.processStandardTxs(b.Transactions, onDecisionState, b.Parent()) + inputs, atomicRequests, onAcceptFunc, err := v.processStandardTxs(b.Transactions, onDecisionState, b.Parent(), b.Timestamp()) if err != nil { return err } @@ -125,7 +126,7 @@ func (v *verifier) BanffStandardBlock(b *block.BanffStandardBlock) error { return errBanffStandardBlockWithoutChanges } - return v.standardBlock(&b.ApricotStandardBlock, onAcceptState) + return v.standardBlock(&b.ApricotStandardBlock, b.Timestamp(), onAcceptState) } func (v *verifier) ApricotAbortBlock(b *block.ApricotAbortBlock) error { @@ -171,7 +172,7 @@ func (v *verifier) ApricotStandardBlock(b *block.ApricotStandardBlock) error { return err } - return v.standardBlock(b, onAcceptState) + return v.standardBlock(b, time.Time{}, onAcceptState) } func (v *verifier) ApricotAtomicBlock(b *block.ApricotAtomicBlock) error { @@ -409,9 +410,10 @@ func (v *verifier) proposalBlock( // standardBlock populates the state of this block if [nil] is returned func (v *verifier) standardBlock( b *block.ApricotStandardBlock, + blkTimestamp time.Time, onAcceptState state.Diff, ) error { - inputs, atomicRequests, onAcceptFunc, err := v.processStandardTxs(b.Transactions, onAcceptState, b.Parent()) + inputs, atomicRequests, onAcceptFunc, err := v.processStandardTxs(b.Transactions, onAcceptState, b.Parent(), blkTimestamp) if err != nil { return err } @@ -432,29 +434,35 @@ func (v *verifier) standardBlock( return nil } -func (v *verifier) processStandardTxs(txs []*txs.Tx, state state.Diff, parentID ids.ID) ( +func (v *verifier) processStandardTxs(txs []*txs.Tx, state state.Diff, parentID ids.ID, blkTimestamp time.Time) ( set.Set[ids.ID], map[ids.ID]*atomic.Requests, func(), error, ) { var ( + currentTimestamp = state.GetTimestamp() + isEForkActive = v.txExecutorBackend.Config.IsEForkActivated(currentTimestamp) + feesCfg = v.txExecutorBackend.Config.GetDynamicFeesConfig() + unitFees = state.GetUnitFees() + unitWindows = state.GetConsumedUnitsWindows() + onAcceptFunc func() inputs set.Set[ids.ID] funcs = make([]func(), 0, len(txs)) atomicRequests = make(map[ids.ID]*atomic.Requests) ) - unitFees, err := state.GetUnitFees() - if err != nil { - return nil, nil, nil, err - } - unitWindows, err := state.GetConsumedUnitsWindows() - if err != nil { - return nil, nil, nil, err - } - feeManager := fees.NewManager(unitFees, unitWindows) + if isEForkActive { + feeManager = feeManager.ComputeNext( + currentTimestamp.Unix(), + blkTimestamp.Unix(), + feesCfg.BlockUnitsTarget, + feesCfg.FeesChangeDenominator, + feesCfg.MinUnitFees, + ) + } for _, tx := range txs { txExecutor := executor.StandardTxExecutor{ @@ -498,6 +506,11 @@ func (v *verifier) processStandardTxs(txs []*txs.Tx, state state.Diff, parentID return nil, nil, nil, err } + if isEForkActive { + state.SetUnitFees(feeManager.GetUnitFees()) + state.SetConsumedUnitsWindows(feeManager.GetFeeWindows()) + } + if numFuncs := len(funcs); numFuncs == 1 { onAcceptFunc = funcs[0] } else if numFuncs > 1 { diff --git a/vms/platformvm/block/executor/verifier_test.go b/vms/platformvm/block/executor/verifier_test.go index 87caf1adeee4..b22b2765753a 100644 --- a/vms/platformvm/block/executor/verifier_test.go +++ b/vms/platformvm/block/executor/verifier_test.go @@ -27,8 +27,6 @@ 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/mempool" - - commonfees "github.com/ava-labs/avalanchego/vms/components/fees" ) func TestVerifierVisitProposalBlock(t *testing.T) { @@ -234,6 +232,9 @@ func TestVerifierVisitStandardBlock(t *testing.T) { Config: &config.Config{ ApricotPhase5Time: time.Now().Add(time.Hour), BanffTime: mockable.MaxTime, // banff is not activated + CortinaTime: mockable.MaxTime, + DurangoTime: mockable.MaxTime, + EForkTime: mockable.MaxTime, }, Clk: &mockable.Clock{}, }, @@ -287,9 +288,6 @@ func TestVerifierVisitStandardBlock(t *testing.T) { // Set expectations for dependencies. timestamp := time.Now() parentState.EXPECT().GetTimestamp().Return(timestamp).Times(1) - parentState.EXPECT().GetUnitFees().Return(commonfees.EmptyUnitFees, nil) - parentState.EXPECT().GetConsumedUnitsWindows().Return(commonfees.EmptyWindows, nil) - parentStatelessBlk.EXPECT().Height().Return(uint64(1)).Times(1) mempool.EXPECT().Remove(apricotBlk.Txs()).Times(1) @@ -719,6 +717,9 @@ func TestVerifierVisitStandardBlockWithDuplicateInputs(t *testing.T) { Config: &config.Config{ ApricotPhase5Time: time.Now().Add(time.Hour), BanffTime: mockable.MaxTime, // banff is not activated + CortinaTime: mockable.MaxTime, + DurangoTime: mockable.MaxTime, + EForkTime: mockable.MaxTime, }, Clk: &mockable.Clock{}, }, @@ -769,9 +770,6 @@ func TestVerifierVisitStandardBlockWithDuplicateInputs(t *testing.T) { timestamp := time.Now() parentStatelessBlk.EXPECT().Height().Return(uint64(1)).Times(1) parentState.EXPECT().GetTimestamp().Return(timestamp).Times(1) - parentState.EXPECT().GetUnitFees().Return(commonfees.EmptyUnitFees, nil) - parentState.EXPECT().GetConsumedUnitsWindows().Return(commonfees.EmptyWindows, nil) - parentStatelessBlk.EXPECT().Parent().Return(grandParentID).Times(1) err = verifier.ApricotStandardBlock(blk) diff --git a/vms/platformvm/config/dynamic_fees_config.go b/vms/platformvm/config/dynamic_fees_config.go index 551e02de7f6f..f2ef0cbeedc0 100644 --- a/vms/platformvm/config/dynamic_fees_config.go +++ b/vms/platformvm/config/dynamic_fees_config.go @@ -45,6 +45,13 @@ var EForkDynamicFeesConfig = DynamicFeesConfig{ 1, 1, }, + + FeesChangeDenominator: commonfees.Dimensions{ + 1, + 1, + 1, + 1, + }, } type DynamicFeesConfig struct { @@ -81,6 +88,10 @@ func (c *DynamicFeesConfig) validate() error { ) } + if c.FeesChangeDenominator[i] == 0 { + return fmt.Errorf("dimension %d, fees change denominator set to zero", i) + } + if c.BlockUnitsTarget[i] > c.BlockUnitsCap[i] { return fmt.Errorf("dimension %d, block target units %d larger than block units cap %d", i, diff --git a/vms/platformvm/service.go b/vms/platformvm/service.go index 6d77a4478b01..a813bd5f03c2 100644 --- a/vms/platformvm/service.go +++ b/vms/platformvm/service.go @@ -2827,9 +2827,8 @@ func (s *Service) GetUnitFees(_ *http.Request, _ *struct{}, reply *GetUnitFeesRe s.vm.ctx.Lock.Lock() defer s.vm.ctx.Lock.Unlock() - var err error - reply.UnitFees, err = s.vm.state.GetUnitFees() - return err + reply.UnitFees = s.vm.state.GetUnitFees() + return nil } // GetBlockUnitsCapReply is the response from GetBlockUnitsCap diff --git a/vms/platformvm/service_test.go b/vms/platformvm/service_test.go index b646160c171c..4a67b57c2944 100644 --- a/vms/platformvm/service_test.go +++ b/vms/platformvm/service_test.go @@ -1024,8 +1024,7 @@ func TestGetUnitFees(t *testing.T) { service.vm.ctx.Lock.Lock() - unitFees, err := service.vm.state.GetUnitFees() - require.NoError(err) + unitFees := service.vm.state.GetUnitFees() require.Equal(unitFees, reply.UnitFees) @@ -1035,7 +1034,7 @@ func TestGetUnitFees(t *testing.T) { 789, 1011, } - require.NoError(service.vm.state.SetUnitFees(updatedUnitFees)) + service.vm.state.SetUnitFees(updatedUnitFees) service.vm.ctx.Lock.Unlock() diff --git a/vms/platformvm/state/diff.go b/vms/platformvm/state/diff.go index 69b2309b835a..dbb5192dd1dc 100644 --- a/vms/platformvm/state/diff.go +++ b/vms/platformvm/state/diff.go @@ -37,6 +37,9 @@ type diff struct { timestamp time.Time + unitFees commonfees.Dimensions + consumedUnitsWindows commonfees.Windows + // Subnet ID --> supply of native asset of the subnet currentSupply map[ids.ID]uint64 @@ -91,22 +94,20 @@ func NewDiffOn(parentState Chain) (Diff, error) { }) } -// TODO ABENEGIA: fix method with dynamic fees -func (d *diff) GetUnitFees() (commonfees.Dimensions, error) { - parentState, ok := d.stateVersions.GetState(d.parentID) - if !ok { - return commonfees.Dimensions{}, fmt.Errorf("%w: %s", ErrMissingParentState, d.parentID) - } - return parentState.GetUnitFees() +func (d *diff) GetUnitFees() commonfees.Dimensions { + return d.unitFees } -// TODO ABENEGIA: fix method with dynamic fees -func (d *diff) GetConsumedUnitsWindows() (commonfees.Windows, error) { - parentState, ok := d.stateVersions.GetState(d.parentID) - if !ok { - return commonfees.Windows{}, fmt.Errorf("%w: %s", ErrMissingParentState, d.parentID) - } - return parentState.GetConsumedUnitsWindows() +func (d *diff) SetUnitFees(uf commonfees.Dimensions) { + d.unitFees = uf +} + +func (d *diff) GetConsumedUnitsWindows() commonfees.Windows { + return d.consumedUnitsWindows +} + +func (d *diff) SetConsumedUnitsWindows(windows commonfees.Windows) { + d.consumedUnitsWindows = windows } func (d *diff) GetTimestamp() time.Time { diff --git a/vms/platformvm/state/mock_state.go b/vms/platformvm/state/mock_state.go index 329754b98d5d..baeca8ca433d 100644 --- a/vms/platformvm/state/mock_state.go +++ b/vms/platformvm/state/mock_state.go @@ -184,12 +184,11 @@ func (mr *MockChainMockRecorder) DeleteUTXO(arg0 any) *gomock.Call { } // GetConsumedUnitsWindows mocks base method. -func (m *MockChain) GetConsumedUnitsWindows() (fees.Windows, error) { +func (m *MockChain) GetConsumedUnitsWindows() fees.Windows { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetConsumedUnitsWindows") ret0, _ := ret[0].(fees.Windows) - ret1, _ := ret[1].(error) - return ret0, ret1 + return ret0 } // GetConsumedUnitsWindows indicates an expected call of GetConsumedUnitsWindows. @@ -394,12 +393,11 @@ func (mr *MockChainMockRecorder) GetUTXO(arg0 any) *gomock.Call { } // GetUnitFees mocks base method. -func (m *MockChain) GetUnitFees() (fees.Dimensions, error) { +func (m *MockChain) GetUnitFees() fees.Dimensions { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetUnitFees") ret0, _ := ret[0].(fees.Dimensions) - ret1, _ := ret[1].(error) - return ret0, ret1 + return ret0 } // GetUnitFees indicates an expected call of GetUnitFees. @@ -456,6 +454,18 @@ func (mr *MockChainMockRecorder) PutPendingValidator(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PutPendingValidator", reflect.TypeOf((*MockChain)(nil).PutPendingValidator), arg0) } +// SetConsumedUnitsWindows mocks base method. +func (m *MockChain) SetConsumedUnitsWindows(arg0 fees.Windows) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetConsumedUnitsWindows", arg0) +} + +// SetConsumedUnitsWindows indicates an expected call of SetConsumedUnitsWindows. +func (mr *MockChainMockRecorder) SetConsumedUnitsWindows(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetConsumedUnitsWindows", reflect.TypeOf((*MockChain)(nil).SetConsumedUnitsWindows), arg0) +} + // SetCurrentSupply mocks base method. func (m *MockChain) SetCurrentSupply(arg0 ids.ID, arg1 uint64) { m.ctrl.T.Helper() @@ -506,6 +516,18 @@ func (mr *MockChainMockRecorder) SetTimestamp(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetTimestamp", reflect.TypeOf((*MockChain)(nil).SetTimestamp), arg0) } +// SetUnitFees mocks base method. +func (m *MockChain) SetUnitFees(arg0 fees.Dimensions) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetUnitFees", arg0) +} + +// SetUnitFees indicates an expected call of SetUnitFees. +func (mr *MockChainMockRecorder) SetUnitFees(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetUnitFees", reflect.TypeOf((*MockChain)(nil).SetUnitFees), arg0) +} + // MockDiff is a mock of Diff interface. type MockDiff struct { ctrl *gomock.Controller @@ -676,12 +698,11 @@ func (mr *MockDiffMockRecorder) DeleteUTXO(arg0 any) *gomock.Call { } // GetConsumedUnitsWindows mocks base method. -func (m *MockDiff) GetConsumedUnitsWindows() (fees.Windows, error) { +func (m *MockDiff) GetConsumedUnitsWindows() fees.Windows { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetConsumedUnitsWindows") ret0, _ := ret[0].(fees.Windows) - ret1, _ := ret[1].(error) - return ret0, ret1 + return ret0 } // GetConsumedUnitsWindows indicates an expected call of GetConsumedUnitsWindows. @@ -886,12 +907,11 @@ func (mr *MockDiffMockRecorder) GetUTXO(arg0 any) *gomock.Call { } // GetUnitFees mocks base method. -func (m *MockDiff) GetUnitFees() (fees.Dimensions, error) { +func (m *MockDiff) GetUnitFees() fees.Dimensions { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetUnitFees") ret0, _ := ret[0].(fees.Dimensions) - ret1, _ := ret[1].(error) - return ret0, ret1 + return ret0 } // GetUnitFees indicates an expected call of GetUnitFees. @@ -948,6 +968,18 @@ func (mr *MockDiffMockRecorder) PutPendingValidator(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PutPendingValidator", reflect.TypeOf((*MockDiff)(nil).PutPendingValidator), arg0) } +// SetConsumedUnitsWindows mocks base method. +func (m *MockDiff) SetConsumedUnitsWindows(arg0 fees.Windows) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetConsumedUnitsWindows", arg0) +} + +// SetConsumedUnitsWindows indicates an expected call of SetConsumedUnitsWindows. +func (mr *MockDiffMockRecorder) SetConsumedUnitsWindows(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetConsumedUnitsWindows", reflect.TypeOf((*MockDiff)(nil).SetConsumedUnitsWindows), arg0) +} + // SetCurrentSupply mocks base method. func (m *MockDiff) SetCurrentSupply(arg0 ids.ID, arg1 uint64) { m.ctrl.T.Helper() @@ -998,6 +1030,18 @@ func (mr *MockDiffMockRecorder) SetTimestamp(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetTimestamp", reflect.TypeOf((*MockDiff)(nil).SetTimestamp), arg0) } +// SetUnitFees mocks base method. +func (m *MockDiff) SetUnitFees(arg0 fees.Dimensions) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetUnitFees", arg0) +} + +// SetUnitFees indicates an expected call of SetUnitFees. +func (mr *MockDiffMockRecorder) SetUnitFees(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetUnitFees", reflect.TypeOf((*MockDiff)(nil).SetUnitFees), arg0) +} + // MockState is a mock of State interface. type MockState struct { ctrl *gomock.Controller @@ -1293,12 +1337,11 @@ func (mr *MockStateMockRecorder) GetChains(arg0 any) *gomock.Call { } // GetConsumedUnitsWindows mocks base method. -func (m *MockState) GetConsumedUnitsWindows() (fees.Windows, error) { +func (m *MockState) GetConsumedUnitsWindows() fees.Windows { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetConsumedUnitsWindows") ret0, _ := ret[0].(fees.Windows) - ret1, _ := ret[1].(error) - return ret0, ret1 + return ret0 } // GetConsumedUnitsWindows indicates an expected call of GetConsumedUnitsWindows. @@ -1577,12 +1620,11 @@ func (mr *MockStateMockRecorder) GetUTXO(arg0 any) *gomock.Call { } // GetUnitFees mocks base method. -func (m *MockState) GetUnitFees() (fees.Dimensions, error) { +func (m *MockState) GetUnitFees() fees.Dimensions { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetUnitFees") ret0, _ := ret[0].(fees.Dimensions) - ret1, _ := ret[1].(error) - return ret0, ret1 + return ret0 } // GetUnitFees indicates an expected call of GetUnitFees. @@ -1670,11 +1712,9 @@ func (mr *MockStateMockRecorder) PutPendingValidator(arg0 any) *gomock.Call { } // SetConsumedUnitsWindows mocks base method. -func (m *MockState) SetConsumedUnitsWindows(arg0 fees.Windows) error { +func (m *MockState) SetConsumedUnitsWindows(arg0 fees.Windows) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SetConsumedUnitsWindows", arg0) - ret0, _ := ret[0].(error) - return ret0 + m.ctrl.Call(m, "SetConsumedUnitsWindows", arg0) } // SetConsumedUnitsWindows indicates an expected call of SetConsumedUnitsWindows. @@ -1758,11 +1798,9 @@ func (mr *MockStateMockRecorder) SetTimestamp(arg0 any) *gomock.Call { } // SetUnitFees mocks base method. -func (m *MockState) SetUnitFees(arg0 fees.Dimensions) error { +func (m *MockState) SetUnitFees(arg0 fees.Dimensions) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SetUnitFees", arg0) - ret0, _ := ret[0].(error) - return ret0 + m.ctrl.Call(m, "SetUnitFees", arg0) } // SetUnitFees indicates an expected call of SetUnitFees. diff --git a/vms/platformvm/state/state.go b/vms/platformvm/state/state.go index cceb50c33145..ee95bdeebb10 100644 --- a/vms/platformvm/state/state.go +++ b/vms/platformvm/state/state.go @@ -101,8 +101,11 @@ type Chain interface { avax.UTXOGetter avax.UTXODeleter - GetUnitFees() (commonfees.Dimensions, error) - GetConsumedUnitsWindows() (commonfees.Windows, error) + GetUnitFees() commonfees.Dimensions + SetUnitFees(uf commonfees.Dimensions) + + GetConsumedUnitsWindows() commonfees.Windows + SetConsumedUnitsWindows(windows commonfees.Windows) GetTimestamp() time.Time SetTimestamp(tm time.Time) @@ -145,10 +148,6 @@ type State interface { GetSubnets() ([]*txs.Tx, error) GetChains(subnetID ids.ID) ([]*txs.Tx, error) - // At this iteration these getters are helpful for UTs only - SetUnitFees(uf commonfees.Dimensions) error - SetConsumedUnitsWindows(windows commonfees.Windows) error - // ApplyValidatorWeightDiffs iterates from [startHeight] towards the genesis // block until it has applied all of the diffs up to and including // [endHeight]. Applying the diffs modifies [validators]. @@ -385,7 +384,6 @@ type state struct { singletonDB database.Database // TODO ABENEGIA: handle persistence of these attributes - // Maybe blockUnitCaps is an exception, since it should be a fork related quantity unitFees commonfees.Dimensions consumedUnitsWindows commonfees.Windows } @@ -1093,22 +1091,20 @@ func (s *state) GetStartTime(nodeID ids.NodeID, subnetID ids.ID) (time.Time, err return staker.StartTime, nil } -func (s *state) GetUnitFees() (commonfees.Dimensions, error) { - return s.unitFees, nil +func (s *state) GetUnitFees() commonfees.Dimensions { + return s.unitFees } -func (s *state) SetUnitFees(uf commonfees.Dimensions) error { +func (s *state) SetUnitFees(uf commonfees.Dimensions) { s.unitFees = uf - return nil } -func (s *state) GetConsumedUnitsWindows() (commonfees.Windows, error) { - return s.consumedUnitsWindows, nil +func (s *state) GetConsumedUnitsWindows() commonfees.Windows { + return s.consumedUnitsWindows } -func (s *state) SetConsumedUnitsWindows(windows commonfees.Windows) error { +func (s *state) SetConsumedUnitsWindows(windows commonfees.Windows) { s.consumedUnitsWindows = windows - return nil } func (s *state) GetTimestamp() time.Time { diff --git a/vms/platformvm/txs/builder/builder.go b/vms/platformvm/txs/builder/builder.go index dd709a44915e..6b7c8fcd273f 100644 --- a/vms/platformvm/txs/builder/builder.go +++ b/vms/platformvm/txs/builder/builder.go @@ -312,19 +312,10 @@ func (b *builder) NewImportTx( if isEForkActive { var ( dynamicFeesConfig = b.cfg.GetDynamicFeesConfig() - unitFees commonfees.Dimensions - unitWindows commonfees.Windows + unitFees = b.state.GetUnitFees() + unitWindows = b.state.GetConsumedUnitsWindows() ) - unitFees, err = b.state.GetUnitFees() - if err != nil { - return nil, err - } - unitWindows, err = b.state.GetConsumedUnitsWindows() - if err != nil { - return nil, err - } - // while outs are not ordered we add them to get current fees. We'll fix ordering later on utx.BaseTx.Outs = outs feeCalc := &fees.Calculator{ @@ -481,18 +472,9 @@ func (b *builder) NewExportTx( if isEForkActive { var ( dynamicFeesConfig = b.cfg.GetDynamicFeesConfig() - unitFees commonfees.Dimensions - unitWindows commonfees.Windows + unitFees = b.state.GetUnitFees() + unitWindows = b.state.GetConsumedUnitsWindows() ) - unitFees, err = b.state.GetUnitFees() - if err != nil { - return nil, err - } - - unitWindows, err = b.state.GetConsumedUnitsWindows() - if err != nil { - return nil, err - } feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, @@ -577,18 +559,9 @@ func (b *builder) NewCreateChainTx( if isEForkActive { var ( dynamicFeesConfig = b.cfg.GetDynamicFeesConfig() - unitFees commonfees.Dimensions - unitWindows commonfees.Windows + unitFees = b.state.GetUnitFees() + unitWindows = b.state.GetConsumedUnitsWindows() ) - unitFees, err = b.state.GetUnitFees() - if err != nil { - return nil, err - } - - unitWindows, err = b.state.GetConsumedUnitsWindows() - if err != nil { - return nil, err - } feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, @@ -662,18 +635,9 @@ func (b *builder) NewCreateSubnetTx( if isEForkActive { var ( dynamicFeesConfig = b.cfg.GetDynamicFeesConfig() - unitFees commonfees.Dimensions - unitWindows commonfees.Windows + unitFees = b.state.GetUnitFees() + unitWindows = b.state.GetConsumedUnitsWindows() ) - unitFees, err = b.state.GetUnitFees() - if err != nil { - return nil, err - } - - unitWindows, err = b.state.GetConsumedUnitsWindows() - if err != nil { - return nil, err - } feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, @@ -756,18 +720,9 @@ func (b *builder) NewAddValidatorTx( if isEForkActive { var ( dynamicFeesConfig = b.cfg.GetDynamicFeesConfig() - unitFees commonfees.Dimensions - unitWindows commonfees.Windows + unitFees = b.state.GetUnitFees() + unitWindows = b.state.GetConsumedUnitsWindows() ) - unitFees, err = b.state.GetUnitFees() - if err != nil { - return nil, err - } - - unitWindows, err = b.state.GetConsumedUnitsWindows() - if err != nil { - return nil, err - } feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, @@ -848,18 +803,9 @@ func (b *builder) NewAddDelegatorTx( if isEForkActive { var ( dynamicFeesConfig = b.cfg.GetDynamicFeesConfig() - unitFees commonfees.Dimensions - unitWindows commonfees.Windows + unitFees = b.state.GetUnitFees() + unitWindows = b.state.GetConsumedUnitsWindows() ) - unitFees, err = b.state.GetUnitFees() - if err != nil { - return nil, err - } - - unitWindows, err = b.state.GetConsumedUnitsWindows() - if err != nil { - return nil, err - } feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, @@ -941,18 +887,9 @@ func (b *builder) NewAddSubnetValidatorTx( if isEForkActive { var ( dynamicFeesConfig = b.cfg.GetDynamicFeesConfig() - unitFees commonfees.Dimensions - unitWindows commonfees.Windows + unitFees = b.state.GetUnitFees() + unitWindows = b.state.GetConsumedUnitsWindows() ) - unitFees, err = b.state.GetUnitFees() - if err != nil { - return nil, err - } - - unitWindows, err = b.state.GetConsumedUnitsWindows() - if err != nil { - return nil, err - } feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, @@ -1024,18 +961,9 @@ func (b *builder) NewRemoveSubnetValidatorTx( if isEForkActive { var ( dynamicFeesConfig = b.cfg.GetDynamicFeesConfig() - unitFees commonfees.Dimensions - unitWindows commonfees.Windows + unitFees = b.state.GetUnitFees() + unitWindows = b.state.GetConsumedUnitsWindows() ) - unitFees, err = b.state.GetUnitFees() - if err != nil { - return nil, err - } - - unitWindows, err = b.state.GetConsumedUnitsWindows() - if err != nil { - return nil, err - } feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, @@ -1121,19 +1049,10 @@ func (b *builder) NewTransferSubnetOwnershipTx( if isEForkActive { var ( dynamicFeesConfig = b.cfg.GetDynamicFeesConfig() - unitFees commonfees.Dimensions - unitWindows commonfees.Windows + unitFees = b.state.GetUnitFees() + unitWindows = b.state.GetConsumedUnitsWindows() ) - unitFees, err = b.state.GetUnitFees() - if err != nil { - return nil, err - } - unitWindows, err = b.state.GetConsumedUnitsWindows() - if err != nil { - return nil, err - } - feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, FeeManager: commonfees.NewManager(unitFees, unitWindows), @@ -1198,18 +1117,9 @@ func (b *builder) NewBaseTx( if isEForkActive { var ( dynamicFeesConfig = b.cfg.GetDynamicFeesConfig() - unitFees commonfees.Dimensions - unitWindows commonfees.Windows + unitFees = b.state.GetUnitFees() + unitWindows = b.state.GetConsumedUnitsWindows() ) - unitFees, err = b.state.GetUnitFees() - if err != nil { - return nil, err - } - - unitWindows, err = b.state.GetConsumedUnitsWindows() - if err != nil { - return nil, err - } feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, diff --git a/vms/platformvm/txs/executor/helpers_test.go b/vms/platformvm/txs/executor/helpers_test.go index bfc04a09d78c..4b7a49e2912b 100644 --- a/vms/platformvm/txs/executor/helpers_test.go +++ b/vms/platformvm/txs/executor/helpers_test.go @@ -229,11 +229,8 @@ func addSubnet( stateDiff, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - unitFees, err := env.state.GetUnitFees() - require.NoError(err) - - unitWindows, err := env.state.GetConsumedUnitsWindows() - require.NoError(err) + unitFees := env.state.GetUnitFees() + unitWindows := env.state.GetConsumedUnitsWindows() executor := StandardTxExecutor{ Backend: &env.backend, From a279f4e34546500d4240cb137fe3153007a1ac50 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 1 Feb 2024 17:04:22 +0100 Subject: [PATCH 100/190] wip: persist unit fees and fee windows --- vms/components/fees/dimensions.go | 30 ++++++- vms/components/fees/dimensions_test.go | 21 +++++ vms/components/fees/manager.go | 2 - vms/components/fees/window.go | 40 +++++++-- vms/components/fees/window_test.go | 16 ++++ vms/platformvm/block/builder/builder.go | 2 +- vms/platformvm/block/builder/helpers_test.go | 2 +- vms/platformvm/block/executor/helpers_test.go | 2 +- vms/platformvm/block/executor/manager.go | 2 +- .../block/executor/standard_block_test.go | 2 +- vms/platformvm/block/executor/verifier.go | 2 +- vms/platformvm/state/diff.go | 4 +- vms/platformvm/state/mock_state.go | 84 +++++++++---------- vms/platformvm/state/state.go | 61 +++++++++++--- vms/platformvm/txs/builder/builder.go | 20 ++--- vms/platformvm/txs/executor/helpers_test.go | 2 +- 16 files changed, 210 insertions(+), 82 deletions(-) create mode 100644 vms/components/fees/dimensions_test.go diff --git a/vms/components/fees/dimensions.go b/vms/components/fees/dimensions.go index b8050be15dc1..eab049cb437f 100644 --- a/vms/components/fees/dimensions.go +++ b/vms/components/fees/dimensions.go @@ -3,7 +3,12 @@ package fees -import "github.com/ava-labs/avalanchego/utils/math" +import ( + "encoding/binary" + "fmt" + + "github.com/ava-labs/avalanchego/utils/math" +) const ( Bandwidth Dimension = 0 @@ -12,6 +17,8 @@ const ( Compute Dimension = 3 // signatures checks, tx-specific FeeDimensions = 4 + + uint64Len = 8 ) var ( @@ -36,3 +43,24 @@ func Add(lhs, rhs Dimensions) (Dimensions, error) { } return res, nil } + +func (d *Dimensions) Bytes() []byte { + res := make([]byte, FeeDimensions*uint64Len) + for i := Dimension(0); i < FeeDimensions; i++ { + binary.BigEndian.PutUint64(res[i*uint64Len:], d[i]) + } + return res +} + +func (d *Dimensions) FromBytes(b []byte) error { + if len(b) != FeeDimensions*uint64Len { + return fmt.Errorf("unexpected bytes length: expected %d, actual %d", + FeeDimensions*uint64Len, + len(b), + ) + } + for i := Dimension(0); i < FeeDimensions; i++ { + d[i] = binary.BigEndian.Uint64(b[i*uint64Len : (i+1)*uint64Len]) + } + return nil +} diff --git a/vms/components/fees/dimensions_test.go b/vms/components/fees/dimensions_test.go new file mode 100644 index 000000000000..2f2dcd3d12a9 --- /dev/null +++ b/vms/components/fees/dimensions_test.go @@ -0,0 +1,21 @@ +// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package fees + +import ( + "math" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestMarshalUnmarshalDimensions(t *testing.T) { + require := require.New(t) + + input := Dimensions{0, 1, 2024, math.MaxUint64} + bytes := input.Bytes() + var output Dimensions + require.NoError(output.FromBytes(bytes)) + require.Equal(input, output) +} diff --git a/vms/components/fees/manager.go b/vms/components/fees/manager.go index 5e56c0947d26..4d2af3e518f4 100644 --- a/vms/components/fees/manager.go +++ b/vms/components/fees/manager.go @@ -10,8 +10,6 @@ import ( safemath "github.com/ava-labs/avalanchego/utils/math" ) -type Windows [FeeDimensions]Window - type Manager struct { // Avax denominated unit fees for all fee dimensions unitFees Dimensions diff --git a/vms/components/fees/window.go b/vms/components/fees/window.go index 14a84c213834..64364bb51f22 100644 --- a/vms/components/fees/window.go +++ b/vms/components/fees/window.go @@ -4,6 +4,8 @@ package fees import ( + "encoding/binary" + "fmt" "math" safemath "github.com/ava-labs/avalanchego/utils/math" @@ -11,7 +13,37 @@ import ( const WindowSize = 10 -type Window [WindowSize]uint64 +type ( + Window [WindowSize]uint64 + Windows [FeeDimensions]Window +) + +func (w *Windows) Bytes() []byte { + res := make([]byte, FeeDimensions*WindowSize*uint64Len) + for i := Dimension(0); i < FeeDimensions; i++ { + for j, u := range w[i] { + start := (WindowSize*int(i) + j) * uint64Len + binary.BigEndian.PutUint64(res[start:], u) + } + } + return res +} + +func (w *Windows) FromBytes(b []byte) error { + if len(b) != FeeDimensions*WindowSize*uint64Len { + return fmt.Errorf("unexpected bytes length: expected %d, actual %d", + FeeDimensions*WindowSize*uint64Len, + len(b), + ) + } + for i := Dimension(0); i < FeeDimensions; i++ { + for j := 0; j < WindowSize; j++ { + start := (WindowSize*int(i) + j) * uint64Len + w[i][j] = binary.BigEndian.Uint64(b[start:]) + } + } + return nil +} // Roll rolls the uint64s consumed units within [consumptionWindow] over by [roll] places. // For example, if there are 4 uint64 encoded in a 32 byte slice, rollWindow would @@ -70,9 +102,3 @@ func Update(w *Window, idx int, unitsConsumed uint64) { } w[idx] = totalUnitsConsumed } - -func Last(w *Window) uint64 { - return w[len(w)-1] -} - -// TODO ABENEGIA: add Marshal/Unmarshal to bytes, or let the codec do that? diff --git a/vms/components/fees/window_test.go b/vms/components/fees/window_test.go index 9297b81c6267..e673df51c60c 100644 --- a/vms/components/fees/window_test.go +++ b/vms/components/fees/window_test.go @@ -10,6 +10,22 @@ import ( "github.com/stretchr/testify/require" ) +func TestMarshalUnmarshalWindows(t *testing.T) { + require := require.New(t) + + input := Windows{ + Window{}, + Window{1, 2, 3, 4, 5, 4, 3, 2, 1, 0}, + Window{math.MaxUint64, math.MaxUint64, math.MaxUint64, math.MaxUint64, 0, 0, 0, 0, 0, math.MaxUint64}, + Window{math.MaxUint64, 0, math.MaxUint64, 0, math.MaxUint64, 0, math.MaxUint64, 0, math.MaxUint64, 0}, + } + + bytes := input.Bytes() + var output Windows + require.NoError(output.FromBytes(bytes)) + require.Equal(input, output) +} + func TestWindowRoll(t *testing.T) { require := require.New(t) diff --git a/vms/platformvm/block/builder/builder.go b/vms/platformvm/block/builder/builder.go index 57025a2e80c9..868e81cb3edc 100644 --- a/vms/platformvm/block/builder/builder.go +++ b/vms/platformvm/block/builder/builder.go @@ -354,7 +354,7 @@ func packBlockTxs( var ( unitFees = stateDiff.GetUnitFees() - unitWindows = stateDiff.GetConsumedUnitsWindows() + unitWindows = stateDiff.GetFeeWindows() blockTxs []*txs.Tx inputs set.Set[ids.ID] diff --git a/vms/platformvm/block/builder/helpers_test.go b/vms/platformvm/block/builder/helpers_test.go index dd43b00cebba..528f0ee3afe4 100644 --- a/vms/platformvm/block/builder/helpers_test.go +++ b/vms/platformvm/block/builder/helpers_test.go @@ -256,7 +256,7 @@ func addSubnet(t *testing.T, env *environment) { require.NoError(err) unitFees := env.state.GetUnitFees() - unitWindows := env.state.GetConsumedUnitsWindows() + unitWindows := env.state.GetFeeWindows() executor := txexecutor.StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: fees.NewManager(unitFees, unitWindows), diff --git a/vms/platformvm/block/executor/helpers_test.go b/vms/platformvm/block/executor/helpers_test.go index 147e9ebbdfb0..b14f8a13fc8a 100644 --- a/vms/platformvm/block/executor/helpers_test.go +++ b/vms/platformvm/block/executor/helpers_test.go @@ -276,7 +276,7 @@ func addSubnet(env *environment) { } unitFees := env.state.GetUnitFees() - unitWindows := env.state.GetConsumedUnitsWindows() + unitWindows := env.state.GetFeeWindows() executor := executor.StandardTxExecutor{ Backend: env.backend, diff --git a/vms/platformvm/block/executor/manager.go b/vms/platformvm/block/executor/manager.go index f3284e9217f0..53af7b303e49 100644 --- a/vms/platformvm/block/executor/manager.go +++ b/vms/platformvm/block/executor/manager.go @@ -146,7 +146,7 @@ func (m *manager) VerifyTx(tx *txs.Tx) error { var ( feesCfg = m.txExecutorBackend.Config.GetDynamicFeesConfig() unitFees = stateDiff.GetUnitFees() - unitWindows = stateDiff.GetConsumedUnitsWindows() + unitWindows = stateDiff.GetFeeWindows() ) parentFeeManager := fees.NewManager(unitFees, unitWindows) diff --git a/vms/platformvm/block/executor/standard_block_test.go b/vms/platformvm/block/executor/standard_block_test.go index a83d4c8d5b85..07a30a5e797a 100644 --- a/vms/platformvm/block/executor/standard_block_test.go +++ b/vms/platformvm/block/executor/standard_block_test.go @@ -155,7 +155,7 @@ func TestBanffStandardBlockTimeVerification(t *testing.T) { utxoID := utxo.InputID() onParentAccept.EXPECT().GetUTXO(utxoID).Return(utxo, nil).AnyTimes() onParentAccept.EXPECT().GetUnitFees().Return(commonfees.EmptyUnitFees).AnyTimes() - onParentAccept.EXPECT().GetConsumedUnitsWindows().Return(commonfees.EmptyWindows).AnyTimes() + onParentAccept.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows).AnyTimes() // Create the tx utx := &txs.CreateSubnetTx{ diff --git a/vms/platformvm/block/executor/verifier.go b/vms/platformvm/block/executor/verifier.go index fa249066263e..9a26352f69a5 100644 --- a/vms/platformvm/block/executor/verifier.go +++ b/vms/platformvm/block/executor/verifier.go @@ -445,7 +445,7 @@ func (v *verifier) processStandardTxs(txs []*txs.Tx, state state.Diff, parentID isEForkActive = v.txExecutorBackend.Config.IsEForkActivated(currentTimestamp) feesCfg = v.txExecutorBackend.Config.GetDynamicFeesConfig() unitFees = state.GetUnitFees() - unitWindows = state.GetConsumedUnitsWindows() + unitWindows = state.GetFeeWindows() onAcceptFunc func() inputs set.Set[ids.ID] diff --git a/vms/platformvm/state/diff.go b/vms/platformvm/state/diff.go index dbb5192dd1dc..5dffe5f02ef0 100644 --- a/vms/platformvm/state/diff.go +++ b/vms/platformvm/state/diff.go @@ -102,7 +102,7 @@ func (d *diff) SetUnitFees(uf commonfees.Dimensions) { d.unitFees = uf } -func (d *diff) GetConsumedUnitsWindows() commonfees.Windows { +func (d *diff) GetFeeWindows() commonfees.Windows { return d.consumedUnitsWindows } @@ -422,6 +422,8 @@ func (d *diff) DeleteUTXO(utxoID ids.ID) { func (d *diff) Apply(baseState Chain) error { baseState.SetTimestamp(d.timestamp) + baseState.SetUnitFees(d.unitFees) + baseState.SetConsumedUnitsWindows(d.consumedUnitsWindows) 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 baeca8ca433d..21bfc3d8d0e0 100644 --- a/vms/platformvm/state/mock_state.go +++ b/vms/platformvm/state/mock_state.go @@ -183,20 +183,6 @@ func (mr *MockChainMockRecorder) DeleteUTXO(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteUTXO", reflect.TypeOf((*MockChain)(nil).DeleteUTXO), arg0) } -// GetConsumedUnitsWindows mocks base method. -func (m *MockChain) GetConsumedUnitsWindows() fees.Windows { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetConsumedUnitsWindows") - ret0, _ := ret[0].(fees.Windows) - return ret0 -} - -// GetConsumedUnitsWindows indicates an expected call of GetConsumedUnitsWindows. -func (mr *MockChainMockRecorder) GetConsumedUnitsWindows() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetConsumedUnitsWindows", reflect.TypeOf((*MockChain)(nil).GetConsumedUnitsWindows)) -} - // GetCurrentDelegatorIterator mocks base method. func (m *MockChain) GetCurrentDelegatorIterator(arg0 ids.ID, arg1 ids.NodeID) (StakerIterator, error) { m.ctrl.T.Helper() @@ -272,6 +258,20 @@ func (mr *MockChainMockRecorder) GetDelegateeReward(arg0, arg1 any) *gomock.Call return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDelegateeReward", reflect.TypeOf((*MockChain)(nil).GetDelegateeReward), arg0, arg1) } +// GetFeeWindows mocks base method. +func (m *MockChain) GetFeeWindows() fees.Windows { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetFeeWindows") + ret0, _ := ret[0].(fees.Windows) + return ret0 +} + +// GetFeeWindows indicates an expected call of GetFeeWindows. +func (mr *MockChainMockRecorder) GetFeeWindows() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFeeWindows", reflect.TypeOf((*MockChain)(nil).GetFeeWindows)) +} + // GetPendingDelegatorIterator mocks base method. func (m *MockChain) GetPendingDelegatorIterator(arg0 ids.ID, arg1 ids.NodeID) (StakerIterator, error) { m.ctrl.T.Helper() @@ -697,20 +697,6 @@ func (mr *MockDiffMockRecorder) DeleteUTXO(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteUTXO", reflect.TypeOf((*MockDiff)(nil).DeleteUTXO), arg0) } -// GetConsumedUnitsWindows mocks base method. -func (m *MockDiff) GetConsumedUnitsWindows() fees.Windows { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetConsumedUnitsWindows") - ret0, _ := ret[0].(fees.Windows) - return ret0 -} - -// GetConsumedUnitsWindows indicates an expected call of GetConsumedUnitsWindows. -func (mr *MockDiffMockRecorder) GetConsumedUnitsWindows() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetConsumedUnitsWindows", reflect.TypeOf((*MockDiff)(nil).GetConsumedUnitsWindows)) -} - // GetCurrentDelegatorIterator mocks base method. func (m *MockDiff) GetCurrentDelegatorIterator(arg0 ids.ID, arg1 ids.NodeID) (StakerIterator, error) { m.ctrl.T.Helper() @@ -786,6 +772,20 @@ func (mr *MockDiffMockRecorder) GetDelegateeReward(arg0, arg1 any) *gomock.Call return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDelegateeReward", reflect.TypeOf((*MockDiff)(nil).GetDelegateeReward), arg0, arg1) } +// GetFeeWindows mocks base method. +func (m *MockDiff) GetFeeWindows() fees.Windows { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetFeeWindows") + ret0, _ := ret[0].(fees.Windows) + return ret0 +} + +// GetFeeWindows indicates an expected call of GetFeeWindows. +func (mr *MockDiffMockRecorder) GetFeeWindows() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFeeWindows", reflect.TypeOf((*MockDiff)(nil).GetFeeWindows)) +} + // GetPendingDelegatorIterator mocks base method. func (m *MockDiff) GetPendingDelegatorIterator(arg0 ids.ID, arg1 ids.NodeID) (StakerIterator, error) { m.ctrl.T.Helper() @@ -1336,20 +1336,6 @@ func (mr *MockStateMockRecorder) GetChains(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetChains", reflect.TypeOf((*MockState)(nil).GetChains), arg0) } -// GetConsumedUnitsWindows mocks base method. -func (m *MockState) GetConsumedUnitsWindows() fees.Windows { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetConsumedUnitsWindows") - ret0, _ := ret[0].(fees.Windows) - return ret0 -} - -// GetConsumedUnitsWindows indicates an expected call of GetConsumedUnitsWindows. -func (mr *MockStateMockRecorder) GetConsumedUnitsWindows() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetConsumedUnitsWindows", reflect.TypeOf((*MockState)(nil).GetConsumedUnitsWindows)) -} - // GetCurrentDelegatorIterator mocks base method. func (m *MockState) GetCurrentDelegatorIterator(arg0 ids.ID, arg1 ids.NodeID) (StakerIterator, error) { m.ctrl.T.Helper() @@ -1425,6 +1411,20 @@ func (mr *MockStateMockRecorder) GetDelegateeReward(arg0, arg1 any) *gomock.Call return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDelegateeReward", reflect.TypeOf((*MockState)(nil).GetDelegateeReward), arg0, arg1) } +// GetFeeWindows mocks base method. +func (m *MockState) GetFeeWindows() fees.Windows { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetFeeWindows") + ret0, _ := ret[0].(fees.Windows) + return ret0 +} + +// GetFeeWindows indicates an expected call of GetFeeWindows. +func (mr *MockStateMockRecorder) GetFeeWindows() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFeeWindows", reflect.TypeOf((*MockState)(nil).GetFeeWindows)) +} + // GetLastAccepted mocks base method. func (m *MockState) GetLastAccepted() ids.ID { m.ctrl.T.Helper() diff --git a/vms/platformvm/state/state.go b/vms/platformvm/state/state.go index ee95bdeebb10..65fc62ae2e71 100644 --- a/vms/platformvm/state/state.go +++ b/vms/platformvm/state/state.go @@ -89,6 +89,8 @@ var ( CurrentSupplyKey = []byte("current supply") LastAcceptedKey = []byte("last accepted") HeightsIndexedKey = []byte("heights indexed") + UnitFeesKey = []byte("unit fees") + FeesWindowsKey = []byte("fees windows") InitializedKey = []byte("initialized") PrunedKey = []byte("pruned") ) @@ -104,7 +106,7 @@ type Chain interface { GetUnitFees() commonfees.Dimensions SetUnitFees(uf commonfees.Dimensions) - GetConsumedUnitsWindows() commonfees.Windows + GetFeeWindows() commonfees.Windows SetConsumedUnitsWindows(windows commonfees.Windows) GetTimestamp() time.Time @@ -377,15 +379,12 @@ type state struct { // The persisted fields represent the current database value timestamp, persistedTimestamp time.Time + unitFees commonfees.Dimensions + feesWindows commonfees.Windows currentSupply, persistedCurrentSupply uint64 - // [lastAccepted] is the most recently accepted block. - lastAccepted, persistedLastAccepted ids.ID - indexedHeights *heightRange - singletonDB database.Database - - // TODO ABENEGIA: handle persistence of these attributes - unitFees commonfees.Dimensions - consumedUnitsWindows commonfees.Windows + lastAccepted, persistedLastAccepted ids.ID + indexedHeights *heightRange + singletonDB database.Database } // heightRange is used to track which heights are safe to use the native DB @@ -1099,12 +1098,12 @@ func (s *state) SetUnitFees(uf commonfees.Dimensions) { s.unitFees = uf } -func (s *state) GetConsumedUnitsWindows() commonfees.Windows { - return s.consumedUnitsWindows +func (s *state) GetFeeWindows() commonfees.Windows { + return s.feesWindows } func (s *state) SetConsumedUnitsWindows(windows commonfees.Windows) { - s.consumedUnitsWindows = windows + s.feesWindows = windows } func (s *state) GetTimestamp() time.Time { @@ -1442,6 +1441,38 @@ func (s *state) loadMetadata() error { s.persistedTimestamp = timestamp s.SetTimestamp(timestamp) + switch unitFeesBytes, err := s.singletonDB.Get(UnitFeesKey); err { + case nil: + if err := s.unitFees.FromBytes(unitFeesBytes); err != nil { + return err + } + + case database.ErrNotFound: + // fork introducing dynamic fees may not be active yet, + // hence we may have never stored unit fees. Load from config + // TODO: remove once fork is active + s.unitFees = s.cfg.GetDynamicFeesConfig().InitialUnitFees + + default: + return err + } + + switch feesWindowsBytes, err := s.singletonDB.Get(FeesWindowsKey); err { + case nil: + if err := s.feesWindows.FromBytes(feesWindowsBytes); err != nil { + return err + } + + 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 + s.feesWindows = commonfees.EmptyWindows + + default: + return err + } + currentSupply, err := database.GetUInt64(s.singletonDB, CurrentSupplyKey) if err != nil { return err @@ -2456,6 +2487,12 @@ func (s *state) writeMetadata() error { } s.persistedTimestamp = s.timestamp } + if err := s.singletonDB.Put(UnitFeesKey, s.unitFees.Bytes()); err != nil { + return fmt.Errorf("failed to write unit fees: %w", err) + } + if err := s.singletonDB.Put(FeesWindowsKey, s.feesWindows.Bytes()); err != nil { + return fmt.Errorf("failed to write unit fees: %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/builder/builder.go b/vms/platformvm/txs/builder/builder.go index 6b7c8fcd273f..ee2d5c9997dd 100644 --- a/vms/platformvm/txs/builder/builder.go +++ b/vms/platformvm/txs/builder/builder.go @@ -313,7 +313,7 @@ func (b *builder) NewImportTx( var ( dynamicFeesConfig = b.cfg.GetDynamicFeesConfig() unitFees = b.state.GetUnitFees() - unitWindows = b.state.GetConsumedUnitsWindows() + unitWindows = b.state.GetFeeWindows() ) // while outs are not ordered we add them to get current fees. We'll fix ordering later on @@ -473,7 +473,7 @@ func (b *builder) NewExportTx( var ( dynamicFeesConfig = b.cfg.GetDynamicFeesConfig() unitFees = b.state.GetUnitFees() - unitWindows = b.state.GetConsumedUnitsWindows() + unitWindows = b.state.GetFeeWindows() ) feeCalc := &fees.Calculator{ @@ -560,7 +560,7 @@ func (b *builder) NewCreateChainTx( var ( dynamicFeesConfig = b.cfg.GetDynamicFeesConfig() unitFees = b.state.GetUnitFees() - unitWindows = b.state.GetConsumedUnitsWindows() + unitWindows = b.state.GetFeeWindows() ) feeCalc := &fees.Calculator{ @@ -636,7 +636,7 @@ func (b *builder) NewCreateSubnetTx( var ( dynamicFeesConfig = b.cfg.GetDynamicFeesConfig() unitFees = b.state.GetUnitFees() - unitWindows = b.state.GetConsumedUnitsWindows() + unitWindows = b.state.GetFeeWindows() ) feeCalc := &fees.Calculator{ @@ -721,7 +721,7 @@ func (b *builder) NewAddValidatorTx( var ( dynamicFeesConfig = b.cfg.GetDynamicFeesConfig() unitFees = b.state.GetUnitFees() - unitWindows = b.state.GetConsumedUnitsWindows() + unitWindows = b.state.GetFeeWindows() ) feeCalc := &fees.Calculator{ @@ -804,7 +804,7 @@ func (b *builder) NewAddDelegatorTx( var ( dynamicFeesConfig = b.cfg.GetDynamicFeesConfig() unitFees = b.state.GetUnitFees() - unitWindows = b.state.GetConsumedUnitsWindows() + unitWindows = b.state.GetFeeWindows() ) feeCalc := &fees.Calculator{ @@ -888,7 +888,7 @@ func (b *builder) NewAddSubnetValidatorTx( var ( dynamicFeesConfig = b.cfg.GetDynamicFeesConfig() unitFees = b.state.GetUnitFees() - unitWindows = b.state.GetConsumedUnitsWindows() + unitWindows = b.state.GetFeeWindows() ) feeCalc := &fees.Calculator{ @@ -962,7 +962,7 @@ func (b *builder) NewRemoveSubnetValidatorTx( var ( dynamicFeesConfig = b.cfg.GetDynamicFeesConfig() unitFees = b.state.GetUnitFees() - unitWindows = b.state.GetConsumedUnitsWindows() + unitWindows = b.state.GetFeeWindows() ) feeCalc := &fees.Calculator{ @@ -1050,7 +1050,7 @@ func (b *builder) NewTransferSubnetOwnershipTx( var ( dynamicFeesConfig = b.cfg.GetDynamicFeesConfig() unitFees = b.state.GetUnitFees() - unitWindows = b.state.GetConsumedUnitsWindows() + unitWindows = b.state.GetFeeWindows() ) feeCalc := &fees.Calculator{ @@ -1118,7 +1118,7 @@ func (b *builder) NewBaseTx( var ( dynamicFeesConfig = b.cfg.GetDynamicFeesConfig() unitFees = b.state.GetUnitFees() - unitWindows = b.state.GetConsumedUnitsWindows() + unitWindows = b.state.GetFeeWindows() ) feeCalc := &fees.Calculator{ diff --git a/vms/platformvm/txs/executor/helpers_test.go b/vms/platformvm/txs/executor/helpers_test.go index 4b7a49e2912b..6b2d036ceddb 100644 --- a/vms/platformvm/txs/executor/helpers_test.go +++ b/vms/platformvm/txs/executor/helpers_test.go @@ -230,7 +230,7 @@ func addSubnet( require.NoError(err) unitFees := env.state.GetUnitFees() - unitWindows := env.state.GetConsumedUnitsWindows() + unitWindows := env.state.GetFeeWindows() executor := StandardTxExecutor{ Backend: &env.backend, From 744c41e57f95026fec1e1f0e6d882656d689c4b3 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 1 Feb 2024 18:02:06 +0100 Subject: [PATCH 101/190] nits --- vms/components/fees/dimensions.go | 6 +- vms/components/fees/window.go | 2 + vms/platformvm/block/builder/helpers_test.go | 9 +- vms/platformvm/block/executor/helpers_test.go | 10 +- .../block/executor/standard_block_test.go | 2 +- vms/platformvm/block/executor/verifier.go | 2 +- vms/platformvm/config/dynamic_fees_config.go | 16 ++- vms/platformvm/state/state.go | 2 - vms/platformvm/txs/builder/builder.go | 80 +++++------ .../txs/executor/atomic_tx_executor.go | 4 +- .../txs/executor/create_chain_test.go | 20 +-- .../txs/executor/create_subnet_test.go | 4 +- vms/platformvm/txs/executor/helpers_test.go | 10 +- .../txs/executor/proposal_tx_executor.go | 6 +- .../executor/staker_tx_verification_test.go | 4 +- .../txs/executor/standard_tx_executor_test.go | 128 +++++++++--------- 16 files changed, 155 insertions(+), 150 deletions(-) diff --git a/vms/components/fees/dimensions.go b/vms/components/fees/dimensions.go index eab049cb437f..31e46e246c7b 100644 --- a/vms/components/fees/dimensions.go +++ b/vms/components/fees/dimensions.go @@ -21,11 +21,7 @@ const ( uint64Len = 8 ) -var ( - EmptyUnitFees = Dimensions{} // helps avoiding reading unit fees from db for some pre E fork processing - EmptyUnitCaps = Dimensions{} // helps avoiding reading unit fees from db for some pre E fork processing - EmptyWindows = [FeeDimensions]Window{} -) +var Empty = Dimensions{} // helps avoiding reading unit fees from db for some pre E fork processing type ( Dimension int diff --git a/vms/components/fees/window.go b/vms/components/fees/window.go index 64364bb51f22..f050f46caa06 100644 --- a/vms/components/fees/window.go +++ b/vms/components/fees/window.go @@ -18,6 +18,8 @@ type ( Windows [FeeDimensions]Window ) +var EmptyWindows = [FeeDimensions]Window{} + func (w *Windows) Bytes() []byte { res := make([]byte, FeeDimensions*WindowSize*uint64Len) for i := Dimension(0); i < FeeDimensions; i++ { diff --git a/vms/platformvm/block/builder/helpers_test.go b/vms/platformvm/block/builder/helpers_test.go index 528f0ee3afe4..a540f788d7eb 100644 --- a/vms/platformvm/block/builder/helpers_test.go +++ b/vms/platformvm/block/builder/helpers_test.go @@ -255,12 +255,15 @@ func addSubnet(t *testing.T, env *environment) { stateDiff, err := state.NewDiff(genesisID, env.blkManager) require.NoError(err) - unitFees := env.state.GetUnitFees() - unitWindows := env.state.GetFeeWindows() + var ( + unitFees = env.state.GetUnitFees() + unitWindows = env.state.GetFeeWindows() + unitCaps = env.backend.Config.GetDynamicFeesConfig().BlockUnitsCap + ) executor := txexecutor.StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: fees.NewManager(unitFees, unitWindows), - UnitCaps: env.backend.Config.GetDynamicFeesConfig().BlockUnitsCap, + UnitCaps: unitCaps, State: stateDiff, Tx: testSubnet1, } diff --git a/vms/platformvm/block/executor/helpers_test.go b/vms/platformvm/block/executor/helpers_test.go index b14f8a13fc8a..696efb2e8e06 100644 --- a/vms/platformvm/block/executor/helpers_test.go +++ b/vms/platformvm/block/executor/helpers_test.go @@ -275,13 +275,15 @@ func addSubnet(env *environment) { panic(err) } - unitFees := env.state.GetUnitFees() - unitWindows := env.state.GetFeeWindows() - + var ( + unitFees = env.state.GetUnitFees() + unitWindows = env.state.GetFeeWindows() + unitCaps = env.backend.Config.GetDynamicFeesConfig().BlockUnitsCap + ) executor := executor.StandardTxExecutor{ Backend: env.backend, BlkFeeManager: fees.NewManager(unitFees, unitWindows), - UnitCaps: env.backend.Config.GetDynamicFeesConfig().BlockUnitsCap, + UnitCaps: unitCaps, State: stateDiff, Tx: testSubnet1, } diff --git a/vms/platformvm/block/executor/standard_block_test.go b/vms/platformvm/block/executor/standard_block_test.go index 07a30a5e797a..26353e838e81 100644 --- a/vms/platformvm/block/executor/standard_block_test.go +++ b/vms/platformvm/block/executor/standard_block_test.go @@ -154,7 +154,7 @@ func TestBanffStandardBlockTimeVerification(t *testing.T) { } utxoID := utxo.InputID() onParentAccept.EXPECT().GetUTXO(utxoID).Return(utxo, nil).AnyTimes() - onParentAccept.EXPECT().GetUnitFees().Return(commonfees.EmptyUnitFees).AnyTimes() + onParentAccept.EXPECT().GetUnitFees().Return(commonfees.Empty).AnyTimes() onParentAccept.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows).AnyTimes() // Create the tx diff --git a/vms/platformvm/block/executor/verifier.go b/vms/platformvm/block/executor/verifier.go index 9a26352f69a5..e5cb9f5195c5 100644 --- a/vms/platformvm/block/executor/verifier.go +++ b/vms/platformvm/block/executor/verifier.go @@ -468,7 +468,7 @@ func (v *verifier) processStandardTxs(txs []*txs.Tx, state state.Diff, parentID txExecutor := executor.StandardTxExecutor{ Backend: v.txExecutorBackend, BlkFeeManager: feeManager, - UnitCaps: v.txExecutorBackend.Config.GetDynamicFeesConfig().BlockUnitsCap, + UnitCaps: feesCfg.BlockUnitsCap, State: state, Tx: tx, } diff --git a/vms/platformvm/config/dynamic_fees_config.go b/vms/platformvm/config/dynamic_fees_config.go index f2ef0cbeedc0..5db0b5c7db8f 100644 --- a/vms/platformvm/config/dynamic_fees_config.go +++ b/vms/platformvm/config/dynamic_fees_config.go @@ -32,6 +32,15 @@ var EForkDynamicFeesConfig = DynamicFeesConfig{ 4, }, + MinUnitFees: commonfees.Dimensions{}, + + FeesChangeDenominator: commonfees.Dimensions{ + 1, + 1, + 1, + 1, + }, + BlockUnitsCap: commonfees.Dimensions{ math.MaxUint64, math.MaxUint64, @@ -45,13 +54,6 @@ var EForkDynamicFeesConfig = DynamicFeesConfig{ 1, 1, }, - - FeesChangeDenominator: commonfees.Dimensions{ - 1, - 1, - 1, - 1, - }, } type DynamicFeesConfig struct { diff --git a/vms/platformvm/state/state.go b/vms/platformvm/state/state.go index 65fc62ae2e71..08e2ae266171 100644 --- a/vms/platformvm/state/state.go +++ b/vms/platformvm/state/state.go @@ -714,8 +714,6 @@ func newState( chainDBCache: chainDBCache, singletonDB: prefixdb.New(SingletonPrefix, baseDB), - - unitFees: cfg.GetDynamicFeesConfig().InitialUnitFees, }, nil } diff --git a/vms/platformvm/txs/builder/builder.go b/vms/platformvm/txs/builder/builder.go index ee2d5c9997dd..58a0c0420012 100644 --- a/vms/platformvm/txs/builder/builder.go +++ b/vms/platformvm/txs/builder/builder.go @@ -311,9 +311,9 @@ func (b *builder) NewImportTx( ) if isEForkActive { var ( - dynamicFeesConfig = b.cfg.GetDynamicFeesConfig() - unitFees = b.state.GetUnitFees() - unitWindows = b.state.GetFeeWindows() + unitFees = b.state.GetUnitFees() + unitWindows = b.state.GetFeeWindows() + unitCaps = b.cfg.GetDynamicFeesConfig().BlockUnitsCap ) // while outs are not ordered we add them to get current fees. We'll fix ordering later on @@ -321,7 +321,7 @@ func (b *builder) NewImportTx( feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, FeeManager: commonfees.NewManager(unitFees, unitWindows), - ConsumedUnitsCap: dynamicFeesConfig.BlockUnitsCap, + ConsumedUnitsCap: unitCaps, Credentials: txs.EmptyCredentials(signers), } @@ -471,15 +471,15 @@ func (b *builder) NewExportTx( ) if isEForkActive { var ( - dynamicFeesConfig = b.cfg.GetDynamicFeesConfig() - unitFees = b.state.GetUnitFees() - unitWindows = b.state.GetFeeWindows() + unitFees = b.state.GetUnitFees() + unitWindows = b.state.GetFeeWindows() + unitCaps = b.cfg.GetDynamicFeesConfig().BlockUnitsCap ) feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, FeeManager: commonfees.NewManager(unitFees, unitWindows), - ConsumedUnitsCap: dynamicFeesConfig.BlockUnitsCap, + ConsumedUnitsCap: unitCaps, Credentials: txs.EmptyCredentials(signers), } @@ -558,15 +558,15 @@ func (b *builder) NewCreateChainTx( ) if isEForkActive { var ( - dynamicFeesConfig = b.cfg.GetDynamicFeesConfig() - unitFees = b.state.GetUnitFees() - unitWindows = b.state.GetFeeWindows() + unitFees = b.state.GetUnitFees() + unitWindows = b.state.GetFeeWindows() + unitCaps = b.cfg.GetDynamicFeesConfig().BlockUnitsCap ) feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, FeeManager: commonfees.NewManager(unitFees, unitWindows), - ConsumedUnitsCap: dynamicFeesConfig.BlockUnitsCap, + ConsumedUnitsCap: unitCaps, Credentials: txs.EmptyCredentials(signers), } @@ -634,15 +634,15 @@ func (b *builder) NewCreateSubnetTx( ) if isEForkActive { var ( - dynamicFeesConfig = b.cfg.GetDynamicFeesConfig() - unitFees = b.state.GetUnitFees() - unitWindows = b.state.GetFeeWindows() + unitFees = b.state.GetUnitFees() + unitWindows = b.state.GetFeeWindows() + unitCaps = b.cfg.GetDynamicFeesConfig().BlockUnitsCap ) feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, FeeManager: commonfees.NewManager(unitFees, unitWindows), - ConsumedUnitsCap: dynamicFeesConfig.BlockUnitsCap, + ConsumedUnitsCap: unitCaps, Credentials: txs.EmptyCredentials(signers), } @@ -719,15 +719,15 @@ func (b *builder) NewAddValidatorTx( ) if isEForkActive { var ( - dynamicFeesConfig = b.cfg.GetDynamicFeesConfig() - unitFees = b.state.GetUnitFees() - unitWindows = b.state.GetFeeWindows() + unitFees = b.state.GetUnitFees() + unitWindows = b.state.GetFeeWindows() + unitCaps = b.cfg.GetDynamicFeesConfig().BlockUnitsCap ) feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, FeeManager: commonfees.NewManager(unitFees, unitWindows), - ConsumedUnitsCap: dynamicFeesConfig.BlockUnitsCap, + ConsumedUnitsCap: unitCaps, Credentials: txs.EmptyCredentials(signers), } @@ -802,15 +802,15 @@ func (b *builder) NewAddDelegatorTx( ) if isEForkActive { var ( - dynamicFeesConfig = b.cfg.GetDynamicFeesConfig() - unitFees = b.state.GetUnitFees() - unitWindows = b.state.GetFeeWindows() + unitFees = b.state.GetUnitFees() + unitWindows = b.state.GetFeeWindows() + unitCaps = b.cfg.GetDynamicFeesConfig().BlockUnitsCap ) feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, FeeManager: commonfees.NewManager(unitFees, unitWindows), - ConsumedUnitsCap: dynamicFeesConfig.BlockUnitsCap, + ConsumedUnitsCap: unitCaps, Credentials: txs.EmptyCredentials(signers), } @@ -886,15 +886,15 @@ func (b *builder) NewAddSubnetValidatorTx( ) if isEForkActive { var ( - dynamicFeesConfig = b.cfg.GetDynamicFeesConfig() - unitFees = b.state.GetUnitFees() - unitWindows = b.state.GetFeeWindows() + unitFees = b.state.GetUnitFees() + unitWindows = b.state.GetFeeWindows() + unitCaps = b.cfg.GetDynamicFeesConfig().BlockUnitsCap ) feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, FeeManager: commonfees.NewManager(unitFees, unitWindows), - ConsumedUnitsCap: dynamicFeesConfig.BlockUnitsCap, + ConsumedUnitsCap: unitCaps, Credentials: txs.EmptyCredentials(signers), } @@ -960,15 +960,15 @@ func (b *builder) NewRemoveSubnetValidatorTx( ) if isEForkActive { var ( - dynamicFeesConfig = b.cfg.GetDynamicFeesConfig() - unitFees = b.state.GetUnitFees() - unitWindows = b.state.GetFeeWindows() + unitFees = b.state.GetUnitFees() + unitWindows = b.state.GetFeeWindows() + unitCaps = b.cfg.GetDynamicFeesConfig().BlockUnitsCap ) feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, FeeManager: commonfees.NewManager(unitFees, unitWindows), - ConsumedUnitsCap: dynamicFeesConfig.BlockUnitsCap, + ConsumedUnitsCap: unitCaps, Credentials: txs.EmptyCredentials(signers), } @@ -1048,15 +1048,15 @@ func (b *builder) NewTransferSubnetOwnershipTx( ) if isEForkActive { var ( - dynamicFeesConfig = b.cfg.GetDynamicFeesConfig() - unitFees = b.state.GetUnitFees() - unitWindows = b.state.GetFeeWindows() + unitFees = b.state.GetUnitFees() + unitWindows = b.state.GetFeeWindows() + unitCaps = b.cfg.GetDynamicFeesConfig().BlockUnitsCap ) feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, FeeManager: commonfees.NewManager(unitFees, unitWindows), - ConsumedUnitsCap: dynamicFeesConfig.BlockUnitsCap, + ConsumedUnitsCap: unitCaps, Credentials: txs.EmptyCredentials(signers), } @@ -1116,15 +1116,15 @@ func (b *builder) NewBaseTx( ) if isEForkActive { var ( - dynamicFeesConfig = b.cfg.GetDynamicFeesConfig() - unitFees = b.state.GetUnitFees() - unitWindows = b.state.GetFeeWindows() + unitFees = b.state.GetUnitFees() + unitWindows = b.state.GetFeeWindows() + unitCaps = b.cfg.GetDynamicFeesConfig().BlockUnitsCap ) feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, FeeManager: commonfees.NewManager(unitFees, unitWindows), - ConsumedUnitsCap: dynamicFeesConfig.BlockUnitsCap, + ConsumedUnitsCap: unitCaps, Credentials: txs.EmptyCredentials(signers), } diff --git a/vms/platformvm/txs/executor/atomic_tx_executor.go b/vms/platformvm/txs/executor/atomic_tx_executor.go index a4095f0310d5..b9c41bcce1cf 100644 --- a/vms/platformvm/txs/executor/atomic_tx_executor.go +++ b/vms/platformvm/txs/executor/atomic_tx_executor.go @@ -102,8 +102,8 @@ func (e *AtomicTxExecutor) atomicTx(tx txs.UnsignedTx) error { executor := StandardTxExecutor{ Backend: e.Backend, - BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees, commonfees.EmptyWindows), - UnitCaps: commonfees.EmptyUnitCaps, + BlkFeeManager: commonfees.NewManager(commonfees.Empty, commonfees.EmptyWindows), + UnitCaps: commonfees.Empty, State: e.OnAccept, Tx: e.Tx, } diff --git a/vms/platformvm/txs/executor/create_chain_test.go b/vms/platformvm/txs/executor/create_chain_test.go index 5cc8e037002f..de9cf700670d 100644 --- a/vms/platformvm/txs/executor/create_chain_test.go +++ b/vms/platformvm/txs/executor/create_chain_test.go @@ -50,8 +50,8 @@ func TestCreateChainTxInsufficientControlSigs(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees, commonfees.EmptyWindows), - UnitCaps: commonfees.EmptyUnitCaps, + BlkFeeManager: commonfees.NewManager(commonfees.Empty, commonfees.EmptyWindows), + UnitCaps: commonfees.Empty, State: stateDiff, Tx: tx, } @@ -91,8 +91,8 @@ func TestCreateChainTxWrongControlSig(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees, commonfees.EmptyWindows), - UnitCaps: commonfees.EmptyUnitCaps, + BlkFeeManager: commonfees.NewManager(commonfees.Empty, commonfees.EmptyWindows), + UnitCaps: commonfees.Empty, State: stateDiff, Tx: tx, } @@ -126,8 +126,8 @@ func TestCreateChainTxNoSuchSubnet(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees, commonfees.EmptyWindows), - UnitCaps: commonfees.EmptyUnitCaps, + BlkFeeManager: commonfees.NewManager(commonfees.Empty, commonfees.EmptyWindows), + UnitCaps: commonfees.Empty, State: stateDiff, Tx: tx, } @@ -158,8 +158,8 @@ func TestCreateChainTxValid(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees, commonfees.EmptyWindows), - UnitCaps: commonfees.EmptyUnitCaps, + BlkFeeManager: commonfees.NewManager(commonfees.Empty, commonfees.EmptyWindows), + UnitCaps: commonfees.Empty, State: stateDiff, Tx: tx, } @@ -231,8 +231,8 @@ func TestCreateChainTxAP3FeeChange(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees, commonfees.EmptyWindows), - UnitCaps: commonfees.EmptyUnitCaps, + BlkFeeManager: commonfees.NewManager(commonfees.Empty, commonfees.EmptyWindows), + UnitCaps: commonfees.Empty, State: stateDiff, Tx: tx, } diff --git a/vms/platformvm/txs/executor/create_subnet_test.go b/vms/platformvm/txs/executor/create_subnet_test.go index 7041f0f84c2a..83f617a712ec 100644 --- a/vms/platformvm/txs/executor/create_subnet_test.go +++ b/vms/platformvm/txs/executor/create_subnet_test.go @@ -79,8 +79,8 @@ func TestCreateSubnetTxAP3FeeChange(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(commonfees.EmptyUnitFees, commonfees.EmptyWindows), - UnitCaps: commonfees.EmptyUnitCaps, + BlkFeeManager: commonfees.NewManager(commonfees.Empty, commonfees.EmptyWindows), + UnitCaps: commonfees.Empty, State: stateDiff, Tx: tx, } diff --git a/vms/platformvm/txs/executor/helpers_test.go b/vms/platformvm/txs/executor/helpers_test.go index 6b2d036ceddb..e8147b84bb24 100644 --- a/vms/platformvm/txs/executor/helpers_test.go +++ b/vms/platformvm/txs/executor/helpers_test.go @@ -229,13 +229,15 @@ func addSubnet( stateDiff, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - unitFees := env.state.GetUnitFees() - unitWindows := env.state.GetFeeWindows() - + var ( + unitFees = env.state.GetUnitFees() + unitWindows = env.state.GetFeeWindows() + unitCaps = env.backend.Config.GetDynamicFeesConfig().BlockUnitsCap + ) executor := StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: fees.NewManager(unitFees, unitWindows), - UnitCaps: env.backend.Config.GetDynamicFeesConfig().BlockUnitsCap, + UnitCaps: unitCaps, State: stateDiff, Tx: testSubnet1, } diff --git a/vms/platformvm/txs/executor/proposal_tx_executor.go b/vms/platformvm/txs/executor/proposal_tx_executor.go index 335eb1ffb295..0aaab27c5b4b 100644 --- a/vms/platformvm/txs/executor/proposal_tx_executor.go +++ b/vms/platformvm/txs/executor/proposal_tx_executor.go @@ -118,7 +118,7 @@ func (e *ProposalTxExecutor) AddValidatorTx(tx *txs.AddValidatorTx) error { onAbortOuts, err := verifyAddValidatorTx( e.Backend, e.BlkFeeManager, - commonfees.EmptyUnitCaps, + commonfees.Empty, e.OnCommitState, e.Tx, tx, @@ -167,7 +167,7 @@ func (e *ProposalTxExecutor) AddSubnetValidatorTx(tx *txs.AddSubnetValidatorTx) if err := verifyAddSubnetValidatorTx( e.Backend, e.BlkFeeManager, - commonfees.EmptyUnitCaps, + commonfees.Empty, e.OnCommitState, e.Tx, tx, @@ -215,7 +215,7 @@ func (e *ProposalTxExecutor) AddDelegatorTx(tx *txs.AddDelegatorTx) error { onAbortOuts, err := verifyAddDelegatorTx( e.Backend, e.BlkFeeManager, - commonfees.EmptyUnitCaps, + commonfees.Empty, e.OnCommitState, e.Tx, tx, diff --git a/vms/platformvm/txs/executor/staker_tx_verification_test.go b/vms/platformvm/txs/executor/staker_tx_verification_test.go index 9de443943a71..251ff750486c 100644 --- a/vms/platformvm/txs/executor/staker_tx_verification_test.go +++ b/vms/platformvm/txs/executor/staker_tx_verification_test.go @@ -601,13 +601,13 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { var ( backend = tt.backendF(ctrl) - feeManager = fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows) + feeManager = fees.NewManager(fees.Empty, fees.EmptyWindows) state = tt.stateF(ctrl) sTx = tt.sTxF() tx = tt.txF() ) - err := verifyAddPermissionlessValidatorTx(backend, feeManager, fees.EmptyUnitCaps, state, sTx, tx) + err := verifyAddPermissionlessValidatorTx(backend, feeManager, fees.Empty, state, sTx, tx) require.ErrorIs(t, err, tt.expectedErr) }) } diff --git a/vms/platformvm/txs/executor/standard_tx_executor_test.go b/vms/platformvm/txs/executor/standard_tx_executor_test.go index 40cd8b463134..efae69901b71 100644 --- a/vms/platformvm/txs/executor/standard_tx_executor_test.go +++ b/vms/platformvm/txs/executor/standard_tx_executor_test.go @@ -92,8 +92,8 @@ func TestStandardTxExecutorAddValidatorTxEmptyID(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + UnitCaps: fees.Empty, State: stateDiff, Tx: tx, } @@ -350,8 +350,8 @@ func TestStandardTxExecutorAddDelegator(t *testing.T) { executor := StandardTxExecutor{ Backend: &freshTH.backend, - BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + UnitCaps: fees.Empty, State: onAcceptState, Tx: tx, } @@ -390,8 +390,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + UnitCaps: fees.Empty, State: onAcceptState, Tx: tx, } @@ -420,8 +420,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + UnitCaps: fees.Empty, State: onAcceptState, Tx: tx, } @@ -464,8 +464,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + UnitCaps: fees.Empty, State: onAcceptState, Tx: tx, } @@ -509,8 +509,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + UnitCaps: fees.Empty, State: onAcceptState, Tx: tx, } @@ -537,8 +537,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + UnitCaps: fees.Empty, State: onAcceptState, Tx: tx, } @@ -564,8 +564,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { require.NoError(err) executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + UnitCaps: fees.Empty, State: onAcceptState, Tx: tx, } @@ -594,8 +594,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + UnitCaps: fees.Empty, State: onAcceptState, Tx: tx, } @@ -652,8 +652,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + UnitCaps: fees.Empty, State: onAcceptState, Tx: duplicateSubnetTx, } @@ -691,8 +691,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + UnitCaps: fees.Empty, State: onAcceptState, Tx: tx, } @@ -726,8 +726,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + UnitCaps: fees.Empty, State: onAcceptState, Tx: tx, } @@ -759,8 +759,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + UnitCaps: fees.Empty, State: onAcceptState, Tx: tx, } @@ -802,8 +802,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + UnitCaps: fees.Empty, State: onAcceptState, Tx: tx, } @@ -839,8 +839,8 @@ func TestBanffStandardTxExecutorAddValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + UnitCaps: fees.Empty, State: onAcceptState, Tx: tx, } @@ -867,8 +867,8 @@ func TestBanffStandardTxExecutorAddValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + UnitCaps: fees.Empty, State: onAcceptState, Tx: tx, } @@ -908,8 +908,8 @@ func TestBanffStandardTxExecutorAddValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + UnitCaps: fees.Empty, State: onAcceptState, Tx: tx, } @@ -946,8 +946,8 @@ func TestBanffStandardTxExecutorAddValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + UnitCaps: fees.Empty, State: onAcceptState, Tx: tx, } @@ -983,8 +983,8 @@ func TestBanffStandardTxExecutorAddValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + UnitCaps: fees.Empty, State: onAcceptState, Tx: tx, } @@ -1762,8 +1762,8 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + UnitCaps: fees.Empty, Tx: env.tx, State: env.state, } @@ -1794,8 +1794,8 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + UnitCaps: fees.Empty, Tx: env.tx, State: env.state, } @@ -1827,8 +1827,8 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + UnitCaps: fees.Empty, Tx: env.tx, State: env.state, } @@ -1863,8 +1863,8 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + UnitCaps: fees.Empty, Tx: env.tx, State: env.state, } @@ -1897,8 +1897,8 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + UnitCaps: fees.Empty, Tx: env.tx, State: env.state, } @@ -1930,8 +1930,8 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + UnitCaps: fees.Empty, Tx: env.tx, State: env.state, } @@ -1965,8 +1965,8 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + UnitCaps: fees.Empty, Tx: env.tx, State: env.state, } @@ -2003,8 +2003,8 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + UnitCaps: fees.Empty, Tx: env.tx, State: env.state, } @@ -2165,8 +2165,8 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + UnitCaps: fees.Empty, Tx: env.tx, State: env.state, } @@ -2197,8 +2197,8 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + UnitCaps: fees.Empty, Tx: env.tx, State: env.state, } @@ -2231,8 +2231,8 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + UnitCaps: fees.Empty, Tx: env.tx, State: env.state, } @@ -2270,8 +2270,8 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + UnitCaps: fees.Empty, Tx: env.tx, State: env.state, } @@ -2314,8 +2314,8 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(fees.EmptyUnitFees, fees.EmptyWindows), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + UnitCaps: fees.Empty, Tx: env.tx, State: env.state, } From b5d6cfe7f0e117985cf916576dcf1a1dea3c8b49 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Tue, 6 Feb 2024 12:18:22 +0100 Subject: [PATCH 102/190] nit --- vms/platformvm/config/config.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/vms/platformvm/config/config.go b/vms/platformvm/config/config.go index 34cc99519121..91927e0b44f4 100644 --- a/vms/platformvm/config/config.go +++ b/vms/platformvm/config/config.go @@ -41,31 +41,31 @@ type Config struct { // Set of subnets that this node is validating TrackedSubnets set.Set[ids.ID] - // Pre E Fork, fee that is burned by every non-state creating transaction + // Fee that is burned by every non-state creating transaction TxFee uint64 - // Pre E Fork, fee that must be burned by every state creating transaction before AP3 + // Fee that must be burned by every state creating transaction before AP3 CreateAssetTxFee uint64 - // Pre E Fork, fee that must be burned by every subnet creating transaction after AP3 + // Fee that must be burned by every subnet creating transaction after AP3 CreateSubnetTxFee uint64 - // Pre E Fork, fee that must be burned by every transform subnet transaction + // Fee that must be burned by every transform subnet transaction TransformSubnetTxFee uint64 - // Pre E Fork, fee that must be burned by every blockchain creating transaction after AP3 + // Fee that must be burned by every blockchain creating transaction after AP3 CreateBlockchainTxFee uint64 - // Pre E Fork, transaction fee for adding a primary network validator + // Transaction fee for adding a primary network validator AddPrimaryNetworkValidatorFee uint64 - // Pre E Fork, transaction fee for adding a primary network delegator + // Transaction fee for adding a primary network delegator AddPrimaryNetworkDelegatorFee uint64 - // Pre E Fork, transaction fee for adding a subnet validator + // Transaction fee for adding a subnet validator AddSubnetValidatorFee uint64 - // Pre E Fork, transaction fee for adding a subnet delegator + // Transaction fee for adding a subnet delegator AddSubnetDelegatorFee uint64 // The minimum amount of tokens one must bond to be a validator From 088cc532b63ff3ca7740dba26d9a7bb5c714f097 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Tue, 6 Feb 2024 12:48:09 +0100 Subject: [PATCH 103/190] fixed P-chain api with GetFeeWindows --- tests/e2e/p/workflow.go | 7 +++++-- vms/platformvm/client.go | 12 ++++++------ vms/platformvm/service.go | 9 ++++----- wallet/chain/p/wallet.go | 5 ++++- 4 files changed, 19 insertions(+), 14 deletions(-) diff --git a/tests/e2e/p/workflow.go b/tests/e2e/p/workflow.go index f024c09bd7ed..dc5490a690cb 100644 --- a/tests/e2e/p/workflow.go +++ b/tests/e2e/p/workflow.go @@ -20,6 +20,7 @@ import ( "github.com/ava-labs/avalanchego/utils/units" "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/platformvm" + "github.com/ava-labs/avalanchego/vms/platformvm/config" "github.com/ava-labs/avalanchego/vms/platformvm/signer" "github.com/ava-labs/avalanchego/vms/platformvm/txs" "github.com/ava-labs/avalanchego/vms/platformvm/txs/fees" @@ -140,7 +141,9 @@ var _ = e2e.DescribePChain("[Workflow]", func() { unitFees, err := pChainClient.GetUnitFees(e2e.DefaultContext()) require.NoError(err) - unitCaps, err := pChainClient.GetBlockUnitsCap(e2e.DefaultContext()) + unitCaps := config.EUpgradeDynamicFeesConfig.BlockUnitsCap + + feeWindows, err := pChainClient.GetFeeWindows(e2e.DefaultContext()) require.NoError(err) tx, err := pWallet.IssueExportTx( @@ -160,7 +163,7 @@ var _ = e2e.DescribePChain("[Workflow]", func() { // retrieve fees paid for the tx feeCalc := fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(unitFees, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(unitFees, feeWindows), ConsumedUnitsCap: unitCaps, Credentials: tx.Creds, } diff --git a/vms/platformvm/client.go b/vms/platformvm/client.go index 1bccc9382139..aa54c792b1ac 100644 --- a/vms/platformvm/client.go +++ b/vms/platformvm/client.go @@ -268,8 +268,8 @@ type Client interface { // GetUnitFees returns the current unit fees that a transaction must pay to be accepted GetUnitFees(ctx context.Context, options ...rpc.Option) (commonfees.Dimensions, error) - // GetBlockUnitsCap returns the current maximal units that can be consumed in a block - GetBlockUnitsCap(ctx context.Context, options ...rpc.Option) (commonfees.Dimensions, error) + // GetFeeWindows returns the current maximal units that can be consumed in a block + GetFeeWindows(ctx context.Context, options ...rpc.Option) (commonfees.Windows, error) } // Client implementation for interacting with the P Chain endpoint @@ -905,8 +905,8 @@ func (c *client) GetUnitFees(ctx context.Context, options ...rpc.Option) (common return res.UnitFees, err } -func (c *client) GetBlockUnitsCap(ctx context.Context, options ...rpc.Option) (commonfees.Dimensions, error) { - res := &GetBlockUnitsCapReply{} - err := c.requester.SendRequest(ctx, "platform.getBlockUnitsCap", struct{}{}, res, options...) - return res.MaxUnits, err +func (c *client) GetFeeWindows(ctx context.Context, options ...rpc.Option) (commonfees.Windows, error) { + res := &GetFeeWindowsReply{} + err := c.requester.SendRequest(ctx, "platform.getFeeWindows", struct{}{}, res, options...) + return res.FeeWindows, err } diff --git a/vms/platformvm/service.go b/vms/platformvm/service.go index fce9a1d6e591..938a86b66cd5 100644 --- a/vms/platformvm/service.go +++ b/vms/platformvm/service.go @@ -32,7 +32,6 @@ import ( "github.com/ava-labs/avalanchego/utils/set" "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/components/keystore" - "github.com/ava-labs/avalanchego/vms/platformvm/config" "github.com/ava-labs/avalanchego/vms/platformvm/fx" "github.com/ava-labs/avalanchego/vms/platformvm/reward" "github.com/ava-labs/avalanchego/vms/platformvm/signer" @@ -2833,13 +2832,13 @@ func (s *Service) GetUnitFees(_ *http.Request, _ *struct{}, reply *GetUnitFeesRe } // GetBlockUnitsCapReply is the response from GetBlockUnitsCap -type GetBlockUnitsCapReply struct { +type GetFeeWindowsReply struct { // Current timestamp - MaxUnits commonfees.Dimensions `json:"maxUnits"` + FeeWindows commonfees.Windows `json:"feeWindows"` } // GetTimestamp returns the current timestamp on chain. -func (s *Service) GetBlockUnitsCap(_ *http.Request, _ *struct{}, reply *GetBlockUnitsCapReply) error { +func (s *Service) GetFeeWindows(_ *http.Request, _ *struct{}, reply *GetFeeWindowsReply) error { s.vm.ctx.Log.Debug("API called", zap.String("service", "platform"), zap.String("method", "getBlockUnitsCap"), @@ -2848,7 +2847,7 @@ func (s *Service) GetBlockUnitsCap(_ *http.Request, _ *struct{}, reply *GetBlock s.vm.ctx.Lock.Lock() defer s.vm.ctx.Lock.Unlock() - reply.MaxUnits = config.EUpgradeDynamicFeesConfig.BlockUnitsCap + reply.FeeWindows = s.vm.state.GetFeeWindows() return nil } diff --git a/wallet/chain/p/wallet.go b/wallet/chain/p/wallet.go index c84b1dab690a..d4bb92636f58 100644 --- a/wallet/chain/p/wallet.go +++ b/wallet/chain/p/wallet.go @@ -13,6 +13,7 @@ import ( "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/components/fees" "github.com/ava-labs/avalanchego/vms/platformvm" + "github.com/ava-labs/avalanchego/vms/platformvm/config" "github.com/ava-labs/avalanchego/vms/platformvm/signer" "github.com/ava-labs/avalanchego/vms/platformvm/status" "github.com/ava-labs/avalanchego/vms/platformvm/txs" @@ -272,6 +273,7 @@ func NewWallet( dynamicBuilder: dynFeesBuilder, signer: signer, client: client, + unitCaps: config.EUpgradeDynamicFeesConfig.BlockUnitsCap, } } @@ -284,6 +286,7 @@ type wallet struct { builder Builder dynamicBuilder *DynamicFeesBuilder unitFees, unitCaps fees.Dimensions + feeWindows fees.Windows } func (w *wallet) Builder() Builder { @@ -784,7 +787,7 @@ func (w *wallet) refreshFeesData(options ...common.Option) error { return err } - w.unitCaps, err = w.client.GetBlockUnitsCap(ctx) + w.feeWindows, err = w.client.GetFeeWindows(ctx) if err != nil { return err } From 97f48977a855ef1b3553b67aaf2a2bb2ee8e6988 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Tue, 6 Feb 2024 12:52:03 +0100 Subject: [PATCH 104/190] nit --- tests/e2e/p/workflow.go | 4 ++-- vms/platformvm/client.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/e2e/p/workflow.go b/tests/e2e/p/workflow.go index dc5490a690cb..0bd2eeb4ccde 100644 --- a/tests/e2e/p/workflow.go +++ b/tests/e2e/p/workflow.go @@ -138,11 +138,11 @@ var _ = e2e.DescribePChain("[Workflow]", func() { pChainExportFee := uint64(0) ginkgo.By("export avax from P to X chain", func() { + unitCaps := config.EUpgradeDynamicFeesConfig.BlockUnitsCap + unitFees, err := pChainClient.GetUnitFees(e2e.DefaultContext()) require.NoError(err) - unitCaps := config.EUpgradeDynamicFeesConfig.BlockUnitsCap - feeWindows, err := pChainClient.GetFeeWindows(e2e.DefaultContext()) require.NoError(err) diff --git a/vms/platformvm/client.go b/vms/platformvm/client.go index aa54c792b1ac..11b1997be325 100644 --- a/vms/platformvm/client.go +++ b/vms/platformvm/client.go @@ -268,7 +268,7 @@ type Client interface { // GetUnitFees returns the current unit fees that a transaction must pay to be accepted GetUnitFees(ctx context.Context, options ...rpc.Option) (commonfees.Dimensions, error) - // GetFeeWindows returns the current maximal units that can be consumed in a block + // GetFeeWindows returns the fee window needed to calculate next block unit fees GetFeeWindows(ctx context.Context, options ...rpc.Option) (commonfees.Windows, error) } From 0217214927f6a128ad163425a3cd41546794f7bf Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Tue, 6 Feb 2024 12:59:01 +0100 Subject: [PATCH 105/190] added UT --- vms/platformvm/service_test.go | 41 ++++++++++++++++------------------ 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/vms/platformvm/service_test.go b/vms/platformvm/service_test.go index 6fb984b64c44..8681e4d7aeac 100644 --- a/vms/platformvm/service_test.go +++ b/vms/platformvm/service_test.go @@ -1048,31 +1048,28 @@ func TestGetUnitFees(t *testing.T) { require.Equal(updatedUnitFees, reply.UnitFees) } -// TODO ABENEGIA: rethink the way to pull up this stuff -// func TestGetBlockUnitsCap(t *testing.T) { -// require := require.New(t) -// service, _ := defaultService(t) - -// reply := GetBlockUnitsCapReply{} -// require.NoError(service.GetBlockUnitsCap(nil, nil, &reply)) +func TestGetFeeWindows(t *testing.T) { + require := require.New(t) + service, _ := defaultService(t) -// service.vm.ctx.Lock.Lock() + reply := GetFeeWindowsReply{} + require.NoError(service.GetFeeWindows(nil, nil, &reply)) -// unitCaps, err := service.vm.state.GetBlockUnitCaps() -// require.NoError(err) + service.vm.ctx.Lock.Lock() -// require.Equal(unitCaps, reply.MaxUnits) + feeWindows := service.vm.state.GetFeeWindows() + require.Equal(feeWindows, reply.FeeWindows) -// updatedUnitCaps := commonfees.Dimensions{ -// 123, -// 456, -// 789, -// 1011, -// } -// require.NoError(service.vm.state.SetBlockUnitCaps(updatedUnitCaps)) + updatedFeeWindows := commonfees.Windows{ + commonfees.Window{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, + commonfees.Window{11, 12, 13, 14, 15, 16, 17, 18, 19, 20}, + commonfees.Window{math.MaxUint64, 0, math.MaxUint64, 0, math.MaxUint64, 0, math.MaxUint64, 0, math.MaxUint64, 0}, + commonfees.Window{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, + } + service.vm.state.SetConsumedUnitsWindows(updatedFeeWindows) -// service.vm.ctx.Lock.Unlock() + service.vm.ctx.Lock.Unlock() -// require.NoError(service.GetBlockUnitsCap(nil, nil, &reply)) -// require.Equal(updatedUnitCaps, reply.MaxUnits) -// } + require.NoError(service.GetFeeWindows(nil, nil, &reply)) + require.Equal(updatedFeeWindows, reply.FeeWindows) +} From 4dc0983e15efdd65f6dbd1506d4f8181e4bf832c Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Tue, 6 Feb 2024 13:14:07 +0100 Subject: [PATCH 106/190] nit --- vms/platformvm/block/executor/verifier.go | 2 +- vms/platformvm/service_test.go | 2 +- vms/platformvm/state/diff.go | 4 +- vms/platformvm/state/mock_state.go | 72 +++++++++++------------ vms/platformvm/state/state.go | 4 +- 5 files changed, 42 insertions(+), 42 deletions(-) diff --git a/vms/platformvm/block/executor/verifier.go b/vms/platformvm/block/executor/verifier.go index f5f5d60b0857..6cb504bc7300 100644 --- a/vms/platformvm/block/executor/verifier.go +++ b/vms/platformvm/block/executor/verifier.go @@ -509,7 +509,7 @@ func (v *verifier) processStandardTxs(txs []*txs.Tx, state state.Diff, parentID if isEForkActive { state.SetUnitFees(feeManager.GetUnitFees()) - state.SetConsumedUnitsWindows(feeManager.GetFeeWindows()) + state.SetFeeWindows(feeManager.GetFeeWindows()) } if numFuncs := len(funcs); numFuncs == 1 { diff --git a/vms/platformvm/service_test.go b/vms/platformvm/service_test.go index 8681e4d7aeac..37551734c1a9 100644 --- a/vms/platformvm/service_test.go +++ b/vms/platformvm/service_test.go @@ -1066,7 +1066,7 @@ func TestGetFeeWindows(t *testing.T) { commonfees.Window{math.MaxUint64, 0, math.MaxUint64, 0, math.MaxUint64, 0, math.MaxUint64, 0, math.MaxUint64, 0}, commonfees.Window{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, } - service.vm.state.SetConsumedUnitsWindows(updatedFeeWindows) + service.vm.state.SetFeeWindows(updatedFeeWindows) service.vm.ctx.Lock.Unlock() diff --git a/vms/platformvm/state/diff.go b/vms/platformvm/state/diff.go index 5dffe5f02ef0..c54ceb416c29 100644 --- a/vms/platformvm/state/diff.go +++ b/vms/platformvm/state/diff.go @@ -106,7 +106,7 @@ func (d *diff) GetFeeWindows() commonfees.Windows { return d.consumedUnitsWindows } -func (d *diff) SetConsumedUnitsWindows(windows commonfees.Windows) { +func (d *diff) SetFeeWindows(windows commonfees.Windows) { d.consumedUnitsWindows = windows } @@ -423,7 +423,7 @@ func (d *diff) DeleteUTXO(utxoID ids.ID) { func (d *diff) Apply(baseState Chain) error { baseState.SetTimestamp(d.timestamp) baseState.SetUnitFees(d.unitFees) - baseState.SetConsumedUnitsWindows(d.consumedUnitsWindows) + baseState.SetFeeWindows(d.consumedUnitsWindows) 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 21bfc3d8d0e0..a0f27194bc54 100644 --- a/vms/platformvm/state/mock_state.go +++ b/vms/platformvm/state/mock_state.go @@ -454,18 +454,6 @@ func (mr *MockChainMockRecorder) PutPendingValidator(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PutPendingValidator", reflect.TypeOf((*MockChain)(nil).PutPendingValidator), arg0) } -// SetConsumedUnitsWindows mocks base method. -func (m *MockChain) SetConsumedUnitsWindows(arg0 fees.Windows) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "SetConsumedUnitsWindows", arg0) -} - -// SetConsumedUnitsWindows indicates an expected call of SetConsumedUnitsWindows. -func (mr *MockChainMockRecorder) SetConsumedUnitsWindows(arg0 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetConsumedUnitsWindows", reflect.TypeOf((*MockChain)(nil).SetConsumedUnitsWindows), arg0) -} - // SetCurrentSupply mocks base method. func (m *MockChain) SetCurrentSupply(arg0 ids.ID, arg1 uint64) { m.ctrl.T.Helper() @@ -492,6 +480,18 @@ func (mr *MockChainMockRecorder) SetDelegateeReward(arg0, arg1, arg2 any) *gomoc return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetDelegateeReward", reflect.TypeOf((*MockChain)(nil).SetDelegateeReward), arg0, arg1, arg2) } +// SetFeeWindows mocks base method. +func (m *MockChain) SetFeeWindows(arg0 fees.Windows) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetFeeWindows", arg0) +} + +// SetFeeWindows indicates an expected call of SetFeeWindows. +func (mr *MockChainMockRecorder) SetFeeWindows(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetFeeWindows", reflect.TypeOf((*MockChain)(nil).SetFeeWindows), arg0) +} + // SetSubnetOwner mocks base method. func (m *MockChain) SetSubnetOwner(arg0 ids.ID, arg1 fx.Owner) { m.ctrl.T.Helper() @@ -968,18 +968,6 @@ func (mr *MockDiffMockRecorder) PutPendingValidator(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PutPendingValidator", reflect.TypeOf((*MockDiff)(nil).PutPendingValidator), arg0) } -// SetConsumedUnitsWindows mocks base method. -func (m *MockDiff) SetConsumedUnitsWindows(arg0 fees.Windows) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "SetConsumedUnitsWindows", arg0) -} - -// SetConsumedUnitsWindows indicates an expected call of SetConsumedUnitsWindows. -func (mr *MockDiffMockRecorder) SetConsumedUnitsWindows(arg0 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetConsumedUnitsWindows", reflect.TypeOf((*MockDiff)(nil).SetConsumedUnitsWindows), arg0) -} - // SetCurrentSupply mocks base method. func (m *MockDiff) SetCurrentSupply(arg0 ids.ID, arg1 uint64) { m.ctrl.T.Helper() @@ -1006,6 +994,18 @@ func (mr *MockDiffMockRecorder) SetDelegateeReward(arg0, arg1, arg2 any) *gomock return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetDelegateeReward", reflect.TypeOf((*MockDiff)(nil).SetDelegateeReward), arg0, arg1, arg2) } +// SetFeeWindows mocks base method. +func (m *MockDiff) SetFeeWindows(arg0 fees.Windows) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetFeeWindows", arg0) +} + +// SetFeeWindows indicates an expected call of SetFeeWindows. +func (mr *MockDiffMockRecorder) SetFeeWindows(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetFeeWindows", reflect.TypeOf((*MockDiff)(nil).SetFeeWindows), arg0) +} + // SetSubnetOwner mocks base method. func (m *MockDiff) SetSubnetOwner(arg0 ids.ID, arg1 fx.Owner) { m.ctrl.T.Helper() @@ -1711,18 +1711,6 @@ func (mr *MockStateMockRecorder) PutPendingValidator(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PutPendingValidator", reflect.TypeOf((*MockState)(nil).PutPendingValidator), arg0) } -// SetConsumedUnitsWindows mocks base method. -func (m *MockState) SetConsumedUnitsWindows(arg0 fees.Windows) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "SetConsumedUnitsWindows", arg0) -} - -// SetConsumedUnitsWindows indicates an expected call of SetConsumedUnitsWindows. -func (mr *MockStateMockRecorder) SetConsumedUnitsWindows(arg0 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetConsumedUnitsWindows", reflect.TypeOf((*MockState)(nil).SetConsumedUnitsWindows), arg0) -} - // SetCurrentSupply mocks base method. func (m *MockState) SetCurrentSupply(arg0 ids.ID, arg1 uint64) { m.ctrl.T.Helper() @@ -1749,6 +1737,18 @@ func (mr *MockStateMockRecorder) SetDelegateeReward(arg0, arg1, arg2 any) *gomoc return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetDelegateeReward", reflect.TypeOf((*MockState)(nil).SetDelegateeReward), arg0, arg1, arg2) } +// SetFeeWindows mocks base method. +func (m *MockState) SetFeeWindows(arg0 fees.Windows) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetFeeWindows", arg0) +} + +// SetFeeWindows indicates an expected call of SetFeeWindows. +func (mr *MockStateMockRecorder) SetFeeWindows(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetFeeWindows", reflect.TypeOf((*MockState)(nil).SetFeeWindows), arg0) +} + // SetHeight mocks base method. func (m *MockState) SetHeight(arg0 uint64) { m.ctrl.T.Helper() diff --git a/vms/platformvm/state/state.go b/vms/platformvm/state/state.go index 2271f6aeb5d6..e725ffbcfe2c 100644 --- a/vms/platformvm/state/state.go +++ b/vms/platformvm/state/state.go @@ -107,7 +107,7 @@ type Chain interface { SetUnitFees(uf commonfees.Dimensions) GetFeeWindows() commonfees.Windows - SetConsumedUnitsWindows(windows commonfees.Windows) + SetFeeWindows(windows commonfees.Windows) GetTimestamp() time.Time SetTimestamp(tm time.Time) @@ -1100,7 +1100,7 @@ func (s *state) GetFeeWindows() commonfees.Windows { return s.feesWindows } -func (s *state) SetConsumedUnitsWindows(windows commonfees.Windows) { +func (s *state) SetFeeWindows(windows commonfees.Windows) { s.feesWindows = windows } From 353883fd224b6cc7456c2d0ecff626a24033afa7 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Tue, 6 Feb 2024 13:21:20 +0100 Subject: [PATCH 107/190] fix merge --- vms/platformvm/txs/builder/builder.go | 116 +++--------------- .../txs/executor/staker_tx_verification.go | 1 + 2 files changed, 17 insertions(+), 100 deletions(-) diff --git a/vms/platformvm/txs/builder/builder.go b/vms/platformvm/txs/builder/builder.go index 8cea72fed1e7..492de17cdbdf 100644 --- a/vms/platformvm/txs/builder/builder.go +++ b/vms/platformvm/txs/builder/builder.go @@ -723,11 +723,17 @@ func (b *builder) NewAddValidatorTx( keys []*secp256k1.PrivateKey, changeAddr ids.ShortID, ) (*txs.Tx, error) { - // 1. Build core transaction without utxos + ins, unstakedOuts, stakedOuts, signers, err := b.Spend(b.state, keys, stakeAmount, b.cfg.AddPrimaryNetworkValidatorFee, changeAddr) + if err != nil { + return nil, fmt.Errorf("couldn't generate tx inputs/outputs: %w", err) + } + // Create the tx utx := &txs.AddValidatorTx{ BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ NetworkID: b.ctx.NetworkID, BlockchainID: b.ctx.ChainID, + Ins: ins, + Outs: unstakedOuts, }}, Validator: txs.Validator{ NodeID: nodeID, @@ -735,6 +741,7 @@ func (b *builder) NewAddValidatorTx( End: endTime, Wght: stakeAmount, }, + StakeOuts: stakedOuts, RewardsOwner: &secp256k1fx.OutputOwners{ Locktime: 0, Threshold: 1, @@ -742,55 +749,6 @@ func (b *builder) NewAddValidatorTx( }, DelegationShares: shares, } - - // 2. Finance the tx by building the utxos (inputs, outputs and stakes) - var ( - chainTime = b.state.GetTimestamp() - isEForkActive = b.cfg.IsEUpgradeActivated(chainTime) - ins []*avax.TransferableInput - outs []*avax.TransferableOutput - stakedOuts []*avax.TransferableOutput - signers [][]*secp256k1.PrivateKey - err error - ) - if isEForkActive { - var ( - unitFees = b.state.GetUnitFees() - unitWindows = b.state.GetFeeWindows() - unitCaps = config.EUpgradeDynamicFeesConfig.BlockUnitsCap - ) - - feeCalc := &fees.Calculator{ - IsEUpgradeActive: isEForkActive, - FeeManager: commonfees.NewManager(unitFees, unitWindows), - ConsumedUnitsCap: unitCaps, - Credentials: txs.EmptyCredentials(signers), - } - - // feesMan cumulates consumed units. Let's init it with utx filled so far - if err = feeCalc.AddValidatorTx(utx); err != nil { - return nil, err - } - - ins, outs, _, signers, err = b.FinanceTx( - b.state, - keys, - 0, - feeCalc, - changeAddr, - ) - } else { - ins, outs, stakedOuts, signers, err = b.Spend(b.state, keys, stakeAmount, b.cfg.AddPrimaryNetworkValidatorFee, changeAddr) - } - if err != nil { - return nil, fmt.Errorf("couldn't generate tx inputs/outputs: %w", err) - } - - utx.BaseTx.Ins = ins - utx.BaseTx.Outs = outs - utx.StakeOuts = stakedOuts - - // 3. Sign the tx tx, err := txs.NewSigned(utx, txs.Codec, signers) if err != nil { return nil, err @@ -900,11 +858,17 @@ func (b *builder) NewAddDelegatorTx( keys []*secp256k1.PrivateKey, changeAddr ids.ShortID, ) (*txs.Tx, error) { - // 1. Build core transaction without utxos + ins, unlockedOuts, lockedOuts, signers, err := b.Spend(b.state, keys, stakeAmount, b.cfg.AddPrimaryNetworkDelegatorFee, changeAddr) + if err != nil { + return nil, fmt.Errorf("couldn't generate tx inputs/outputs: %w", err) + } + // Create the tx utx := &txs.AddDelegatorTx{ BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ NetworkID: b.ctx.NetworkID, BlockchainID: b.ctx.ChainID, + Ins: ins, + Outs: unlockedOuts, }}, Validator: txs.Validator{ NodeID: nodeID, @@ -912,61 +876,13 @@ func (b *builder) NewAddDelegatorTx( End: endTime, Wght: stakeAmount, }, + StakeOuts: lockedOuts, DelegationRewardsOwner: &secp256k1fx.OutputOwners{ Locktime: 0, Threshold: 1, Addrs: []ids.ShortID{rewardAddress}, }, } - - // 2. Finance the tx by building the utxos (inputs, outputs and stakes) - var ( - chainTime = b.state.GetTimestamp() - isEForkActive = b.cfg.IsEUpgradeActivated(chainTime) - ins []*avax.TransferableInput - outs []*avax.TransferableOutput - stakedOuts []*avax.TransferableOutput - signers [][]*secp256k1.PrivateKey - err error - ) - if isEForkActive { - var ( - unitFees = b.state.GetUnitFees() - unitWindows = b.state.GetFeeWindows() - unitCaps = config.EUpgradeDynamicFeesConfig.BlockUnitsCap - ) - - feeCalc := &fees.Calculator{ - IsEUpgradeActive: isEForkActive, - FeeManager: commonfees.NewManager(unitFees, unitWindows), - ConsumedUnitsCap: unitCaps, - Credentials: txs.EmptyCredentials(signers), - } - - // feesMan cumulates consumed units. Let's init it with utx filled so far - if err = feeCalc.AddDelegatorTx(utx); err != nil { - return nil, err - } - - ins, outs, _, signers, err = b.FinanceTx( - b.state, - keys, - 0, - feeCalc, - changeAddr, - ) - } else { - ins, outs, stakedOuts, signers, err = b.Spend(b.state, keys, stakeAmount, b.cfg.AddPrimaryNetworkDelegatorFee, changeAddr) - } - if err != nil { - return nil, fmt.Errorf("couldn't generate tx inputs/outputs: %w", err) - } - - utx.BaseTx.Ins = ins - utx.BaseTx.Outs = outs - utx.StakeOuts = stakedOuts - - // 3. Sign the tx tx, err := txs.NewSigned(utx, txs.Codec, signers) if err != nil { return nil, err diff --git a/vms/platformvm/txs/executor/staker_tx_verification.go b/vms/platformvm/txs/executor/staker_tx_verification.go index dd8e6ea50d94..43f381772e26 100644 --- a/vms/platformvm/txs/executor/staker_tx_verification.go +++ b/vms/platformvm/txs/executor/staker_tx_verification.go @@ -793,6 +793,7 @@ func verifyAddPermissionlessDelegatorTx( return err } + // Verify the flowcheck if err := backend.FlowChecker.VerifySpend( tx, chainState, From be27aeb090cb7a581c51bfc0dc6049ed35df97ff Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Fri, 16 Feb 2024 14:32:38 +0100 Subject: [PATCH 108/190] fix fees getters --- vms/platformvm/block/builder/builder.go | 15 +- vms/platformvm/block/builder/helpers_test.go | 12 +- vms/platformvm/block/executor/helpers_test.go | 16 +- vms/platformvm/block/executor/manager.go | 16 +- .../block/executor/proposal_block_test.go | 4 + .../block/executor/standard_block_test.go | 6 +- vms/platformvm/block/executor/verifier.go | 11 +- .../block/executor/verifier_test.go | 7 + vms/platformvm/service.go | 10 +- vms/platformvm/service_test.go | 23 ++- vms/platformvm/state/diff.go | 58 +++++-- vms/platformvm/state/mock_state.go | 30 ++-- vms/platformvm/state/state.go | 12 +- vms/platformvm/txs/builder/builder.go | 163 +++++++++++++----- .../txs/executor/create_chain_test.go | 28 +-- vms/platformvm/txs/executor/helpers_test.go | 12 +- vms/platformvm/vm_test.go | 32 ++-- 17 files changed, 323 insertions(+), 132 deletions(-) diff --git a/vms/platformvm/block/builder/builder.go b/vms/platformvm/block/builder/builder.go index f7734deae70a..a448ede08924 100644 --- a/vms/platformvm/block/builder/builder.go +++ b/vms/platformvm/block/builder/builder.go @@ -349,11 +349,18 @@ func packBlockTxs( return nil, err } + unitFees, err := stateDiff.GetUnitFees() + if err != nil { + return nil, err + } + unitWindows, err := stateDiff.GetFeeWindows() + if err != nil { + return nil, err + } + var ( - feeCfg = backend.Config.GetDynamicFeesConfig(stateDiff.GetTimestamp()) - unitFees = stateDiff.GetUnitFees() - unitWindows = stateDiff.GetFeeWindows() - feeMan = fees.NewManager(unitFees, unitWindows) + feeCfg = backend.Config.GetDynamicFeesConfig(stateDiff.GetTimestamp()) + feeMan = fees.NewManager(unitFees, unitWindows) blockTxs []*txs.Tx inputs set.Set[ids.ID] diff --git a/vms/platformvm/block/builder/helpers_test.go b/vms/platformvm/block/builder/helpers_test.go index 4390343fb2bd..0abd81e01961 100644 --- a/vms/platformvm/block/builder/helpers_test.go +++ b/vms/platformvm/block/builder/helpers_test.go @@ -264,11 +264,13 @@ func addSubnet(t *testing.T, env *environment) { stateDiff, err := state.NewDiff(genesisID, env.blkManager) require.NoError(err) - var ( - unitFees = env.state.GetUnitFees() - unitWindows = env.state.GetFeeWindows() - feeCfg = env.config.GetDynamicFeesConfig(env.state.GetTimestamp()) - ) + unitFees, err := env.state.GetUnitFees() + require.NoError(err) + + unitWindows, err := env.state.GetFeeWindows() + require.NoError(err) + + feeCfg := env.config.GetDynamicFeesConfig(env.state.GetTimestamp()) executor := txexecutor.StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: fees.NewManager(unitFees, unitWindows), diff --git a/vms/platformvm/block/executor/helpers_test.go b/vms/platformvm/block/executor/helpers_test.go index ccc4e9030c25..03c19bc7da0f 100644 --- a/vms/platformvm/block/executor/helpers_test.go +++ b/vms/platformvm/block/executor/helpers_test.go @@ -283,11 +283,17 @@ func addSubnet(env *environment) { panic(err) } - var ( - unitFees = env.state.GetUnitFees() - unitWindows = env.state.GetFeeWindows() - feeCfg = env.config.GetDynamicFeesConfig(env.state.GetTimestamp()) - ) + unitFees, err := env.state.GetUnitFees() + if err != nil { + panic(err) + } + + unitWindows, err := env.state.GetFeeWindows() + if err != nil { + panic(err) + } + + feeCfg := env.config.GetDynamicFeesConfig(env.state.GetTimestamp()) executor := executor.StandardTxExecutor{ Backend: env.backend, BlkFeeManager: fees.NewManager(unitFees, unitWindows), diff --git a/vms/platformvm/block/executor/manager.go b/vms/platformvm/block/executor/manager.go index 2c0c428929b1..57e039274896 100644 --- a/vms/platformvm/block/executor/manager.go +++ b/vms/platformvm/block/executor/manager.go @@ -143,13 +143,19 @@ func (m *manager) VerifyTx(tx *txs.Tx) error { return err } + unitFees, err := stateDiff.GetUnitFees() + if err != nil { + return err + } + unitWindows, err := stateDiff.GetFeeWindows() + if err != nil { + return err + } + var ( - feesCfg = m.txExecutorBackend.Config.GetDynamicFeesConfig(stateDiff.GetTimestamp()) - unitFees = stateDiff.GetUnitFees() - unitWindows = stateDiff.GetFeeWindows() + feesCfg = m.txExecutorBackend.Config.GetDynamicFeesConfig(stateDiff.GetTimestamp()) + parentFeeManager = fees.NewManager(unitFees, unitWindows) ) - - parentFeeManager := fees.NewManager(unitFees, unitWindows) feeManager := parentFeeManager.ComputeNext( stateDiff.GetTimestamp().Unix(), nextBlkTime.Unix(), diff --git a/vms/platformvm/block/executor/proposal_block_test.go b/vms/platformvm/block/executor/proposal_block_test.go index 5086028687ab..7181631e9fc4 100644 --- a/vms/platformvm/block/executor/proposal_block_test.go +++ b/vms/platformvm/block/executor/proposal_block_test.go @@ -29,6 +29,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/secp256k1fx" + + commonfees "github.com/ava-labs/avalanchego/vms/components/fees" ) func TestApricotProposalBlockTimeVerification(t *testing.T) { @@ -162,6 +164,8 @@ func TestBanffProposalBlockTimeVerification(t *testing.T) { onParentAccept := state.NewMockDiff(ctrl) onParentAccept.EXPECT().GetTimestamp().Return(parentTime).AnyTimes() + onParentAccept.EXPECT().GetUnitFees().Return(commonfees.Empty, nil).Times(2) + onParentAccept.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows, nil).Times(2) 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 2d60d8e55703..cf775fedcf38 100644 --- a/vms/platformvm/block/executor/standard_block_test.go +++ b/vms/platformvm/block/executor/standard_block_test.go @@ -57,6 +57,8 @@ 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().GetUnitFees().Return(commonfees.Empty, nil).AnyTimes() + onParentAccept.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows, nil).AnyTimes() // wrong height apricotChildBlk, err := block.NewApricotStandardBlock( @@ -153,8 +155,8 @@ func TestBanffStandardBlockTimeVerification(t *testing.T) { } utxoID := utxo.InputID() onParentAccept.EXPECT().GetUTXO(utxoID).Return(utxo, nil).AnyTimes() - onParentAccept.EXPECT().GetUnitFees().Return(commonfees.Empty).AnyTimes() - onParentAccept.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows).AnyTimes() + onParentAccept.EXPECT().GetUnitFees().Return(commonfees.Empty, nil).AnyTimes() + onParentAccept.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows, 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 1339a536f5ec..a449198fbcf2 100644 --- a/vms/platformvm/block/executor/verifier.go +++ b/vms/platformvm/block/executor/verifier.go @@ -440,12 +440,19 @@ func (v *verifier) processStandardTxs(txs []*txs.Tx, state state.Diff, parentID func(), error, ) { + unitFees, err := state.GetUnitFees() + if err != nil { + return nil, nil, nil, err + } + unitWindows, err := state.GetFeeWindows() + if err != nil { + return nil, nil, nil, err + } + var ( currentTimestamp = state.GetTimestamp() isEForkActive = v.txExecutorBackend.Config.IsEUpgradeActivated(currentTimestamp) feesCfg = v.txExecutorBackend.Config.GetDynamicFeesConfig(currentTimestamp) - unitFees = state.GetUnitFees() - unitWindows = state.GetFeeWindows() onAcceptFunc func() inputs set.Set[ids.ID] diff --git a/vms/platformvm/block/executor/verifier_test.go b/vms/platformvm/block/executor/verifier_test.go index 1d77c50e6d12..23e613042434 100644 --- a/vms/platformvm/block/executor/verifier_test.go +++ b/vms/platformvm/block/executor/verifier_test.go @@ -26,6 +26,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/mempool" + + commonfees "github.com/ava-labs/avalanchego/vms/components/fees" ) func TestVerifierVisitProposalBlock(t *testing.T) { @@ -287,6 +289,8 @@ func TestVerifierVisitStandardBlock(t *testing.T) { // Set expectations for dependencies. timestamp := time.Now() parentState.EXPECT().GetTimestamp().Return(timestamp).Times(1) + parentState.EXPECT().GetUnitFees().Return(commonfees.Empty, nil) + parentState.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows, nil) parentStatelessBlk.EXPECT().Height().Return(uint64(1)).Times(1) mempool.EXPECT().Remove(apricotBlk.Txs()).Times(1) @@ -769,6 +773,9 @@ func TestVerifierVisitStandardBlockWithDuplicateInputs(t *testing.T) { timestamp := time.Now() parentStatelessBlk.EXPECT().Height().Return(uint64(1)).Times(1) parentState.EXPECT().GetTimestamp().Return(timestamp).Times(1) + parentState.EXPECT().GetUnitFees().Return(commonfees.Empty, nil) + parentState.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows, nil) + parentStatelessBlk.EXPECT().Parent().Return(grandParentID).Times(1) err = verifier.ApricotStandardBlock(blk) diff --git a/vms/platformvm/service.go b/vms/platformvm/service.go index 619e0d94b476..2bb1cdc9e88a 100644 --- a/vms/platformvm/service.go +++ b/vms/platformvm/service.go @@ -2900,8 +2900,9 @@ func (s *Service) GetUnitFees(_ *http.Request, _ *struct{}, reply *GetUnitFeesRe s.vm.ctx.Lock.Lock() defer s.vm.ctx.Lock.Unlock() - reply.UnitFees = s.vm.state.GetUnitFees() - return nil + var err error + reply.UnitFees, err = s.vm.state.GetUnitFees() + return err } // GetBlockUnitsCapReply is the response from GetBlockUnitsCap @@ -2920,8 +2921,9 @@ func (s *Service) GetFeeWindows(_ *http.Request, _ *struct{}, reply *GetFeeWindo s.vm.ctx.Lock.Lock() defer s.vm.ctx.Lock.Unlock() - reply.FeeWindows = s.vm.state.GetFeeWindows() - return nil + var err error + reply.FeeWindows, err = s.vm.state.GetFeeWindows() + return err } func (s *Service) getAPIUptime(staker *state.Staker) (*avajson.Float32, error) { diff --git a/vms/platformvm/service_test.go b/vms/platformvm/service_test.go index f6cf1a515dd7..ba6ff24b9a74 100644 --- a/vms/platformvm/service_test.go +++ b/vms/platformvm/service_test.go @@ -394,13 +394,17 @@ 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 + unitFees, err := service.vm.state.GetUnitFees() + require.NoError(err) + + feeWindows, err := service.vm.state.GetFeeWindows() + require.NoError(err) + var ( - chainTime = service.vm.state.GetTimestamp() - feeCfg = service.vm.Config.GetDynamicFeesConfig(chainTime) - unitFees = service.vm.state.GetUnitFees() - feeWindows = service.vm.state.GetFeeWindows() - feeMan = commonfees.NewManager(unitFees, feeWindows) - feeCalc = &fees.Calculator{ + chainTime = service.vm.state.GetTimestamp() + feeCfg = service.vm.Config.GetDynamicFeesConfig(chainTime) + feeMan = commonfees.NewManager(unitFees, feeWindows) + feeCalc = &fees.Calculator{ IsEUpgradeActive: service.vm.IsEUpgradeActivated(chainTime), Config: &service.vm.Config, ChainTime: chainTime, @@ -1055,8 +1059,8 @@ func TestGetUnitFees(t *testing.T) { service.vm.ctx.Lock.Lock() - unitFees := service.vm.state.GetUnitFees() - + unitFees, err := service.vm.state.GetUnitFees() + require.NoError(err) require.Equal(unitFees, reply.UnitFees) updatedUnitFees := commonfees.Dimensions{ @@ -1082,7 +1086,8 @@ func TestGetFeeWindows(t *testing.T) { service.vm.ctx.Lock.Lock() - feeWindows := service.vm.state.GetFeeWindows() + feeWindows, err := service.vm.state.GetFeeWindows() + require.NoError(err) require.Equal(feeWindows, reply.FeeWindows) updatedFeeWindows := commonfees.Windows{ diff --git a/vms/platformvm/state/diff.go b/vms/platformvm/state/diff.go index c54ceb416c29..e0f43371c2a1 100644 --- a/vms/platformvm/state/diff.go +++ b/vms/platformvm/state/diff.go @@ -37,8 +37,8 @@ type diff struct { timestamp time.Time - unitFees commonfees.Dimensions - consumedUnitsWindows commonfees.Windows + unitFees *commonfees.Dimensions + feesWindows *commonfees.Windows // Subnet ID --> supply of native asset of the subnet currentSupply map[ids.ID]uint64 @@ -94,20 +94,54 @@ func NewDiffOn(parentState Chain) (Diff, error) { }) } -func (d *diff) GetUnitFees() commonfees.Dimensions { - return d.unitFees +func (d *diff) GetUnitFees() (commonfees.Dimensions, error) { + if d.unitFees == nil { + parentState, ok := d.stateVersions.GetState(d.parentID) + if !ok { + return commonfees.Empty, fmt.Errorf("%w: %s", ErrMissingParentState, d.parentID) + } + parentUnitFees, err := parentState.GetUnitFees() + if err != nil { + return commonfees.Empty, err + } + + d.unitFees = new(commonfees.Dimensions) + *d.unitFees = parentUnitFees + } + + return *d.unitFees, nil } func (d *diff) SetUnitFees(uf commonfees.Dimensions) { - d.unitFees = uf + if d.unitFees == nil { + d.unitFees = new(commonfees.Dimensions) + } + *d.unitFees = uf } -func (d *diff) GetFeeWindows() commonfees.Windows { - return d.consumedUnitsWindows +func (d *diff) GetFeeWindows() (commonfees.Windows, error) { + if d.feesWindows == nil { + parentState, ok := d.stateVersions.GetState(d.parentID) + if !ok { + return commonfees.EmptyWindows, fmt.Errorf("%w: %s", ErrMissingParentState, d.parentID) + } + parentFeeWindows, err := parentState.GetFeeWindows() + if err != nil { + return commonfees.EmptyWindows, err + } + + d.feesWindows = new(commonfees.Windows) + *d.feesWindows = parentFeeWindows + } + + return *d.feesWindows, nil } func (d *diff) SetFeeWindows(windows commonfees.Windows) { - d.consumedUnitsWindows = windows + if d.feesWindows == nil { + d.feesWindows = new(commonfees.Windows) + } + *d.feesWindows = windows } func (d *diff) GetTimestamp() time.Time { @@ -422,8 +456,12 @@ func (d *diff) DeleteUTXO(utxoID ids.ID) { func (d *diff) Apply(baseState Chain) error { baseState.SetTimestamp(d.timestamp) - baseState.SetUnitFees(d.unitFees) - baseState.SetFeeWindows(d.consumedUnitsWindows) + if d.unitFees != nil { + baseState.SetUnitFees(*d.unitFees) + } + if d.feesWindows != nil { + baseState.SetFeeWindows(*d.feesWindows) + } 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 a0f27194bc54..2803d8e5ed26 100644 --- a/vms/platformvm/state/mock_state.go +++ b/vms/platformvm/state/mock_state.go @@ -259,11 +259,12 @@ func (mr *MockChainMockRecorder) GetDelegateeReward(arg0, arg1 any) *gomock.Call } // GetFeeWindows mocks base method. -func (m *MockChain) GetFeeWindows() fees.Windows { +func (m *MockChain) GetFeeWindows() (fees.Windows, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetFeeWindows") ret0, _ := ret[0].(fees.Windows) - return ret0 + ret1, _ := ret[1].(error) + return ret0, ret1 } // GetFeeWindows indicates an expected call of GetFeeWindows. @@ -393,11 +394,12 @@ func (mr *MockChainMockRecorder) GetUTXO(arg0 any) *gomock.Call { } // GetUnitFees mocks base method. -func (m *MockChain) GetUnitFees() fees.Dimensions { +func (m *MockChain) GetUnitFees() (fees.Dimensions, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetUnitFees") ret0, _ := ret[0].(fees.Dimensions) - return ret0 + ret1, _ := ret[1].(error) + return ret0, ret1 } // GetUnitFees indicates an expected call of GetUnitFees. @@ -773,11 +775,12 @@ func (mr *MockDiffMockRecorder) GetDelegateeReward(arg0, arg1 any) *gomock.Call } // GetFeeWindows mocks base method. -func (m *MockDiff) GetFeeWindows() fees.Windows { +func (m *MockDiff) GetFeeWindows() (fees.Windows, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetFeeWindows") ret0, _ := ret[0].(fees.Windows) - return ret0 + ret1, _ := ret[1].(error) + return ret0, ret1 } // GetFeeWindows indicates an expected call of GetFeeWindows. @@ -907,11 +910,12 @@ func (mr *MockDiffMockRecorder) GetUTXO(arg0 any) *gomock.Call { } // GetUnitFees mocks base method. -func (m *MockDiff) GetUnitFees() fees.Dimensions { +func (m *MockDiff) GetUnitFees() (fees.Dimensions, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetUnitFees") ret0, _ := ret[0].(fees.Dimensions) - return ret0 + ret1, _ := ret[1].(error) + return ret0, ret1 } // GetUnitFees indicates an expected call of GetUnitFees. @@ -1412,11 +1416,12 @@ func (mr *MockStateMockRecorder) GetDelegateeReward(arg0, arg1 any) *gomock.Call } // GetFeeWindows mocks base method. -func (m *MockState) GetFeeWindows() fees.Windows { +func (m *MockState) GetFeeWindows() (fees.Windows, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetFeeWindows") ret0, _ := ret[0].(fees.Windows) - return ret0 + ret1, _ := ret[1].(error) + return ret0, ret1 } // GetFeeWindows indicates an expected call of GetFeeWindows. @@ -1620,11 +1625,12 @@ func (mr *MockStateMockRecorder) GetUTXO(arg0 any) *gomock.Call { } // GetUnitFees mocks base method. -func (m *MockState) GetUnitFees() fees.Dimensions { +func (m *MockState) GetUnitFees() (fees.Dimensions, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetUnitFees") ret0, _ := ret[0].(fees.Dimensions) - return ret0 + ret1, _ := ret[1].(error) + return ret0, ret1 } // GetUnitFees indicates an expected call of GetUnitFees. diff --git a/vms/platformvm/state/state.go b/vms/platformvm/state/state.go index 0871388a6eda..e84b2becc461 100644 --- a/vms/platformvm/state/state.go +++ b/vms/platformvm/state/state.go @@ -101,10 +101,10 @@ type Chain interface { avax.UTXOGetter avax.UTXODeleter - GetUnitFees() commonfees.Dimensions + GetUnitFees() (commonfees.Dimensions, error) SetUnitFees(uf commonfees.Dimensions) - GetFeeWindows() commonfees.Windows + GetFeeWindows() (commonfees.Windows, error) SetFeeWindows(windows commonfees.Windows) GetTimestamp() time.Time @@ -1086,16 +1086,16 @@ func (s *state) GetStartTime(nodeID ids.NodeID, subnetID ids.ID) (time.Time, err return staker.StartTime, nil } -func (s *state) GetUnitFees() commonfees.Dimensions { - return s.unitFees +func (s *state) GetUnitFees() (commonfees.Dimensions, error) { + return s.unitFees, nil } func (s *state) SetUnitFees(uf commonfees.Dimensions) { s.unitFees = uf } -func (s *state) GetFeeWindows() commonfees.Windows { - return s.feesWindows +func (s *state) GetFeeWindows() (commonfees.Windows, error) { + return s.feesWindows, nil } func (s *state) SetFeeWindows(windows commonfees.Windows) { diff --git a/vms/platformvm/txs/builder/builder.go b/vms/platformvm/txs/builder/builder.go index c3a72871ed01..43265c440f0d 100644 --- a/vms/platformvm/txs/builder/builder.go +++ b/vms/platformvm/txs/builder/builder.go @@ -373,15 +373,21 @@ func (b *builder) NewImportTx( delete(importedAmounts, assetID) } + unitFees, err := b.state.GetUnitFees() + if err != nil { + return nil, err + } + unitWindows, err := b.state.GetFeeWindows() + if err != nil { + return nil, err + } var ( importedAVAX = importedAmounts[b.ctx.AVAXAssetID] // the only entry left in importedAmounts chainTime = b.state.GetTimestamp() feeCfg = b.cfg.GetDynamicFeesConfig(chainTime) isEUpgradeActive = b.cfg.IsEUpgradeActivated(chainTime) - unitFees = b.state.GetUnitFees() - unitWindows = b.state.GetFeeWindows() - feeCalc = &fees.Calculator{ + feeCalc = &fees.Calculator{ IsEUpgradeActive: isEUpgradeActive, Config: b.cfg, ChainTime: chainTime, @@ -505,14 +511,20 @@ func (b *builder) NewExportTx( } // 2. Finance the tx by building the utxos (inputs, outputs and stakes) + unitFees, err := b.state.GetUnitFees() + if err != nil { + return nil, err + } + unitWindows, err := b.state.GetFeeWindows() + if err != nil { + return nil, err + } + var ( chainTime = b.state.GetTimestamp() isEUpgradeActive = b.cfg.IsEUpgradeActivated(chainTime) feeCfg = b.cfg.GetDynamicFeesConfig(chainTime) - unitFees = b.state.GetUnitFees() - unitWindows = b.state.GetFeeWindows() - feeCalc = &fees.Calculator{ IsEUpgradeActive: isEUpgradeActive, Config: b.cfg, @@ -583,14 +595,21 @@ func (b *builder) NewCreateChainTx( } // 2. Finance the tx by building the utxos (inputs, outputs and stakes) + unitFees, err := b.state.GetUnitFees() + if err != nil { + return nil, err + } + unitWindows, err := b.state.GetFeeWindows() + if err != nil { + return nil, err + } + var ( chainTime = b.state.GetTimestamp() feeCfg = b.cfg.GetDynamicFeesConfig(chainTime) isEUpgradeActive = b.cfg.IsEUpgradeActivated(chainTime) - unitFees = b.state.GetUnitFees() - unitWindows = b.state.GetFeeWindows() - feeCalc = &fees.Calculator{ + feeCalc = &fees.Calculator{ IsEUpgradeActive: isEUpgradeActive, Config: b.cfg, ChainTime: chainTime, @@ -655,14 +674,20 @@ func (b *builder) NewCreateSubnetTx( } // 2. Finance the tx by building the utxos (inputs, outputs and stakes) + unitFees, err := b.state.GetUnitFees() + if err != nil { + return nil, err + } + unitWindows, err := b.state.GetFeeWindows() + if err != nil { + return nil, err + } + var ( chainTime = b.state.GetTimestamp() isEUpgradeActive = b.cfg.IsEUpgradeActivated(chainTime) feeCfg = b.cfg.GetDynamicFeesConfig(chainTime) - unitFees = b.state.GetUnitFees() - unitWindows = b.state.GetFeeWindows() - feeCalc = &fees.Calculator{ IsEUpgradeActive: isEUpgradeActive, Config: b.cfg, @@ -750,14 +775,21 @@ func (b *builder) NewTransformSubnetTx( } // 2. Finance the tx by building the utxos (inputs, outputs and stakes) + unitFees, err := b.state.GetUnitFees() + if err != nil { + return nil, err + } + unitWindows, err := b.state.GetFeeWindows() + if err != nil { + return nil, err + } + var ( chainTime = b.state.GetTimestamp() feeCfg = b.cfg.GetDynamicFeesConfig(chainTime) isEUpgradeActive = b.cfg.IsEUpgradeActivated(chainTime) - unitFees = b.state.GetUnitFees() - unitWindows = b.state.GetFeeWindows() - feeCalc = &fees.Calculator{ + feeCalc = &fees.Calculator{ IsEUpgradeActive: isEUpgradeActive, Config: b.cfg, ChainTime: chainTime, @@ -833,14 +865,21 @@ func (b *builder) NewAddValidatorTx( } // 2. Finance the tx by building the utxos (inputs, outputs and stakes) + unitFees, err := b.state.GetUnitFees() + if err != nil { + return nil, err + } + unitWindows, err := b.state.GetFeeWindows() + if err != nil { + return nil, err + } + var ( chainTime = b.state.GetTimestamp() feeCfg = b.cfg.GetDynamicFeesConfig(chainTime) isEUpgradeActive = b.cfg.IsEUpgradeActivated(chainTime) - unitFees = b.state.GetUnitFees() - unitWindows = b.state.GetFeeWindows() - feeCalc = &fees.Calculator{ + feeCalc = &fees.Calculator{ IsEUpgradeActive: isEUpgradeActive, Config: b.cfg, ChainTime: chainTime, @@ -918,14 +957,20 @@ func (b *builder) NewAddPermissionlessValidatorTx( } // 2. Finance the tx by building the utxos (inputs, outputs and stakes) + unitFees, err := b.state.GetUnitFees() + if err != nil { + return nil, err + } + unitWindows, err := b.state.GetFeeWindows() + if err != nil { + return nil, err + } + var ( chainTime = b.state.GetTimestamp() isEUpgradeActive = b.cfg.IsEUpgradeActivated(chainTime) feeCfg = b.cfg.GetDynamicFeesConfig(chainTime) - unitFees = b.state.GetUnitFees() - unitWindows = b.state.GetFeeWindows() - feeCalc = &fees.Calculator{ IsEUpgradeActive: isEUpgradeActive, Config: b.cfg, @@ -994,14 +1039,20 @@ func (b *builder) NewAddDelegatorTx( } // 2. Finance the tx by building the utxos (inputs, outputs and stakes) + unitFees, err := b.state.GetUnitFees() + if err != nil { + return nil, err + } + unitWindows, err := b.state.GetFeeWindows() + if err != nil { + return nil, err + } + var ( chainTime = b.state.GetTimestamp() feeCfg = b.cfg.GetDynamicFeesConfig(chainTime) isEUpgradeActive = b.cfg.IsEUpgradeActivated(chainTime) - unitFees = b.state.GetUnitFees() - unitWindows = b.state.GetFeeWindows() - feeCalc = &fees.Calculator{ IsEUpgradeActive: isEUpgradeActive, Config: b.cfg, @@ -1073,14 +1124,20 @@ func (b *builder) NewAddPermissionlessDelegatorTx( } // 2. Finance the tx by building the utxos (inputs, outputs and stakes) + unitFees, err := b.state.GetUnitFees() + if err != nil { + return nil, err + } + unitWindows, err := b.state.GetFeeWindows() + if err != nil { + return nil, err + } + var ( chainTime = b.state.GetTimestamp() isEUpgradeActive = b.cfg.IsEUpgradeActivated(chainTime) feeCfg = b.cfg.GetDynamicFeesConfig(chainTime) - unitFees = b.state.GetUnitFees() - unitWindows = b.state.GetFeeWindows() - feeCalc = &fees.Calculator{ IsEUpgradeActive: isEUpgradeActive, Config: b.cfg, @@ -1152,14 +1209,21 @@ func (b *builder) NewAddSubnetValidatorTx( } // 2. Finance the tx by building the utxos (inputs, outputs and stakes) + unitFees, err := b.state.GetUnitFees() + if err != nil { + return nil, err + } + unitWindows, err := b.state.GetFeeWindows() + if err != nil { + return nil, err + } + var ( chainTime = b.state.GetTimestamp() isEUpgradeActive = b.cfg.IsEUpgradeActivated(chainTime) feeCfg = b.cfg.GetDynamicFeesConfig(chainTime) - unitFees = b.state.GetUnitFees() - unitWindows = b.state.GetFeeWindows() - feeCalc = &fees.Calculator{ + feeCalc = &fees.Calculator{ IsEUpgradeActive: isEUpgradeActive, Config: b.cfg, ChainTime: chainTime, @@ -1227,14 +1291,21 @@ func (b *builder) NewRemoveSubnetValidatorTx( } // 2. Finance the tx by building the utxos (inputs, outputs and stakes) + unitFees, err := b.state.GetUnitFees() + if err != nil { + return nil, err + } + unitWindows, err := b.state.GetFeeWindows() + if err != nil { + return nil, err + } + var ( chainTime = b.state.GetTimestamp() isEUpgradeActive = b.cfg.IsEUpgradeActivated(chainTime) feeCfg = b.cfg.GetDynamicFeesConfig(chainTime) - unitFees = b.state.GetUnitFees() - unitWindows = b.state.GetFeeWindows() - feeCalc = &fees.Calculator{ + feeCalc = &fees.Calculator{ IsEUpgradeActive: isEUpgradeActive, Config: b.cfg, ChainTime: chainTime, @@ -1306,14 +1377,21 @@ func (b *builder) NewTransferSubnetOwnershipTx( } // 2. Finance the tx by building the utxos (inputs, outputs and stakes) + unitFees, err := b.state.GetUnitFees() + if err != nil { + return nil, err + } + unitWindows, err := b.state.GetFeeWindows() + if err != nil { + return nil, err + } + var ( chainTime = b.state.GetTimestamp() isEUpgradeActive = b.cfg.IsEUpgradeActivated(chainTime) feeCfg = b.cfg.GetDynamicFeesConfig(chainTime) - unitFees = b.state.GetUnitFees() - unitWindows = b.state.GetFeeWindows() - feeCalc = &fees.Calculator{ + feeCalc = &fees.Calculator{ IsEUpgradeActive: isEUpgradeActive, Config: b.cfg, ChainTime: chainTime, @@ -1379,14 +1457,21 @@ func (b *builder) NewBaseTx( } // 2. Finance the tx by building the utxos (inputs, outputs and stakes) + unitFees, err := b.state.GetUnitFees() + if err != nil { + return nil, err + } + unitWindows, err := b.state.GetFeeWindows() + if err != nil { + return nil, err + } + var ( chainTime = b.state.GetTimestamp() isEUpgradeActive = b.cfg.IsEUpgradeActivated(chainTime) feeCfg = b.cfg.GetDynamicFeesConfig(chainTime) - unitFees = b.state.GetUnitFees() - unitWindows = b.state.GetFeeWindows() - feeCalc = &fees.Calculator{ + feeCalc = &fees.Calculator{ IsEUpgradeActive: isEUpgradeActive, Config: b.cfg, ChainTime: chainTime, diff --git a/vms/platformvm/txs/executor/create_chain_test.go b/vms/platformvm/txs/executor/create_chain_test.go index f1ab114fbbb8..4d66dc7718f2 100644 --- a/vms/platformvm/txs/executor/create_chain_test.go +++ b/vms/platformvm/txs/executor/create_chain_test.go @@ -130,14 +130,16 @@ func TestCreateChainTxNoSuchSubnet(t *testing.T) { stateDiff, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - var ( - feeCfg = env.config.GetDynamicFeesConfig(stateDiff.GetTimestamp()) - unitFees = env.state.GetUnitFees() - feeWindows = env.state.GetFeeWindows() - ) + unitFees, err := env.state.GetUnitFees() + require.NoError(err) + + unitWindows, err := env.state.GetFeeWindows() + require.NoError(err) + + feeCfg := env.config.GetDynamicFeesConfig(stateDiff.GetTimestamp()) executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(unitFees, feeWindows), + BlkFeeManager: commonfees.NewManager(unitFees, unitWindows), UnitCaps: feeCfg.BlockUnitsCap, State: stateDiff, Tx: tx, @@ -168,14 +170,16 @@ func TestCreateChainTxValid(t *testing.T) { stateDiff, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - var ( - feeCfg = env.config.GetDynamicFeesConfig(stateDiff.GetTimestamp()) - unitFees = env.state.GetUnitFees() - feeWindows = env.state.GetFeeWindows() - ) + unitFees, err := env.state.GetUnitFees() + require.NoError(err) + + unitWindows, err := env.state.GetFeeWindows() + require.NoError(err) + + feeCfg := env.config.GetDynamicFeesConfig(stateDiff.GetTimestamp()) executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(unitFees, feeWindows), + BlkFeeManager: commonfees.NewManager(unitFees, unitWindows), UnitCaps: feeCfg.BlockUnitsCap, State: stateDiff, Tx: tx, diff --git a/vms/platformvm/txs/executor/helpers_test.go b/vms/platformvm/txs/executor/helpers_test.go index 847a72ba4888..fc41388ea3f3 100644 --- a/vms/platformvm/txs/executor/helpers_test.go +++ b/vms/platformvm/txs/executor/helpers_test.go @@ -238,11 +238,13 @@ func addSubnet( stateDiff, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - var ( - unitFees = env.state.GetUnitFees() - unitWindows = env.state.GetFeeWindows() - feeCfg = env.config.GetDynamicFeesConfig(env.state.GetTimestamp()) - ) + unitFees, err := env.state.GetUnitFees() + require.NoError(err) + + unitWindows, err := env.state.GetFeeWindows() + require.NoError(err) + + feeCfg := env.config.GetDynamicFeesConfig(env.state.GetTimestamp()) executor := StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: fees.NewManager(unitFees, unitWindows), diff --git a/vms/platformvm/vm_test.go b/vms/platformvm/vm_test.go index e53a40630bcf..a270f7a82a4b 100644 --- a/vms/platformvm/vm_test.go +++ b/vms/platformvm/vm_test.go @@ -373,15 +373,19 @@ func TestGenesis(t *testing.T) { require.Equal(utxo.Address, addr) + unitFees, err := vm.state.GetUnitFees() + require.NoError(err) + + feeWindows, err := vm.state.GetFeeWindows() + require.NoError(err) + // we use the first key to fund a subnet creation in [defaultGenesis]. // As such we need to account for the subnet creation fee var ( - chainTime = vm.state.GetTimestamp() - feeCfg = vm.Config.GetDynamicFeesConfig(chainTime) - unitFees = vm.state.GetUnitFees() - feeWindows = vm.state.GetFeeWindows() - feeMan = commonfees.NewManager(unitFees, feeWindows) - feeCalc = &fees.Calculator{ + chainTime = vm.state.GetTimestamp() + feeCfg = vm.Config.GetDynamicFeesConfig(chainTime) + feeMan = commonfees.NewManager(unitFees, feeWindows) + feeCalc = &fees.Calculator{ IsEUpgradeActive: vm.IsEUpgradeActivated(chainTime), Config: &vm.Config, ChainTime: chainTime, @@ -2273,13 +2277,17 @@ func TestBaseTx(t *testing.T) { } require.Equal(totalOutputAmt, key0OutputAmt+key1OutputAmt+changeAddrOutputAmt) + unitFees, err := vm.state.GetUnitFees() + require.NoError(err) + + feeWindows, err := vm.state.GetFeeWindows() + require.NoError(err) + var ( - chainTime = vm.state.GetTimestamp() - feeCfg = vm.Config.GetDynamicFeesConfig(chainTime) - unitFees = vm.state.GetUnitFees() - feeWindows = vm.state.GetFeeWindows() - feeMan = commonfees.NewManager(unitFees, feeWindows) - feeCalc = &fees.Calculator{ + chainTime = vm.state.GetTimestamp() + feeCfg = vm.Config.GetDynamicFeesConfig(chainTime) + feeMan = commonfees.NewManager(unitFees, feeWindows) + feeCalc = &fees.Calculator{ IsEUpgradeActive: vm.IsEUpgradeActivated(chainTime), Config: &vm.Config, ChainTime: chainTime, From 0704b2e8faad6e9d85ae978e43555b25d118e73f Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Sun, 18 Feb 2024 15:19:25 +0100 Subject: [PATCH 109/190] nit --- wallet/chain/p/{builder_fees_test.go => builder_test.go} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename wallet/chain/p/{builder_fees_test.go => builder_test.go} (100%) diff --git a/wallet/chain/p/builder_fees_test.go b/wallet/chain/p/builder_test.go similarity index 100% rename from wallet/chain/p/builder_fees_test.go rename to wallet/chain/p/builder_test.go From ecfe65aad416829c729b80913084047cb90668ad Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 29 Feb 2024 10:19:27 +0100 Subject: [PATCH 110/190] fixed changedDenom handling --- vms/components/fees/manager.go | 14 ++++++++++---- vms/components/fees/manager_test.go | 8 ++++---- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/vms/components/fees/manager.go b/vms/components/fees/manager.go index 9347a8cd797f..10f06bbde1b7 100644 --- a/vms/components/fees/manager.go +++ b/vms/components/fees/manager.go @@ -155,8 +155,11 @@ func computeNextPriceWindow( return nextUnitFee, newRollupWindow case totalUnitsConsumed > target: // If the parent block used more units than its target, the baseFee should increase. - rawDelta := currentUnitFee * (totalUnitsConsumed - target) / target - delta := max(rawDelta/changeDenom, 1) * changeDenom // price must change in increments on changeDenom + delta := currentUnitFee * (totalUnitsConsumed - target) / target / changeDenom + + // make sure that delta is non zero. We want to move unit fees + // of at least a unit (they should not stay the same since totalUnitsConsumed > target) + delta = max(delta, 1) var over error nextUnitFee, over = safemath.Add64(nextUnitFee, delta) @@ -166,8 +169,11 @@ func computeNextPriceWindow( case totalUnitsConsumed < target: // Otherwise if the parent block used less units than its target, the baseFee should decrease. - rawDelta := currentUnitFee * (target - totalUnitsConsumed) / target - delta := max(rawDelta/changeDenom, 1) * changeDenom // price must change in increments on changeDenom + delta := currentUnitFee * (target - totalUnitsConsumed) / target / changeDenom + + // make sure that delta is non zero. We want to move unit fees + // of at least a unit (they should not stay the same since totalUnitsConsumed < target) + delta = max(delta, 1) // if we had no blocks for more than [WindowSize] seconds, we reduce fees even more, // to try and account for all the low activity interval diff --git a/vms/components/fees/manager_test.go b/vms/components/fees/manager_test.go index 6c963f8ffd45..1dc9d632da08 100644 --- a/vms/components/fees/manager_test.go +++ b/vms/components/fees/manager_test.go @@ -47,10 +47,10 @@ func TestComputeNextEmptyWindows(t *testing.T) { require.Equal(initialUnitFees[UTXORead], next.unitFees[UTXORead]) // UTXOWrite units are above target, next unit fees increased, proportionally to priceChangeDenominator - require.Equal(initialUnitFees[UTXOWrite]+priceChangeDenominator[UTXOWrite], next.unitFees[UTXOWrite]) + require.Equal(initialUnitFees[UTXOWrite]+1, next.unitFees[UTXOWrite]) // Compute units are above target, next unit fees increased, proportionally to priceChangeDenominator - require.Equal(initialUnitFees[Compute]+9*priceChangeDenominator[Compute], next.unitFees[Compute]) + require.Equal(initialUnitFees[Compute]+9, next.unitFees[Compute]) // next cumulated units are zeroed require.Equal(Dimensions{}, next.cumulatedUnits) @@ -97,10 +97,10 @@ func TestComputeNextNonEmptyWindows(t *testing.T) { require.Equal(uint64(737869762948382064), next.unitFees[UTXORead]) // UTXOWrite units are above target, even if they are decreasing within the window. Next unit fees increased. - require.Equal(initialUnitFees[UTXOWrite]+4*priceChangeDenominator[UTXOWrite], next.unitFees[UTXOWrite]) + require.Equal(initialUnitFees[UTXOWrite]+4, next.unitFees[UTXOWrite]) // Compute units are above target, next unit fees increased, proportionally to priceChangeDenominator - require.Equal(uint64(737869762948382061), next.unitFees[Compute]) + require.Equal(uint64(73786976294838207), next.unitFees[Compute]) // next cumulated units are zeroed require.Equal(Dimensions{}, next.cumulatedUnits) From bbc92f131656023bf645bb1a6290475070354250 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Sat, 9 Mar 2024 22:36:40 +0100 Subject: [PATCH 111/190] fee rates exponential updates --- vms/components/fees/manager.go | 47 +++++--------------- vms/components/fees/manager_test.go | 26 +++++------ vms/platformvm/block/executor/manager.go | 2 +- vms/platformvm/block/executor/verifier.go | 2 +- vms/platformvm/config/dynamic_fees_config.go | 20 ++++----- 5 files changed, 35 insertions(+), 62 deletions(-) diff --git a/vms/components/fees/manager.go b/vms/components/fees/manager.go index 10f06bbde1b7..3cc033b83d34 100644 --- a/vms/components/fees/manager.go +++ b/vms/components/fees/manager.go @@ -104,7 +104,7 @@ func (m *Manager) ComputeNext( lastTime, currTime int64, targetUnits, - priceChangeDenominator, + updateCoefficients, minUnitPrice Dimensions, ) *Manager { since := int(currTime - lastTime) @@ -115,7 +115,7 @@ func (m *Manager) ComputeNext( m.cumulatedUnits[i], m.unitFees[i], targetUnits[i], - priceChangeDenominator[i], + updateCoefficients[i], minUnitPrice[i], since, ) @@ -132,7 +132,7 @@ func computeNextPriceWindow( currentUnitsConsumed uint64, currentUnitFee uint64, target uint64, /* per window, must be non-zero */ - changeDenom uint64, + updateCoefficient uint64, minUnitFee uint64, since int, /* seconds */ ) (uint64, Window) { @@ -147,47 +147,24 @@ func computeNextPriceWindow( var ( totalUnitsConsumed = Sum(newRollupWindow) - nextUnitFee = currentUnitFee + exponent = float64(0) ) switch { case totalUnitsConsumed == target: - return nextUnitFee, newRollupWindow + return currentUnitFee, newRollupWindow case totalUnitsConsumed > target: - // If the parent block used more units than its target, the baseFee should increase. - delta := currentUnitFee * (totalUnitsConsumed - target) / target / changeDenom - - // make sure that delta is non zero. We want to move unit fees - // of at least a unit (they should not stay the same since totalUnitsConsumed > target) - delta = max(delta, 1) - - var over error - nextUnitFee, over = safemath.Add64(nextUnitFee, delta) - if over != nil { - nextUnitFee = math.MaxUint64 - } - + exponent = float64(updateCoefficient) * float64(totalUnitsConsumed-target) / float64(target) case totalUnitsConsumed < target: - // Otherwise if the parent block used less units than its target, the baseFee should decrease. - delta := currentUnitFee * (target - totalUnitsConsumed) / target / changeDenom - - // make sure that delta is non zero. We want to move unit fees - // of at least a unit (they should not stay the same since totalUnitsConsumed < target) - delta = max(delta, 1) - - // if we had no blocks for more than [WindowSize] seconds, we reduce fees even more, - // to try and account for all the low activity interval - if since > WindowSize { - delta *= uint64(since / WindowSize) - } + exponent = -float64(updateCoefficient) * float64(target-totalUnitsConsumed) / float64(target) + } - var under error - nextUnitFee, under = safemath.Sub(nextUnitFee, delta) - if under != nil { - nextUnitFee = 0 - } + nextRawRate := math.Round(float64(currentUnitFee) * math.Exp(exponent)) + if nextRawRate > math.MaxUint64 { + return math.MaxUint64, newRollupWindow } + nextUnitFee := uint64(nextRawRate) nextUnitFee = max(nextUnitFee, minUnitFee) return nextUnitFee, newRollupWindow } diff --git a/vms/components/fees/manager_test.go b/vms/components/fees/manager_test.go index 1dc9d632da08..95bd7ebfb73c 100644 --- a/vms/components/fees/manager_test.go +++ b/vms/components/fees/manager_test.go @@ -23,7 +23,7 @@ func TestComputeNextEmptyWindows(t *testing.T) { lastBlkTime = time.Now().Truncate(time.Second) currBlkTime = lastBlkTime.Add(time.Second) - priceChangeDenominator = Dimensions{1, 1, 2, 10} + priceChangeDenominator = Dimensions{0, 1, 2, 10} minUnitFees = Dimensions{0, 0, 0, 0} ) @@ -41,16 +41,16 @@ func TestComputeNextEmptyWindows(t *testing.T) { ) // Bandwidth units are below target, next unit fees are pushed to the minimum - require.Equal(minUnitFees[Bandwidth], next.unitFees[Bandwidth]) + require.Equal(minUnitFees[Bandwidth]+1, next.unitFees[Bandwidth]) // UTXORead units are at target, next unit fees are kept equal require.Equal(initialUnitFees[UTXORead], next.unitFees[UTXORead]) // UTXOWrite units are above target, next unit fees increased, proportionally to priceChangeDenominator - require.Equal(initialUnitFees[UTXOWrite]+1, next.unitFees[UTXOWrite]) + require.Equal(uint64(1), next.unitFees[UTXOWrite]) // Compute units are above target, next unit fees increased, proportionally to priceChangeDenominator - require.Equal(initialUnitFees[Compute]+9, next.unitFees[Compute]) + require.Equal(uint64(math.MaxUint64), next.unitFees[Compute]) // next cumulated units are zeroed require.Equal(Dimensions{}, next.cumulatedUnits) @@ -68,8 +68,8 @@ func TestComputeNextNonEmptyWindows(t *testing.T) { lastBlkTime = time.Now().Truncate(time.Second) currBlkTime = lastBlkTime.Add(time.Second) - priceChangeDenominator = Dimensions{1, 1, 2, 10} - minUnitFees = Dimensions{0, 0, 0, 0} + updateCoefficient = Dimensions{0, 1, 2, 10} + minUnitFees = Dimensions{0, 0, 0, 0} ) m := &Manager{ @@ -86,21 +86,21 @@ func TestComputeNextNonEmptyWindows(t *testing.T) { lastBlkTime.Unix(), currBlkTime.Unix(), targetComplexity, - priceChangeDenominator, + updateCoefficient, minUnitFees, ) // Bandwidth units are below target, next unit fees are pushed to the minimum - require.Equal(minUnitFees[Bandwidth], next.unitFees[Bandwidth]) + require.Equal(uint64(1), next.unitFees[Bandwidth]) // UTXORead units are at above target, due to spike in window. Next unit fees are increased - require.Equal(uint64(737869762948382064), next.unitFees[UTXORead]) + require.Equal(uint64(math.MaxUint64), next.unitFees[UTXORead]) // UTXOWrite units are above target, even if they are decreasing within the window. Next unit fees increased. - require.Equal(initialUnitFees[UTXOWrite]+4, next.unitFees[UTXOWrite]) + require.Equal(uint64(19776403), next.unitFees[UTXOWrite]) // Compute units are above target, next unit fees increased, proportionally to priceChangeDenominator - require.Equal(uint64(73786976294838207), next.unitFees[Compute]) + require.Equal(uint64(math.MaxUint64), next.unitFees[Compute]) // next cumulated units are zeroed require.Equal(Dimensions{}, next.cumulatedUnits) @@ -147,10 +147,10 @@ func TestComputeNextEdgeCases(t *testing.T) { require.Equal(initialUnitFees[UTXORead], next.unitFees[UTXORead]) // UTXOWrite units are above target, even if they are decreasing within the window. Next unit fees increased. - require.Equal(minUnitFees[UTXOWrite], next.unitFees[UTXOWrite]) + require.Equal(initialUnitFees[UTXOWrite]-1, next.unitFees[UTXOWrite]) // Compute units are above target, next unit fees increased, proportionally to priceChangeDenominator - require.Equal(minUnitFees[Compute], next.unitFees[Compute]) + require.Equal(initialUnitFees[Compute]-1, next.unitFees[Compute]) // next cumulated units are zeroed require.Equal(Dimensions{}, next.cumulatedUnits) diff --git a/vms/platformvm/block/executor/manager.go b/vms/platformvm/block/executor/manager.go index 69dcb9d2483d..705844410afd 100644 --- a/vms/platformvm/block/executor/manager.go +++ b/vms/platformvm/block/executor/manager.go @@ -160,7 +160,7 @@ func (m *manager) VerifyTx(tx *txs.Tx) error { stateDiff.GetTimestamp().Unix(), nextBlkTime.Unix(), feesCfg.BlockUnitsTarget, - feesCfg.FeesChangeDenominator, + feesCfg.UpdateCoefficient, feesCfg.MinUnitFees, ) diff --git a/vms/platformvm/block/executor/verifier.go b/vms/platformvm/block/executor/verifier.go index 5ca2873998ef..bfac31d5883d 100644 --- a/vms/platformvm/block/executor/verifier.go +++ b/vms/platformvm/block/executor/verifier.go @@ -478,7 +478,7 @@ func (v *verifier) processStandardTxs(txs []*txs.Tx, state state.Diff, parentID currentTimestamp.Unix(), blkTimestamp.Unix(), feesCfg.BlockUnitsTarget, - feesCfg.FeesChangeDenominator, + feesCfg.UpdateCoefficient, feesCfg.MinUnitFees, ) } diff --git a/vms/platformvm/config/dynamic_fees_config.go b/vms/platformvm/config/dynamic_fees_config.go index 6b74029b2f73..91354c30b31e 100644 --- a/vms/platformvm/config/dynamic_fees_config.go +++ b/vms/platformvm/config/dynamic_fees_config.go @@ -34,11 +34,11 @@ var ( 4 * units.NanoAvax, }, MinUnitFees: commonfees.Dimensions{}, - FeesChangeDenominator: commonfees.Dimensions{ - units.NanoAvax, - units.NanoAvax, - units.NanoAvax, - units.NanoAvax, + UpdateCoefficient: commonfees.Dimensions{ + 1, + 1, + 1, + 1, }, BlockUnitsCap: commonfees.Max, BlockUnitsTarget: commonfees.Dimensions{1, 1, 1, 1}, @@ -61,9 +61,9 @@ type DynamicFeesConfig struct { // minimal unit fees enforced by the dynamic fees algo. MinUnitFees commonfees.Dimensions - // FeesChangeDenominator contains, per each fee dimension, the - // minimal unit fees change - FeesChangeDenominator commonfees.Dimensions + // UpdateCoefficient contains, per each fee dimension, the + // exponential update coefficient + UpdateCoefficient commonfees.Dimensions // BlockUnitsCap contains, per each fee dimension, the // maximal complexity a valid P-chain block can host @@ -85,10 +85,6 @@ func (c *DynamicFeesConfig) validate() error { ) } - if c.FeesChangeDenominator[i] == 0 { - return fmt.Errorf("dimension %d, fees change denominator set to zero", i) - } - if c.BlockUnitsTarget[i] > c.BlockUnitsCap[i] { return fmt.Errorf("dimension %d, block target units %d larger than block units cap %d", i, From 4a939217d834a514745b4400d3641fa7ace760f8 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Sun, 10 Mar 2024 20:25:37 +0100 Subject: [PATCH 112/190] nits --- vms/components/fees/manager.go | 2 +- vms/components/fees/manager_test.go | 42 ++++++++++---------- vms/platformvm/config/dynamic_fees_config.go | 3 +- 3 files changed, 24 insertions(+), 23 deletions(-) diff --git a/vms/components/fees/manager.go b/vms/components/fees/manager.go index 3cc033b83d34..07b1e2d12e10 100644 --- a/vms/components/fees/manager.go +++ b/vms/components/fees/manager.go @@ -160,7 +160,7 @@ func computeNextPriceWindow( } nextRawRate := math.Round(float64(currentUnitFee) * math.Exp(exponent)) - if nextRawRate > math.MaxUint64 { + if nextRawRate >= math.MaxUint64 { return math.MaxUint64, newRollupWindow } diff --git a/vms/components/fees/manager_test.go b/vms/components/fees/manager_test.go index 95bd7ebfb73c..dac2f0d5093f 100644 --- a/vms/components/fees/manager_test.go +++ b/vms/components/fees/manager_test.go @@ -16,15 +16,15 @@ func TestComputeNextEmptyWindows(t *testing.T) { var ( initialUnitFees = Dimensions{1, 1, 1, 1} - consumedUnits = Dimensions{10, 25, 30, 2500} + consumedUnits = Dimensions{5, 25, 30, 2500} targetComplexity = Dimensions{25, 25, 25, 25} // last block happened within Window lastBlkTime = time.Now().Truncate(time.Second) currBlkTime = lastBlkTime.Add(time.Second) - priceChangeDenominator = Dimensions{0, 1, 2, 10} - minUnitFees = Dimensions{0, 0, 0, 0} + updateCoefficient = Dimensions{1, 2, 5, 10} + minUnitFees = Dimensions{0, 0, 0, 0} ) m := &Manager{ @@ -36,20 +36,20 @@ func TestComputeNextEmptyWindows(t *testing.T) { lastBlkTime.Unix(), currBlkTime.Unix(), targetComplexity, - priceChangeDenominator, + updateCoefficient, minUnitFees, ) // Bandwidth units are below target, next unit fees are pushed to the minimum - require.Equal(minUnitFees[Bandwidth]+1, next.unitFees[Bandwidth]) + require.Equal(minUnitFees[Bandwidth], next.unitFees[Bandwidth]) // UTXORead units are at target, next unit fees are kept equal require.Equal(initialUnitFees[UTXORead], next.unitFees[UTXORead]) - // UTXOWrite units are above target, next unit fees increased, proportionally to priceChangeDenominator - require.Equal(uint64(1), next.unitFees[UTXOWrite]) + // UTXOWrite units are above target, next unit fees increased + require.Equal(uint64(3), next.unitFees[UTXOWrite]) - // Compute units are above target, next unit fees increased, proportionally to priceChangeDenominator + // Compute units are way above target, next unit fees are increased to the max require.Equal(uint64(math.MaxUint64), next.unitFees[Compute]) // next cumulated units are zeroed @@ -68,7 +68,7 @@ func TestComputeNextNonEmptyWindows(t *testing.T) { lastBlkTime = time.Now().Truncate(time.Second) currBlkTime = lastBlkTime.Add(time.Second) - updateCoefficient = Dimensions{0, 1, 2, 10} + updateCoefficient = Dimensions{1, 2, 5, 10} minUnitFees = Dimensions{0, 0, 0, 0} ) @@ -91,15 +91,15 @@ func TestComputeNextNonEmptyWindows(t *testing.T) { ) // Bandwidth units are below target, next unit fees are pushed to the minimum - require.Equal(uint64(1), next.unitFees[Bandwidth]) + require.Equal(initialUnitFees[Bandwidth], next.unitFees[Bandwidth]) // UTXORead units are at above target, due to spike in window. Next unit fees are increased require.Equal(uint64(math.MaxUint64), next.unitFees[UTXORead]) // UTXOWrite units are above target, even if they are decreasing within the window. Next unit fees increased. - require.Equal(uint64(19776403), next.unitFees[UTXOWrite]) + require.Equal(uint64(1739274941520500992), next.unitFees[UTXOWrite]) - // Compute units are above target, next unit fees increased, proportionally to priceChangeDenominator + // Compute units are above target, next unit fees are increased. require.Equal(uint64(math.MaxUint64), next.unitFees[Compute]) // next cumulated units are zeroed @@ -118,15 +118,15 @@ func TestComputeNextEdgeCases(t *testing.T) { lastBlkTime = time.Now().Truncate(time.Second) currBlkTime = lastBlkTime.Add(time.Second) - priceChangeDenominator = Dimensions{1, 1, 1, 1} - minUnitFees = Dimensions{1, 0, 0, 0} + updateCoefficient = Dimensions{1, 1, 1, 1} + minUnitFees = Dimensions{1, 0, 0, 0} ) m := &Manager{ unitFees: initialUnitFees, windows: [FeeDimensions]Window{ {0, 0, 0, math.MaxUint64, 0, 0, 0, 0, 0, 0}, // a huge spike in the past, on the non-constrained dimension - {0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, // a small spike, but above the zero constrain set for this dimension + {0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, // a small spike, but it hits the small constrain set for this dimension {}, {}, }, @@ -136,21 +136,21 @@ func TestComputeNextEdgeCases(t *testing.T) { lastBlkTime.Unix(), currBlkTime.Unix(), targetComplexity, - priceChangeDenominator, + updateCoefficient, minUnitFees, ) // Bandwidth units are below target, next unit fees are pushed to the minimum require.Equal(minUnitFees[Bandwidth], next.unitFees[Bandwidth]) - // UTXORead units are at above target, due to spike in window. Next unit fees are increased + // UTXORead units are at target, due to spike in window. Unit fees are kept unchanged. require.Equal(initialUnitFees[UTXORead], next.unitFees[UTXORead]) - // UTXOWrite units are above target, even if they are decreasing within the window. Next unit fees increased. - require.Equal(initialUnitFees[UTXOWrite]-1, next.unitFees[UTXOWrite]) + // UTXOWrite units are below target. Unit fees are decreased. + require.Equal(initialUnitFees[UTXOWrite]/2, next.unitFees[UTXOWrite]) - // Compute units are above target, next unit fees increased, proportionally to priceChangeDenominator - require.Equal(initialUnitFees[Compute]-1, next.unitFees[Compute]) + // Compute units are below target. Unit fees are decreased. + require.Equal(initialUnitFees[Compute]/2, next.unitFees[Compute]) // next cumulated units are zeroed require.Equal(Dimensions{}, next.cumulatedUnits) diff --git a/vms/platformvm/config/dynamic_fees_config.go b/vms/platformvm/config/dynamic_fees_config.go index 91354c30b31e..8cdd7c19c1cf 100644 --- a/vms/platformvm/config/dynamic_fees_config.go +++ b/vms/platformvm/config/dynamic_fees_config.go @@ -62,7 +62,8 @@ type DynamicFeesConfig struct { MinUnitFees commonfees.Dimensions // UpdateCoefficient contains, per each fee dimension, the - // exponential update coefficient + // exponential update coefficient. Setting an entry to 0 makes + // the corresponding fee rate constant. UpdateCoefficient commonfees.Dimensions // BlockUnitsCap contains, per each fee dimension, the From 6d28d7a57354de45a601d2d82a7fba82f05b055c Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Sun, 10 Mar 2024 21:47:38 +0100 Subject: [PATCH 113/190] nit + minor UT fix --- vms/components/fees/manager_test.go | 2 +- vms/platformvm/block/executor/manager.go | 23 ++++++++++++++--------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/vms/components/fees/manager_test.go b/vms/components/fees/manager_test.go index dac2f0d5093f..78175c9692d3 100644 --- a/vms/components/fees/manager_test.go +++ b/vms/components/fees/manager_test.go @@ -97,7 +97,7 @@ func TestComputeNextNonEmptyWindows(t *testing.T) { require.Equal(uint64(math.MaxUint64), next.unitFees[UTXORead]) // UTXOWrite units are above target, even if they are decreasing within the window. Next unit fees increased. - require.Equal(uint64(1739274941520500992), next.unitFees[UTXOWrite]) + require.Equal(uint64(1739274941520501248), next.unitFees[UTXOWrite]) // Compute units are above target, next unit fees are increased. require.Equal(uint64(math.MaxUint64), next.unitFees[Compute]) diff --git a/vms/platformvm/block/executor/manager.go b/vms/platformvm/block/executor/manager.go index 705844410afd..d76ef2cb7ece 100644 --- a/vms/platformvm/block/executor/manager.go +++ b/vms/platformvm/block/executor/manager.go @@ -153,17 +153,22 @@ func (m *manager) VerifyTx(tx *txs.Tx) error { } var ( - feesCfg = m.txExecutorBackend.Config.GetDynamicFeesConfig(stateDiff.GetTimestamp()) - parentFeeManager = fees.NewManager(unitFees, unitWindows) - ) - feeManager := parentFeeManager.ComputeNext( - stateDiff.GetTimestamp().Unix(), - nextBlkTime.Unix(), - feesCfg.BlockUnitsTarget, - feesCfg.UpdateCoefficient, - feesCfg.MinUnitFees, + chainTime = stateDiff.GetTimestamp() + isEForkActive = m.txExecutorBackend.Config.IsEUpgradeActivated(chainTime) + feesCfg = m.txExecutorBackend.Config.GetDynamicFeesConfig(chainTime) ) + feeManager := fees.NewManager(unitFees, unitWindows) + if isEForkActive { + feeManager = feeManager.ComputeNext( + chainTime.Unix(), + nextBlkTime.Unix(), + feesCfg.BlockUnitsTarget, + feesCfg.UpdateCoefficient, + feesCfg.MinUnitFees, + ) + } + return tx.Unsigned.Visit(&executor.StandardTxExecutor{ Backend: m.txExecutorBackend, BlkFeeManager: feeManager, From 003b2c841b784a40263ecf256486e6fc3095e09f Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 11 Mar 2024 01:24:55 +0100 Subject: [PATCH 114/190] another exponential fee update approximation --- vms/components/fees/manager.go | 42 ++++++++++++++++------------- vms/components/fees/manager_test.go | 16 +++++------ 2 files changed, 32 insertions(+), 26 deletions(-) diff --git a/vms/components/fees/manager.go b/vms/components/fees/manager.go index 07b1e2d12e10..a64fbe94fe36 100644 --- a/vms/components/fees/manager.go +++ b/vms/components/fees/manager.go @@ -145,26 +145,32 @@ func computeNextPriceWindow( Update(&newRollupWindow, start, currentUnitsConsumed) } - var ( - totalUnitsConsumed = Sum(newRollupWindow) - exponent = float64(0) - ) + totalUnitsConsumed := Sum(newRollupWindow) + nextUnitFee := nextFeeRate(currentUnitFee, updateCoefficient, totalUnitsConsumed, target) + nextUnitFee = max(nextUnitFee, minUnitFee) + return nextUnitFee, newRollupWindow +} + +func nextFeeRate(currentUnitFee, updateCoefficient, unitsConsumed, target uint64) uint64 { + // We approximate e^{k(u-t)/t} with 2^{k(u-t)/(t ln(2))} + // 1/ln(2) is approx. 1,442695 switch { - case totalUnitsConsumed == target: - return currentUnitFee, newRollupWindow - case totalUnitsConsumed > target: - exponent = float64(updateCoefficient) * float64(totalUnitsConsumed-target) / float64(target) - case totalUnitsConsumed < target: - exponent = -float64(updateCoefficient) * float64(target-totalUnitsConsumed) / float64(target) - } + case unitsConsumed > target: + exp := float64(1.442695) * float64(updateCoefficient*(unitsConsumed-target)) / float64(target) + intExp := min(uint64(math.Ceil(exp)), 62) // we cap the exponent to avoid an overflow of uint64 type + res, over := safemath.Mul64(currentUnitFee, 1<= math.MaxUint64 { - return math.MaxUint64, newRollupWindow - } + case unitsConsumed < target: + exp := float64(1.442695) * float64(updateCoefficient*(target-unitsConsumed)) / float64(target) + intExp := min(uint64(math.Ceil(exp)), 62) // we cap the exponent to avoid an overflow of uint64 type + return currentUnitFee / (1 << intExp) - nextUnitFee := uint64(nextRawRate) - nextUnitFee = max(nextUnitFee, minUnitFee) - return nextUnitFee, newRollupWindow + default: + return currentUnitFee // unitsConsumed == target + } } diff --git a/vms/components/fees/manager_test.go b/vms/components/fees/manager_test.go index 78175c9692d3..2bbf690aae12 100644 --- a/vms/components/fees/manager_test.go +++ b/vms/components/fees/manager_test.go @@ -47,10 +47,10 @@ func TestComputeNextEmptyWindows(t *testing.T) { require.Equal(initialUnitFees[UTXORead], next.unitFees[UTXORead]) // UTXOWrite units are above target, next unit fees increased - require.Equal(uint64(3), next.unitFees[UTXOWrite]) + require.Equal(uint64(4), next.unitFees[UTXOWrite]) // Compute units are way above target, next unit fees are increased to the max - require.Equal(uint64(math.MaxUint64), next.unitFees[Compute]) + require.Equal(uint64(4*1<<60), next.unitFees[Compute]) // next cumulated units are zeroed require.Equal(Dimensions{}, next.cumulatedUnits) @@ -91,16 +91,16 @@ func TestComputeNextNonEmptyWindows(t *testing.T) { ) // Bandwidth units are below target, next unit fees are pushed to the minimum - require.Equal(initialUnitFees[Bandwidth], next.unitFees[Bandwidth]) + require.Equal(minUnitFees[Bandwidth], next.unitFees[Bandwidth]) // UTXORead units are at above target, due to spike in window. Next unit fees are increased - require.Equal(uint64(math.MaxUint64), next.unitFees[UTXORead]) + require.Equal(uint64(4*1<<60), next.unitFees[UTXORead]) // UTXOWrite units are above target, even if they are decreasing within the window. Next unit fees increased. - require.Equal(uint64(1739274941520501248), next.unitFees[UTXOWrite]) + require.Equal(uint64(2*1<<60), next.unitFees[UTXOWrite]) // Compute units are above target, next unit fees are increased. - require.Equal(uint64(math.MaxUint64), next.unitFees[Compute]) + require.Equal(uint64(4*1<<60), next.unitFees[Compute]) // next cumulated units are zeroed require.Equal(Dimensions{}, next.cumulatedUnits) @@ -147,10 +147,10 @@ func TestComputeNextEdgeCases(t *testing.T) { require.Equal(initialUnitFees[UTXORead], next.unitFees[UTXORead]) // UTXOWrite units are below target. Unit fees are decreased. - require.Equal(initialUnitFees[UTXOWrite]/2, next.unitFees[UTXOWrite]) + require.Equal(minUnitFees[UTXOWrite], next.unitFees[UTXOWrite]) // Compute units are below target. Unit fees are decreased. - require.Equal(initialUnitFees[Compute]/2, next.unitFees[Compute]) + require.Equal(minUnitFees[Compute], next.unitFees[Compute]) // next cumulated units are zeroed require.Equal(Dimensions{}, next.cumulatedUnits) From d25205c9d5b60cc2af5902922649728102608a2f Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 11 Mar 2024 13:29:43 +0100 Subject: [PATCH 115/190] fixed block building post e upgrade --- vms/components/fees/dimensions.go | 9 +++++++ vms/components/fees/manager.go | 4 ++-- vms/platformvm/block/builder/builder.go | 32 ++++++++++++++++++++----- vms/platformvm/vm_test.go | 2 +- 4 files changed, 38 insertions(+), 9 deletions(-) diff --git a/vms/components/fees/dimensions.go b/vms/components/fees/dimensions.go index 05171ec3c0ff..a42e55226f00 100644 --- a/vms/components/fees/dimensions.go +++ b/vms/components/fees/dimensions.go @@ -72,6 +72,15 @@ func Add(lhs, rhs Dimensions) (Dimensions, error) { return res, nil } +func Compare(lhs, rhs Dimensions) bool { + for i := 0; i < FeeDimensions; i++ { + if lhs[i] > rhs[i] { + return false + } + } + return true +} + func (d *Dimensions) Bytes() []byte { res := make([]byte, FeeDimensions*uint64Len) for i := Dimension(0); i < FeeDimensions; i++ { diff --git a/vms/components/fees/manager.go b/vms/components/fees/manager.go index a64fbe94fe36..27a6cc049e76 100644 --- a/vms/components/fees/manager.go +++ b/vms/components/fees/manager.go @@ -152,8 +152,8 @@ func computeNextPriceWindow( } func nextFeeRate(currentUnitFee, updateCoefficient, unitsConsumed, target uint64) uint64 { - // We approximate e^{k(u-t)/t} with 2^{k(u-t)/(t ln(2))} - // 1/ln(2) is approx. 1,442695 + // We update the fee rate with the formula e^{k(u-t)/t} == 2^{1/ln(2) * k(u-t)/t} + // We approximate 1/ln(2) with 1,442695 and we round the exponent to a uint64 switch { case unitsConsumed > target: diff --git a/vms/platformvm/block/builder/builder.go b/vms/platformvm/block/builder/builder.go index 8a7574633fca..9ed2cda969c2 100644 --- a/vms/platformvm/block/builder/builder.go +++ b/vms/platformvm/block/builder/builder.go @@ -18,13 +18,13 @@ import ( "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/fees" "github.com/ava-labs/avalanchego/vms/platformvm/block" "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/mempool" + commonfees "github.com/ava-labs/avalanchego/vms/components/fees" blockexecutor "github.com/ava-labs/avalanchego/vms/platformvm/block/executor" txexecutor "github.com/ava-labs/avalanchego/vms/platformvm/txs/executor" ) @@ -342,20 +342,38 @@ func packBlockTxs( } var ( - feeCfg = backend.Config.GetDynamicFeesConfig(stateDiff.GetTimestamp()) - feeMan = fees.NewManager(unitFees, unitWindows) + parentBlkTime = parentState.GetTimestamp() + feesCfg = backend.Config.GetDynamicFeesConfig(timestamp) + isEForkActive = backend.Config.IsEUpgradeActivated(timestamp) blockTxs []*txs.Tx inputs set.Set[ids.ID] ) + feeMan := commonfees.NewManager(unitFees, unitWindows) + if isEForkActive { + feeMan = feeMan.ComputeNext( + parentBlkTime.Unix(), + timestamp.Unix(), + feesCfg.BlockUnitsTarget, + feesCfg.UpdateCoefficient, + feesCfg.MinUnitFees, + ) + } + for { tx, exists := mempool.Peek() if !exists { break } + txSize := len(tx.Bytes()) - if txSize > remainingSize { + + // pre e upgrade is active, we fill blocks till a target size + // post e upgrade is active, we fill blocks till a target complexity + targetSizeReached := (!isEForkActive && txSize > remainingSize) || + (isEForkActive && !commonfees.Compare(feeMan.GetCumulatedUnits(), feesCfg.BlockUnitsTarget)) + if targetSizeReached { break } mempool.Remove(tx) @@ -370,7 +388,7 @@ func packBlockTxs( executor := &txexecutor.StandardTxExecutor{ Backend: backend, BlkFeeManager: feeMan, - UnitCaps: feeCfg.BlockUnitsCap, + UnitCaps: feesCfg.BlockUnitsCap, State: txDiff, Tx: tx, } @@ -401,7 +419,9 @@ func packBlockTxs( return nil, err } - remainingSize -= txSize + if !isEForkActive { + remainingSize -= txSize + } blockTxs = append(blockTxs, tx) } diff --git a/vms/platformvm/vm_test.go b/vms/platformvm/vm_test.go index 34779b67fe22..118c428ae940 100644 --- a/vms/platformvm/vm_test.go +++ b/vms/platformvm/vm_test.go @@ -2316,7 +2316,7 @@ func TestBaseTx(t *testing.T) { func TestPruneMempool(t *testing.T) { require := require.New(t) - vm, _, _ := defaultVM(t, latestFork) + vm, _, _ := defaultVM(t, durango) vm.ctx.Lock.Lock() defer vm.ctx.Lock.Unlock() From 3175c7d1e60b2f8244663feab5dcedb233e539d6 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 11 Mar 2024 15:00:05 +0100 Subject: [PATCH 116/190] exponential fees update stability --- vms/components/fees/manager_test.go | 62 +++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/vms/components/fees/manager_test.go b/vms/components/fees/manager_test.go index 2bbf690aae12..e5e1fc26c9c0 100644 --- a/vms/components/fees/manager_test.go +++ b/vms/components/fees/manager_test.go @@ -155,3 +155,65 @@ func TestComputeNextEdgeCases(t *testing.T) { // next cumulated units are zeroed require.Equal(Dimensions{}, next.cumulatedUnits) } + +func TestComputeNextStability(t *testing.T) { + // The advantage of using an exponential fee update scheme + // (vs e.g. the EIP-1559 scheme we use in the C-chain) is that + // it is more stable against dithering. + // We prove here that if consumed used oscillate around the target + // unit fees are unchanged. + + require := require.New(t) + + var ( + initialUnitFees = Dimensions{10, 100, 1_000, 1_000_000_000} + consumedUnits1 = Dimensions{24, 45, 70, 500} + consumedUnits2 = Dimensions{26, 55, 130, 1500} + targetComplexity = Dimensions{25, 50, 100, 1000} + + lastBlkTime = time.Now().Truncate(time.Second) + currBlkTime = lastBlkTime.Add(time.Second) + + updateCoefficient = Dimensions{1, 2, 5, 10} + minUnitFees = Dimensions{0, 0, 0, 0} + ) + + // step1: cumulated units are below target. Unit fees must decrease + m1 := &Manager{ + unitFees: initialUnitFees, + windows: [FeeDimensions]Window{}, + cumulatedUnits: consumedUnits1, + } + next1 := m1.ComputeNext( + lastBlkTime.Unix(), + currBlkTime.Unix(), + targetComplexity, + updateCoefficient, + minUnitFees, + ) + + require.Less(next1.unitFees[Bandwidth], initialUnitFees[Bandwidth]) + require.Less(next1.unitFees[UTXORead], initialUnitFees[UTXORead]) + require.Less(next1.unitFees[UTXOWrite], initialUnitFees[UTXOWrite]) + require.Less(next1.unitFees[Compute], initialUnitFees[Compute]) + + // step2: cumulated units go slight above target, so that average consumed units are at target. + // Unit fees go back to the original value + m2 := &Manager{ + unitFees: next1.unitFees, + windows: [FeeDimensions]Window{}, + cumulatedUnits: consumedUnits2, + } + next2 := m2.ComputeNext( + lastBlkTime.Unix(), + currBlkTime.Unix(), + targetComplexity, + updateCoefficient, + minUnitFees, + ) + + require.Equal(initialUnitFees[Bandwidth], next2.unitFees[Bandwidth]) + require.Equal(initialUnitFees[UTXORead], next2.unitFees[UTXORead]) + require.Equal(initialUnitFees[UTXOWrite], next2.unitFees[UTXOWrite]) + require.Equal(initialUnitFees[Compute], next2.unitFees[Compute]) +} From 173de684e5141a39046c2c4b371cff0864ded73e Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 11 Mar 2024 16:56:51 +0100 Subject: [PATCH 117/190] fixed merge --- vms/platformvm/block/builder/builder.go | 2 +- vms/platformvm/block/executor/manager.go | 2 +- vms/platformvm/block/executor/verifier.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/vms/platformvm/block/builder/builder.go b/vms/platformvm/block/builder/builder.go index 9ed2cda969c2..1ca97c99a75e 100644 --- a/vms/platformvm/block/builder/builder.go +++ b/vms/platformvm/block/builder/builder.go @@ -344,7 +344,7 @@ func packBlockTxs( var ( parentBlkTime = parentState.GetTimestamp() feesCfg = backend.Config.GetDynamicFeesConfig(timestamp) - isEForkActive = backend.Config.IsEUpgradeActivated(timestamp) + isEForkActive = backend.Config.IsEActivated(timestamp) blockTxs []*txs.Tx inputs set.Set[ids.ID] diff --git a/vms/platformvm/block/executor/manager.go b/vms/platformvm/block/executor/manager.go index d76ef2cb7ece..f047236a994a 100644 --- a/vms/platformvm/block/executor/manager.go +++ b/vms/platformvm/block/executor/manager.go @@ -154,7 +154,7 @@ func (m *manager) VerifyTx(tx *txs.Tx) error { var ( chainTime = stateDiff.GetTimestamp() - isEForkActive = m.txExecutorBackend.Config.IsEUpgradeActivated(chainTime) + isEForkActive = m.txExecutorBackend.Config.IsEActivated(chainTime) feesCfg = m.txExecutorBackend.Config.GetDynamicFeesConfig(chainTime) ) diff --git a/vms/platformvm/block/executor/verifier.go b/vms/platformvm/block/executor/verifier.go index 3fd9d730ebe3..89b74a5fc7f5 100644 --- a/vms/platformvm/block/executor/verifier.go +++ b/vms/platformvm/block/executor/verifier.go @@ -458,7 +458,7 @@ func (v *verifier) processStandardTxs(txs []*txs.Tx, state state.Diff, parentID var ( currentTimestamp = state.GetTimestamp() - isEForkActive = v.txExecutorBackend.Config.IsEUpgradeActivated(currentTimestamp) + isEForkActive = v.txExecutorBackend.Config.IsEActivated(currentTimestamp) feesCfg = v.txExecutorBackend.Config.GetDynamicFeesConfig(currentTimestamp) onAcceptFunc func() From 0f067dddc71cf53a5283c59a0248ee14eba1c1e9 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 11 Mar 2024 21:32:29 +0100 Subject: [PATCH 118/190] wip: refactored feeConfig getter --- tests/e2e/p/workflow.go | 2 +- vms/platformvm/block/builder/builder.go | 16 ++-- vms/platformvm/block/builder/helpers_test.go | 3 +- vms/platformvm/block/executor/helpers_test.go | 3 +- vms/platformvm/block/executor/manager.go | 9 +- vms/platformvm/block/executor/verifier.go | 9 +- vms/platformvm/config/config.go | 8 -- vms/platformvm/config/dynamic_fees_config.go | 18 +++- vms/platformvm/service_test.go | 3 +- vms/platformvm/state/state.go | 3 +- vms/platformvm/txs/builder/builder.go | 26 +++--- .../txs/executor/atomic_tx_executor.go | 2 +- .../txs/executor/create_chain_test.go | 25 +++-- .../txs/executor/create_subnet_test.go | 13 ++- vms/platformvm/txs/executor/helpers_test.go | 3 +- .../txs/executor/standard_tx_executor_test.go | 93 ++++++++++++------- vms/platformvm/vm_test.go | 4 +- wallet/chain/p/wallet.go | 7 +- 18 files changed, 144 insertions(+), 103 deletions(-) diff --git a/tests/e2e/p/workflow.go b/tests/e2e/p/workflow.go index 5cb325999be5..c559e25cf5eb 100644 --- a/tests/e2e/p/workflow.go +++ b/tests/e2e/p/workflow.go @@ -137,7 +137,7 @@ var _ = e2e.DescribePChain("[Workflow]", func() { pChainExportFee := uint64(0) ginkgo.By("export avax from P to X chain", func() { - unitCaps := config.EUpgradeDynamicFeesConfig.BlockUnitsCap + unitCaps := config.GetDynamicFeesConfig(true /*isEActive*/).BlockUnitsCap unitFees, err := pChainClient.GetUnitFees(e2e.DefaultContext()) require.NoError(err) diff --git a/vms/platformvm/block/builder/builder.go b/vms/platformvm/block/builder/builder.go index 1ca97c99a75e..91cad709212e 100644 --- a/vms/platformvm/block/builder/builder.go +++ b/vms/platformvm/block/builder/builder.go @@ -19,6 +19,7 @@ import ( "github.com/ava-labs/avalanchego/utils/timer/mockable" "github.com/ava-labs/avalanchego/utils/units" "github.com/ava-labs/avalanchego/vms/platformvm/block" + "github.com/ava-labs/avalanchego/vms/platformvm/config" "github.com/ava-labs/avalanchego/vms/platformvm/state" "github.com/ava-labs/avalanchego/vms/platformvm/status" "github.com/ava-labs/avalanchego/vms/platformvm/txs" @@ -342,18 +343,17 @@ func packBlockTxs( } var ( - parentBlkTime = parentState.GetTimestamp() - feesCfg = backend.Config.GetDynamicFeesConfig(timestamp) - isEForkActive = backend.Config.IsEActivated(timestamp) + isEActivated = backend.Config.IsEActivated(timestamp) + feesCfg = config.GetDynamicFeesConfig(isEActivated) blockTxs []*txs.Tx inputs set.Set[ids.ID] ) feeMan := commonfees.NewManager(unitFees, unitWindows) - if isEForkActive { + if isEActivated { feeMan = feeMan.ComputeNext( - parentBlkTime.Unix(), + parentState.GetTimestamp().Unix(), timestamp.Unix(), feesCfg.BlockUnitsTarget, feesCfg.UpdateCoefficient, @@ -371,8 +371,8 @@ 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 complexity - targetSizeReached := (!isEForkActive && txSize > remainingSize) || - (isEForkActive && !commonfees.Compare(feeMan.GetCumulatedUnits(), feesCfg.BlockUnitsTarget)) + targetSizeReached := (!isEActivated && txSize > remainingSize) || + (isEActivated && !commonfees.Compare(feeMan.GetCumulatedUnits(), feesCfg.BlockUnitsTarget)) if targetSizeReached { break } @@ -419,7 +419,7 @@ func packBlockTxs( return nil, err } - if !isEForkActive { + if !isEActivated { remainingSize -= txSize } blockTxs = append(blockTxs, tx) diff --git a/vms/platformvm/block/builder/helpers_test.go b/vms/platformvm/block/builder/helpers_test.go index d72643969945..c0920aa9cd79 100644 --- a/vms/platformvm/block/builder/helpers_test.go +++ b/vms/platformvm/block/builder/helpers_test.go @@ -269,7 +269,8 @@ func addSubnet(t *testing.T, env *environment) { unitWindows, err := env.state.GetFeeWindows() require.NoError(err) - feeCfg := env.config.GetDynamicFeesConfig(env.state.GetTimestamp()) + chainTime := env.state.GetTimestamp() + feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := txexecutor.StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: fees.NewManager(unitFees, unitWindows), diff --git a/vms/platformvm/block/executor/helpers_test.go b/vms/platformvm/block/executor/helpers_test.go index 88e2db3c02af..b866892b1b77 100644 --- a/vms/platformvm/block/executor/helpers_test.go +++ b/vms/platformvm/block/executor/helpers_test.go @@ -289,7 +289,8 @@ func addSubnet(env *environment) { panic(err) } - feeCfg := env.config.GetDynamicFeesConfig(env.state.GetTimestamp()) + chainTime := env.state.GetTimestamp() + feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := executor.StandardTxExecutor{ Backend: env.backend, BlkFeeManager: fees.NewManager(unitFees, unitWindows), diff --git a/vms/platformvm/block/executor/manager.go b/vms/platformvm/block/executor/manager.go index f047236a994a..77a0018da40f 100644 --- a/vms/platformvm/block/executor/manager.go +++ b/vms/platformvm/block/executor/manager.go @@ -11,6 +11,7 @@ import ( "github.com/ava-labs/avalanchego/utils/set" "github.com/ava-labs/avalanchego/vms/components/fees" "github.com/ava-labs/avalanchego/vms/platformvm/block" + "github.com/ava-labs/avalanchego/vms/platformvm/config" "github.com/ava-labs/avalanchego/vms/platformvm/metrics" "github.com/ava-labs/avalanchego/vms/platformvm/state" "github.com/ava-labs/avalanchego/vms/platformvm/txs" @@ -153,13 +154,13 @@ func (m *manager) VerifyTx(tx *txs.Tx) error { } var ( - chainTime = stateDiff.GetTimestamp() - isEForkActive = m.txExecutorBackend.Config.IsEActivated(chainTime) - feesCfg = m.txExecutorBackend.Config.GetDynamicFeesConfig(chainTime) + chainTime = stateDiff.GetTimestamp() + isEActivated = m.txExecutorBackend.Config.IsEActivated(chainTime) + feesCfg = config.GetDynamicFeesConfig(isEActivated) ) feeManager := fees.NewManager(unitFees, unitWindows) - if isEForkActive { + if isEActivated { feeManager = feeManager.ComputeNext( chainTime.Unix(), nextBlkTime.Unix(), diff --git a/vms/platformvm/block/executor/verifier.go b/vms/platformvm/block/executor/verifier.go index 89b74a5fc7f5..6fa5486dbc68 100644 --- a/vms/platformvm/block/executor/verifier.go +++ b/vms/platformvm/block/executor/verifier.go @@ -13,6 +13,7 @@ import ( "github.com/ava-labs/avalanchego/utils/set" "github.com/ava-labs/avalanchego/vms/components/fees" "github.com/ava-labs/avalanchego/vms/platformvm/block" + "github.com/ava-labs/avalanchego/vms/platformvm/config" "github.com/ava-labs/avalanchego/vms/platformvm/state" "github.com/ava-labs/avalanchego/vms/platformvm/status" "github.com/ava-labs/avalanchego/vms/platformvm/txs" @@ -458,8 +459,8 @@ func (v *verifier) processStandardTxs(txs []*txs.Tx, state state.Diff, parentID var ( currentTimestamp = state.GetTimestamp() - isEForkActive = v.txExecutorBackend.Config.IsEActivated(currentTimestamp) - feesCfg = v.txExecutorBackend.Config.GetDynamicFeesConfig(currentTimestamp) + isEActivated = v.txExecutorBackend.Config.IsEActivated(currentTimestamp) + feesCfg = config.GetDynamicFeesConfig(isEActivated) onAcceptFunc func() inputs set.Set[ids.ID] @@ -468,7 +469,7 @@ func (v *verifier) processStandardTxs(txs []*txs.Tx, state state.Diff, parentID ) feeManager := fees.NewManager(unitFees, unitWindows) - if isEForkActive { + if isEActivated { feeManager = feeManager.ComputeNext( currentTimestamp.Unix(), blkTimestamp.Unix(), @@ -520,7 +521,7 @@ func (v *verifier) processStandardTxs(txs []*txs.Tx, state state.Diff, parentID return nil, nil, nil, nil, err } - if isEForkActive { + if isEActivated { state.SetUnitFees(feeManager.GetUnitFees()) state.SetFeeWindows(feeManager.GetFeeWindows()) } diff --git a/vms/platformvm/config/config.go b/vms/platformvm/config/config.go index e2c9a12a1179..0c5fcf15a475 100644 --- a/vms/platformvm/config/config.go +++ b/vms/platformvm/config/config.go @@ -144,14 +144,6 @@ func (c *Config) IsEActivated(timestamp time.Time) bool { return !timestamp.Before(c.EUpgradeTime) } -func (c *Config) GetDynamicFeesConfig(timestamp time.Time) DynamicFeesConfig { - if !c.IsEActivated(timestamp) { - return PreEUpgradeDynamicFeesConfig - } - - return EUpgradeDynamicFeesConfig -} - func (c *Config) GetCreateBlockchainTxFee(timestamp time.Time) uint64 { if c.IsApricotPhase3Activated(timestamp) { return c.CreateBlockchainTxFee diff --git a/vms/platformvm/config/dynamic_fees_config.go b/vms/platformvm/config/dynamic_fees_config.go index 8cdd7c19c1cf..4bb115a29122 100644 --- a/vms/platformvm/config/dynamic_fees_config.go +++ b/vms/platformvm/config/dynamic_fees_config.go @@ -19,14 +19,14 @@ import ( // so to have fork control over which dynamic fees is picked func init() { - if err := EUpgradeDynamicFeesConfig.validate(); err != nil { + if err := eUpgradeDynamicFeesConfig.validate(); err != nil { panic(err) } } -// EUpgradeDynamicFeesConfig to be tuned TODO ABENEGIA +// eUpgradeDynamicFeesConfig to be tuned TODO ABENEGIA var ( - EUpgradeDynamicFeesConfig = DynamicFeesConfig{ + eUpgradeDynamicFeesConfig = DynamicFeesConfig{ InitialUnitFees: commonfees.Dimensions{ 1 * units.NanoAvax, 2 * units.NanoAvax, @@ -44,13 +44,21 @@ var ( BlockUnitsTarget: commonfees.Dimensions{1, 1, 1, 1}, } - // TODO ABENEGIA: decide if and how to validate PreEUpgradeDynamicFeesConfig - PreEUpgradeDynamicFeesConfig = DynamicFeesConfig{ + // TODO ABENEGIA: decide if and how to validate preEUpgradeDynamicFeesConfig + preEUpgradeDynamicFeesConfig = DynamicFeesConfig{ InitialUnitFees: commonfees.Empty, BlockUnitsCap: commonfees.Max, } ) +func GetDynamicFeesConfig(isEActive bool) DynamicFeesConfig { + if !isEActive { + return preEUpgradeDynamicFeesConfig + } + + return eUpgradeDynamicFeesConfig +} + type DynamicFeesConfig struct { // InitialUnitFees contains, per each fee dimension, the // unit fees valid as soon as fork introducing dynamic fees diff --git a/vms/platformvm/service_test.go b/vms/platformvm/service_test.go index 2e301c4e78b6..6259a5bccde8 100644 --- a/vms/platformvm/service_test.go +++ b/vms/platformvm/service_test.go @@ -35,6 +35,7 @@ import ( "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/platformvm/block" "github.com/ava-labs/avalanchego/vms/platformvm/block/builder" + "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" @@ -360,7 +361,7 @@ func TestGetBalance(t *testing.T) { var ( chainTime = service.vm.state.GetTimestamp() - feeCfg = service.vm.Config.GetDynamicFeesConfig(chainTime) + feeCfg = config.GetDynamicFeesConfig(service.vm.Config.IsEActivated(chainTime)) feeMan = commonfees.NewManager(unitFees, feeWindows) feeCalc = &fees.Calculator{ IsEUpgradeActive: service.vm.IsEActivated(chainTime), diff --git a/vms/platformvm/state/state.go b/vms/platformvm/state/state.go index 9fc74b2e4e76..6b1a7cb72274 100644 --- a/vms/platformvm/state/state.go +++ b/vms/platformvm/state/state.go @@ -1362,7 +1362,8 @@ func (s *state) loadMetadata() error { // fork introducing dynamic fees may not be active yet, // hence we may have never stored unit fees. Load from config // TODO: remove once fork is active - s.unitFees = config.EUpgradeDynamicFeesConfig.InitialUnitFees + isEActive := s.cfg.IsEActivated(timestamp) + s.unitFees = config.GetDynamicFeesConfig(isEActive).InitialUnitFees default: return err diff --git a/vms/platformvm/txs/builder/builder.go b/vms/platformvm/txs/builder/builder.go index 92dd211dea11..b807d859803b 100644 --- a/vms/platformvm/txs/builder/builder.go +++ b/vms/platformvm/txs/builder/builder.go @@ -293,7 +293,7 @@ func (b *builder) NewImportTx( var ( pBuilder, pSigner = b.builders(keys) chainTime = b.state.GetTimestamp() - feeCfg = b.cfg.GetDynamicFeesConfig(chainTime) + feeCfg = config.GetDynamicFeesConfig(b.cfg.IsEActivated(chainTime)) isEUpgradeActive = b.cfg.IsEActivated(chainTime) feeCalc = &fees.Calculator{ @@ -349,7 +349,7 @@ func (b *builder) NewExportTx( var ( pBuilder, pSigner = b.builders(keys) chainTime = b.state.GetTimestamp() - feeCfg = b.cfg.GetDynamicFeesConfig(chainTime) + feeCfg = config.GetDynamicFeesConfig(b.cfg.IsEActivated(chainTime)) isEUpgradeActive = b.cfg.IsEActivated(chainTime) feeCalc = &fees.Calculator{ @@ -412,7 +412,7 @@ func (b *builder) NewCreateChainTx( var ( pBuilder, pSigner = b.builders(keys) chainTime = b.state.GetTimestamp() - feeCfg = b.cfg.GetDynamicFeesConfig(chainTime) + feeCfg = config.GetDynamicFeesConfig(b.cfg.IsEActivated(chainTime)) isEUpgradeActive = b.cfg.IsEActivated(chainTime) feeCalc = &fees.Calculator{ @@ -463,7 +463,7 @@ func (b *builder) NewCreateSubnetTx( var ( pBuilder, pSigner = b.builders(keys) chainTime = b.state.GetTimestamp() - feeCfg = b.cfg.GetDynamicFeesConfig(chainTime) + feeCfg = config.GetDynamicFeesConfig(b.cfg.IsEActivated(chainTime)) isEUpgradeActive = b.cfg.IsEActivated(chainTime) feeCalc = &fees.Calculator{ @@ -528,7 +528,7 @@ func (b *builder) NewTransformSubnetTx( var ( pBuilder, pSigner = b.builders(keys) chainTime = b.state.GetTimestamp() - feeCfg = b.cfg.GetDynamicFeesConfig(chainTime) + feeCfg = config.GetDynamicFeesConfig(b.cfg.IsEActivated(chainTime)) isEUpgradeActive = b.cfg.IsEActivated(chainTime) feeCalc = &fees.Calculator{ @@ -592,7 +592,7 @@ func (b *builder) NewAddValidatorTx( var ( pBuilder, pSigner = b.builders(keys) chainTime = b.state.GetTimestamp() - feeCfg = b.cfg.GetDynamicFeesConfig(chainTime) + feeCfg = config.GetDynamicFeesConfig(b.cfg.IsEActivated(chainTime)) isEUpgradeActive = b.cfg.IsEActivated(chainTime) feeCalc = &fees.Calculator{ @@ -658,7 +658,7 @@ func (b *builder) NewAddPermissionlessValidatorTx( var ( pBuilder, pSigner = b.builders(keys) chainTime = b.state.GetTimestamp() - feeCfg = b.cfg.GetDynamicFeesConfig(chainTime) + feeCfg = config.GetDynamicFeesConfig(b.cfg.IsEActivated(chainTime)) isEUpgradeActive = b.cfg.IsEActivated(chainTime) feeCalc = &fees.Calculator{ @@ -728,7 +728,7 @@ func (b *builder) NewAddDelegatorTx( var ( pBuilder, pSigner = b.builders(keys) chainTime = b.state.GetTimestamp() - feeCfg = b.cfg.GetDynamicFeesConfig(chainTime) + feeCfg = config.GetDynamicFeesConfig(b.cfg.IsEActivated(chainTime)) isEUpgradeActive = b.cfg.IsEActivated(chainTime) feeCalc = &fees.Calculator{ @@ -791,7 +791,7 @@ func (b *builder) NewAddPermissionlessDelegatorTx( var ( pBuilder, pSigner = b.builders(keys) chainTime = b.state.GetTimestamp() - feeCfg = b.cfg.GetDynamicFeesConfig(chainTime) + feeCfg = config.GetDynamicFeesConfig(b.cfg.IsEActivated(chainTime)) isEUpgradeActive = b.cfg.IsEActivated(chainTime) feeCalc = &fees.Calculator{ @@ -858,7 +858,7 @@ func (b *builder) NewAddSubnetValidatorTx( var ( pBuilder, pSigner = b.builders(keys) chainTime = b.state.GetTimestamp() - feeCfg = b.cfg.GetDynamicFeesConfig(chainTime) + feeCfg = config.GetDynamicFeesConfig(b.cfg.IsEActivated(chainTime)) isEUpgradeActive = b.cfg.IsEActivated(chainTime) feeCalc = &fees.Calculator{ @@ -915,7 +915,7 @@ func (b *builder) NewRemoveSubnetValidatorTx( var ( pBuilder, pSigner = b.builders(keys) chainTime = b.state.GetTimestamp() - feeCfg = b.cfg.GetDynamicFeesConfig(chainTime) + feeCfg = config.GetDynamicFeesConfig(b.cfg.IsEActivated(chainTime)) isEUpgradeActive = b.cfg.IsEActivated(chainTime) feeCalc = &fees.Calculator{ @@ -964,7 +964,7 @@ func (b *builder) NewTransferSubnetOwnershipTx( var ( pBuilder, pSigner = b.builders(keys) chainTime = b.state.GetTimestamp() - feeCfg = b.cfg.GetDynamicFeesConfig(chainTime) + feeCfg = config.GetDynamicFeesConfig(b.cfg.IsEActivated(chainTime)) isEUpgradeActive = b.cfg.IsEActivated(chainTime) feeCalc = &fees.Calculator{ @@ -1018,7 +1018,7 @@ func (b *builder) NewBaseTx( var ( pBuilder, pSigner = b.builders(keys) chainTime = b.state.GetTimestamp() - feeCfg = b.cfg.GetDynamicFeesConfig(chainTime) + feeCfg = config.GetDynamicFeesConfig(b.cfg.IsEActivated(chainTime)) isEUpgradeActive = b.cfg.IsEActivated(chainTime) feeCalc = &fees.Calculator{ diff --git a/vms/platformvm/txs/executor/atomic_tx_executor.go b/vms/platformvm/txs/executor/atomic_tx_executor.go index 22a58e20b0fc..08f7af5ef853 100644 --- a/vms/platformvm/txs/executor/atomic_tx_executor.go +++ b/vms/platformvm/txs/executor/atomic_tx_executor.go @@ -101,7 +101,7 @@ func (e *AtomicTxExecutor) atomicTx(tx txs.UnsignedTx) error { } e.OnAccept = onAccept - feesCfg := config.PreEUpgradeDynamicFeesConfig + feesCfg := config.GetDynamicFeesConfig(false /*isEActive*/) executor := StandardTxExecutor{ Backend: e.Backend, BlkFeeManager: commonfees.NewManager(commonfees.Empty, commonfees.EmptyWindows), diff --git a/vms/platformvm/txs/executor/create_chain_test.go b/vms/platformvm/txs/executor/create_chain_test.go index 5a2a6c73d05e..a821f7bf4b70 100644 --- a/vms/platformvm/txs/executor/create_chain_test.go +++ b/vms/platformvm/txs/executor/create_chain_test.go @@ -17,6 +17,7 @@ import ( "github.com/ava-labs/avalanchego/utils/hashing" "github.com/ava-labs/avalanchego/utils/set" "github.com/ava-labs/avalanchego/utils/units" + "github.com/ava-labs/avalanchego/vms/platformvm/config" "github.com/ava-labs/avalanchego/vms/platformvm/state" "github.com/ava-labs/avalanchego/vms/platformvm/txs" "github.com/ava-labs/avalanchego/vms/platformvm/txs/builder" @@ -53,7 +54,8 @@ func TestCreateChainTxInsufficientControlSigs(t *testing.T) { stateDiff, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCfg := env.config.GetDynamicFeesConfig(env.state.GetTimestamp()) + chainTime := env.state.GetTimestamp() + feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: commonfees.NewManager(feeCfg.InitialUnitFees, commonfees.EmptyWindows), @@ -96,7 +98,8 @@ func TestCreateChainTxWrongControlSig(t *testing.T) { stateDiff, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCfg := env.config.GetDynamicFeesConfig(stateDiff.GetTimestamp()) + chainTime := stateDiff.GetTimestamp() + feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: commonfees.NewManager(feeCfg.InitialUnitFees, commonfees.EmptyWindows), @@ -139,7 +142,8 @@ func TestCreateChainTxNoSuchSubnet(t *testing.T) { unitWindows, err := env.state.GetFeeWindows() require.NoError(err) - feeCfg := env.config.GetDynamicFeesConfig(stateDiff.GetTimestamp()) + currentTime := stateDiff.GetTimestamp() + feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(currentTime)) executor := StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: commonfees.NewManager(unitFees, unitWindows), @@ -179,7 +183,8 @@ func TestCreateChainTxValid(t *testing.T) { unitWindows, err := env.state.GetFeeWindows() require.NoError(err) - feeCfg := env.config.GetDynamicFeesConfig(stateDiff.GetTimestamp()) + currentTime := stateDiff.GetTimestamp() + feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(currentTime)) executor := StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: commonfees.NewManager(unitFees, unitWindows), @@ -235,10 +240,11 @@ func TestCreateChainTxAP3FeeChange(t *testing.T) { cfg.CreateBlockchainTxFee = test.fee var ( - backend = builder.NewBackend(env.ctx, &cfg, env.state, env.atomicUTXOs) - pBuilder = backends.NewBuilder(addrs, backend) - feeCfg = cfg.GetDynamicFeesConfig(env.state.GetTimestamp()) - feeCalc = &fees.Calculator{ + backend = builder.NewBackend(env.ctx, &cfg, env.state, env.atomicUTXOs) + pBuilder = backends.NewBuilder(addrs, backend) + chainTime = env.state.GetTimestamp() + feeCfg = config.GetDynamicFeesConfig(cfg.IsEActivated(chainTime)) + feeCalc = &fees.Calculator{ IsEUpgradeActive: false, Config: &cfg, ChainTime: test.time, @@ -268,7 +274,8 @@ func TestCreateChainTxAP3FeeChange(t *testing.T) { stateDiff.SetTimestamp(test.time) - feeCfg = env.config.GetDynamicFeesConfig(stateDiff.GetTimestamp()) + currentTime := stateDiff.GetTimestamp() + feeCfg = config.GetDynamicFeesConfig(env.config.IsEActivated(currentTime)) executor := StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: commonfees.NewManager(feeCfg.InitialUnitFees, commonfees.EmptyWindows), diff --git a/vms/platformvm/txs/executor/create_subnet_test.go b/vms/platformvm/txs/executor/create_subnet_test.go index 47a20acbcc7b..ba3f36584f62 100644 --- a/vms/platformvm/txs/executor/create_subnet_test.go +++ b/vms/platformvm/txs/executor/create_subnet_test.go @@ -13,6 +13,7 @@ import ( "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils/set" "github.com/ava-labs/avalanchego/utils/units" + "github.com/ava-labs/avalanchego/vms/platformvm/config" "github.com/ava-labs/avalanchego/vms/platformvm/state" "github.com/ava-labs/avalanchego/vms/platformvm/txs/builder" "github.com/ava-labs/avalanchego/vms/platformvm/txs/fees" @@ -69,10 +70,11 @@ func TestCreateSubnetTxAP3FeeChange(t *testing.T) { cfg := *env.config cfg.CreateSubnetTxFee = test.fee var ( - backend = builder.NewBackend(env.ctx, &cfg, env.state, env.atomicUTXOs) - pBuilder = backends.NewBuilder(addrs, backend) - feeCfg = cfg.GetDynamicFeesConfig(env.state.GetTimestamp()) - feeCalc = &fees.Calculator{ + backend = builder.NewBackend(env.ctx, &cfg, env.state, env.atomicUTXOs) + pBuilder = backends.NewBuilder(addrs, backend) + chainTime = env.state.GetTimestamp() + feeCfg = config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) + feeCalc = &fees.Calculator{ IsEUpgradeActive: false, Config: &cfg, ChainTime: test.time, @@ -100,7 +102,8 @@ func TestCreateSubnetTxAP3FeeChange(t *testing.T) { stateDiff.SetTimestamp(test.time) - feeCfg = env.config.GetDynamicFeesConfig(stateDiff.GetTimestamp()) + chainTime = stateDiff.GetTimestamp() + feeCfg = config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: commonfees.NewManager(feeCfg.InitialUnitFees, commonfees.EmptyWindows), diff --git a/vms/platformvm/txs/executor/helpers_test.go b/vms/platformvm/txs/executor/helpers_test.go index 193f089dfd39..dd3b8ca99c66 100644 --- a/vms/platformvm/txs/executor/helpers_test.go +++ b/vms/platformvm/txs/executor/helpers_test.go @@ -241,7 +241,8 @@ func addSubnet( unitWindows, err := env.state.GetFeeWindows() require.NoError(err) - feeCfg := env.config.GetDynamicFeesConfig(env.state.GetTimestamp()) + chainTime := env.state.GetTimestamp() + feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: fees.NewManager(unitFees, unitWindows), diff --git a/vms/platformvm/txs/executor/standard_tx_executor_test.go b/vms/platformvm/txs/executor/standard_tx_executor_test.go index 28a7b72306cb..ee008e91f701 100644 --- a/vms/platformvm/txs/executor/standard_tx_executor_test.go +++ b/vms/platformvm/txs/executor/standard_tx_executor_test.go @@ -89,7 +89,8 @@ func TestStandardTxExecutorAddValidatorTxEmptyID(t *testing.T) { stateDiff, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCfg := env.config.GetDynamicFeesConfig(env.state.GetTimestamp()) + chainTime := env.state.GetTimestamp() + feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: fees.NewManager(feeCfg.InitialUnitFees, fees.EmptyWindows), @@ -339,7 +340,8 @@ func TestStandardTxExecutorAddDelegator(t *testing.T) { freshTH.config.BanffTime = onAcceptState.GetTimestamp() - feeCfg := freshTH.config.GetDynamicFeesConfig(freshTH.state.GetTimestamp()) + chainTime := freshTH.state.GetTimestamp() + feeCfg := config.GetDynamicFeesConfig(freshTH.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ Backend: &freshTH.backend, BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), @@ -381,7 +383,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { onAcceptState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCfg := env.config.GetDynamicFeesConfig(env.state.GetTimestamp()) + chainTime := env.state.GetTimestamp() + feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), @@ -413,7 +416,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { onAcceptState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCfg := env.config.GetDynamicFeesConfig(env.state.GetTimestamp()) + chainTime := env.state.GetTimestamp() + feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), @@ -460,7 +464,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { onAcceptState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCfg := env.config.GetDynamicFeesConfig(env.state.GetTimestamp()) + chainTime := env.state.GetTimestamp() + feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), @@ -507,7 +512,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { onAcceptState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCfg := env.config.GetDynamicFeesConfig(env.state.GetTimestamp()) + chainTime := env.state.GetTimestamp() + feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), @@ -537,7 +543,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { onAcceptState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCfg := env.config.GetDynamicFeesConfig(env.state.GetTimestamp()) + chainTime := env.state.GetTimestamp() + feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), @@ -567,7 +574,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { onAcceptState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCfg := env.config.GetDynamicFeesConfig(env.state.GetTimestamp()) + chainTime := env.state.GetTimestamp() + feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), @@ -599,7 +607,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { onAcceptState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCfg := env.config.GetDynamicFeesConfig(env.state.GetTimestamp()) + chainTime := env.state.GetTimestamp() + feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), @@ -660,7 +669,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { onAcceptState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCfg := env.config.GetDynamicFeesConfig(env.state.GetTimestamp()) + chainTime := env.state.GetTimestamp() + feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), @@ -701,7 +711,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { onAcceptState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCfg := env.config.GetDynamicFeesConfig(env.state.GetTimestamp()) + chainTime := env.state.GetTimestamp() + feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), @@ -738,7 +749,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { onAcceptState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCfg := env.config.GetDynamicFeesConfig(env.state.GetTimestamp()) + chainTime := env.state.GetTimestamp() + feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), @@ -773,7 +785,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { onAcceptState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCfg := env.config.GetDynamicFeesConfig(env.state.GetTimestamp()) + chainTime := env.state.GetTimestamp() + feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), @@ -818,7 +831,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { onAcceptState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCfg := env.config.GetDynamicFeesConfig(env.state.GetTimestamp()) + chainTime := env.state.GetTimestamp() + feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), @@ -857,7 +871,8 @@ func TestBanffStandardTxExecutorAddValidator(t *testing.T) { onAcceptState, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeCfg := env.config.GetDynamicFeesConfig(env.state.GetTimestamp()) + chainTime := env.state.GetTimestamp() + feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), @@ -900,7 +915,8 @@ func TestBanffStandardTxExecutorAddValidator(t *testing.T) { onAcceptState.PutCurrentValidator(staker) onAcceptState.AddTx(tx, status.Committed) - feeCfg := env.config.GetDynamicFeesConfig(env.state.GetTimestamp()) + chainTime := env.state.GetTimestamp() + feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), @@ -940,7 +956,8 @@ func TestBanffStandardTxExecutorAddValidator(t *testing.T) { onAcceptState.PutPendingValidator(staker) onAcceptState.AddTx(tx, status.Committed) - feeCfg := env.config.GetDynamicFeesConfig(env.state.GetTimestamp()) + chainTime := env.state.GetTimestamp() + feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), @@ -979,7 +996,8 @@ func TestBanffStandardTxExecutorAddValidator(t *testing.T) { onAcceptState.DeleteUTXO(utxoID) } - feeCfg := env.config.GetDynamicFeesConfig(env.state.GetTimestamp()) + chainTime := env.state.GetTimestamp() + feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ Backend: &env.backend, BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), @@ -1559,7 +1577,8 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { env.state.EXPECT().AddUTXO(gomock.Any()).Times(len(env.unsignedTx.Outs)) cfg := defaultTestConfig(t, durango, env.latestForkTime) - feeCfg := cfg.GetDynamicFeesConfig(env.state.GetTimestamp()) + chainTime := env.state.GetTimestamp() + feeCfg := config.GetDynamicFeesConfig(cfg.IsEActivated(chainTime)) e := &StandardTxExecutor{ Backend: &Backend{ Config: defaultTestConfig(t, durango, env.latestForkTime), @@ -1586,8 +1605,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { env.tx.Unsigned.(*txs.RemoveSubnetValidatorTx).Subnet = constants.PrimaryNetworkID env.state = state.NewMockDiff(ctrl) - cfg := defaultTestConfig(t, durango, env.latestForkTime) - feeCfg := cfg.GetDynamicFeesConfig(time.Time{}) // pre E upgrade + feeCfg := config.GetDynamicFeesConfig(false /*isEActive*/) e := &StandardTxExecutor{ Backend: &Backend{ Config: defaultTestConfig(t, durango, env.latestForkTime), @@ -1616,7 +1634,8 @@ 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) - feeCfg := cfg.GetDynamicFeesConfig(env.state.GetTimestamp()) + chainTime := env.state.GetTimestamp() + feeCfg := config.GetDynamicFeesConfig(cfg.IsEActivated(chainTime)) e := &StandardTxExecutor{ Backend: &Backend{ Config: defaultTestConfig(t, durango, env.latestForkTime), @@ -1648,7 +1667,8 @@ 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) - feeCfg := cfg.GetDynamicFeesConfig(env.state.GetTimestamp()) + chainTime := env.state.GetTimestamp() + feeCfg := config.GetDynamicFeesConfig(cfg.IsEActivated(chainTime)) e := &StandardTxExecutor{ Backend: &Backend{ Config: defaultTestConfig(t, durango, env.latestForkTime), @@ -1678,7 +1698,8 @@ 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) - feeCfg := cfg.GetDynamicFeesConfig(env.state.GetTimestamp()) + chainTime := env.state.GetTimestamp() + feeCfg := config.GetDynamicFeesConfig(cfg.IsEActivated(chainTime)) e := &StandardTxExecutor{ Backend: &Backend{ Config: defaultTestConfig(t, durango, env.latestForkTime), @@ -1707,7 +1728,8 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { env.state.EXPECT().GetSubnetOwner(env.unsignedTx.Subnet).Return(nil, database.ErrNotFound) cfg := defaultTestConfig(t, durango, env.latestForkTime) - feeCfg := cfg.GetDynamicFeesConfig(env.state.GetTimestamp()) + chainTime := env.state.GetTimestamp() + feeCfg := config.GetDynamicFeesConfig(cfg.IsEActivated(chainTime)) e := &StandardTxExecutor{ Backend: &Backend{ Config: defaultTestConfig(t, durango, env.latestForkTime), @@ -1738,7 +1760,8 @@ 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) - feeCfg := cfg.GetDynamicFeesConfig(env.state.GetTimestamp()) + chainTime := env.state.GetTimestamp() + feeCfg := config.GetDynamicFeesConfig(cfg.IsEActivated(chainTime)) e := &StandardTxExecutor{ Backend: &Backend{ Config: defaultTestConfig(t, durango, env.latestForkTime), @@ -1772,7 +1795,8 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { ).Return(errTest) cfg := defaultTestConfig(t, durango, env.latestForkTime) - feeCfg := cfg.GetDynamicFeesConfig(env.state.GetTimestamp()) + chainTime := env.state.GetTimestamp() + feeCfg := config.GetDynamicFeesConfig(cfg.IsEActivated(chainTime)) e := &StandardTxExecutor{ Backend: &Backend{ Config: defaultTestConfig(t, durango, env.latestForkTime), @@ -1929,8 +1953,7 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { env.tx.Unsigned = (*txs.TransformSubnetTx)(nil) env.state = state.NewMockDiff(ctrl) - cfg := defaultTestConfig(t, durango, env.latestForkTime) - feeCfg := cfg.GetDynamicFeesConfig(time.Time{}) // pre E-upgrade + feeCfg := config.GetDynamicFeesConfig(false /*isEActive*/) e := &StandardTxExecutor{ Backend: &Backend{ Config: defaultTestConfig(t, durango, env.latestForkTime), @@ -1958,7 +1981,8 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { cfg := defaultTestConfig(t, durango, env.latestForkTime) env.state.EXPECT().GetTimestamp().Return(env.latestForkTime).AnyTimes() - feeCfg := cfg.GetDynamicFeesConfig(env.state.GetTimestamp()) + chainTime := env.state.GetTimestamp() + feeCfg := config.GetDynamicFeesConfig(cfg.IsEActivated(chainTime)) e := &StandardTxExecutor{ Backend: &Backend{ Config: defaultTestConfig(t, durango, env.latestForkTime), @@ -1988,7 +2012,8 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { cfg := defaultTestConfig(t, durango, env.latestForkTime) cfg.MaxStakeDuration = math.MaxInt64 env.state.EXPECT().GetTimestamp().Return(env.latestForkTime).AnyTimes() - feeCfg := cfg.GetDynamicFeesConfig(env.state.GetTimestamp()) + chainTime := env.state.GetTimestamp() + feeCfg := config.GetDynamicFeesConfig(cfg.IsEActivated(chainTime)) e := &StandardTxExecutor{ Backend: &Backend{ Config: cfg, @@ -2023,7 +2048,8 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { cfg := defaultTestConfig(t, durango, env.latestForkTime) cfg.MaxStakeDuration = math.MaxInt64 - feeCfg := cfg.GetDynamicFeesConfig(env.state.GetTimestamp()) + chainTime := env.state.GetTimestamp() + feeCfg := config.GetDynamicFeesConfig(cfg.IsEActivated(chainTime)) e := &StandardTxExecutor{ Backend: &Backend{ Config: cfg, @@ -2063,7 +2089,8 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { cfg := defaultTestConfig(t, durango, env.latestForkTime) cfg.MaxStakeDuration = math.MaxInt64 - feeCfg := cfg.GetDynamicFeesConfig(env.state.GetTimestamp()) + chainTime := env.state.GetTimestamp() + feeCfg := config.GetDynamicFeesConfig(cfg.IsEActivated(chainTime)) e := &StandardTxExecutor{ Backend: &Backend{ Config: cfg, diff --git a/vms/platformvm/vm_test.go b/vms/platformvm/vm_test.go index 09c3110441f7..80e3acd1ad57 100644 --- a/vms/platformvm/vm_test.go +++ b/vms/platformvm/vm_test.go @@ -383,7 +383,7 @@ func TestGenesis(t *testing.T) { // As such we need to account for the subnet creation fee var ( chainTime = vm.state.GetTimestamp() - feeCfg = vm.Config.GetDynamicFeesConfig(chainTime) + feeCfg = config.GetDynamicFeesConfig(vm.Config.IsEActivated(chainTime)) feeMan = commonfees.NewManager(unitFees, feeWindows) feeCalc = &fees.Calculator{ IsEUpgradeActive: vm.IsEActivated(chainTime), @@ -2283,7 +2283,7 @@ func TestBaseTx(t *testing.T) { var ( chainTime = vm.state.GetTimestamp() - feeCfg = vm.Config.GetDynamicFeesConfig(chainTime) + feeCfg = config.GetDynamicFeesConfig(vm.Config.IsEActivated(chainTime)) feeMan = commonfees.NewManager(unitFees, feeWindows) feeCalc = &fees.Calculator{ IsEUpgradeActive: vm.IsEActivated(chainTime), diff --git a/wallet/chain/p/wallet.go b/wallet/chain/p/wallet.go index ffe9b04cad7b..54064aff1484 100644 --- a/wallet/chain/p/wallet.go +++ b/wallet/chain/p/wallet.go @@ -757,10 +757,7 @@ func (w *wallet) refreshFeesData(options ...common.Option) error { return err } - if w.isEForkActive { - w.unitCaps = config.EUpgradeDynamicFeesConfig.BlockUnitsCap - } else { - w.unitCaps = config.PreEUpgradeDynamicFeesConfig.BlockUnitsCap - } + feeCfg := config.GetDynamicFeesConfig(w.isEForkActive) + w.unitCaps = feeCfg.BlockUnitsCap return nil } From 915ac05600f4048ab5dd6269f1997711e04f2d7e Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 11 Mar 2024 22:28:26 +0100 Subject: [PATCH 119/190] wip: added custom dynamic fees config --- vms/platformvm/config/dynamic_fees_config.go | 32 +++++++++++++++----- vms/platformvm/config/execution_config.go | 2 ++ vms/platformvm/vm.go | 6 +++- 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/vms/platformvm/config/dynamic_fees_config.go b/vms/platformvm/config/dynamic_fees_config.go index 4bb115a29122..399cb94a4bb0 100644 --- a/vms/platformvm/config/dynamic_fees_config.go +++ b/vms/platformvm/config/dynamic_fees_config.go @@ -6,19 +6,20 @@ package config import ( "fmt" + "github.com/ava-labs/avalanchego/snow" + "github.com/ava-labs/avalanchego/utils/constants" "github.com/ava-labs/avalanchego/utils/units" commonfees "github.com/ava-labs/avalanchego/vms/components/fees" ) -// Dynamic fees configs become relevant with dynamic fees introduction in E-fork -// We cannot easily include then in Config since they do not come from genesis -// They don't feel like an execution config either, since we need a fork upgrade -// to update them (testing is a different story). -// I am setting them in a separate config object, but will access it via Config -// so to have fork control over which dynamic fees is picked - func init() { + if customDynamicFeesConfig != nil { + if err := customDynamicFeesConfig.validate(); err != nil { + panic(err) + } + } + if err := eUpgradeDynamicFeesConfig.validate(); err != nil { panic(err) } @@ -49,6 +50,8 @@ var ( InitialUnitFees: commonfees.Empty, BlockUnitsCap: commonfees.Max, } + + customDynamicFeesConfig *DynamicFeesConfig ) func GetDynamicFeesConfig(isEActive bool) DynamicFeesConfig { @@ -56,9 +59,24 @@ func GetDynamicFeesConfig(isEActive bool) DynamicFeesConfig { return preEUpgradeDynamicFeesConfig } + if customDynamicFeesConfig != nil { + return *customDynamicFeesConfig + } return eUpgradeDynamicFeesConfig } +func ResetDynamicFeesConfig(ctx *snow.Context, customFeesConfig *DynamicFeesConfig) error { + if customFeesConfig == nil { + return nil // nothing to do + } + if ctx.NetworkID == constants.MainnetID || ctx.NetworkID == constants.FujiID { + return fmt.Errorf("forbidden resetting dynamic unit fees config for network %s", constants.NetworkName(ctx.NetworkID)) + } + + customDynamicFeesConfig = customFeesConfig + return nil +} + type DynamicFeesConfig struct { // InitialUnitFees contains, per each fee dimension, the // unit fees valid as soon as fork introducing dynamic fees diff --git a/vms/platformvm/config/execution_config.go b/vms/platformvm/config/execution_config.go index e182758e0c50..4e4e8f8f0ccb 100644 --- a/vms/platformvm/config/execution_config.go +++ b/vms/platformvm/config/execution_config.go @@ -38,6 +38,8 @@ type ExecutionConfig struct { FxOwnerCacheSize int `json:"fx-owner-cache-size"` ChecksumsEnabled bool `json:"checksums-enabled"` MempoolPruneFrequency time.Duration `json:"mempool-prune-frequency"` + + DynamicFeesConfig *DynamicFeesConfig `json:"dynamic-fees-config"` } // GetExecutionConfig returns an ExecutionConfig diff --git a/vms/platformvm/vm.go b/vms/platformvm/vm.go index cd414ca3330b..69819fd8a91a 100644 --- a/vms/platformvm/vm.go +++ b/vms/platformvm/vm.go @@ -113,7 +113,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 := config.ResetDynamicFeesConfig(chainCtx, execConfig.DynamicFeesConfig); err != nil { + return fmt.Errorf("failed resetting dynamic fees config: %w", err) + } registerer := prometheus.NewRegistry() if err := chainCtx.Metrics.Register(registerer); err != nil { From 90b095b2166bf4bd73441aa60c8292a5ebd59556 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Tue, 12 Mar 2024 16:21:47 +0100 Subject: [PATCH 120/190] wip: fixed dynamic fee config loading --- vms/platformvm/config/dynamic_fees_config.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/vms/platformvm/config/dynamic_fees_config.go b/vms/platformvm/config/dynamic_fees_config.go index 399cb94a4bb0..ede5e2f3163e 100644 --- a/vms/platformvm/config/dynamic_fees_config.go +++ b/vms/platformvm/config/dynamic_fees_config.go @@ -81,25 +81,25 @@ type DynamicFeesConfig struct { // InitialUnitFees contains, per each fee dimension, the // unit fees valid as soon as fork introducing dynamic fees // activates. Unit fees will be then updated by the dynamic fees algo. - InitialUnitFees commonfees.Dimensions + InitialUnitFees commonfees.Dimensions `json:"initial-unit-fees"` // MinUnitFees contains, per each fee dimension, the // minimal unit fees enforced by the dynamic fees algo. - MinUnitFees commonfees.Dimensions + MinUnitFees commonfees.Dimensions `json:"min-unit-fees"` // UpdateCoefficient contains, per each fee dimension, the // exponential update coefficient. Setting an entry to 0 makes // the corresponding fee rate constant. - UpdateCoefficient commonfees.Dimensions + UpdateCoefficient commonfees.Dimensions `json:"update-coefficient"` // BlockUnitsCap contains, per each fee dimension, the // maximal complexity a valid P-chain block can host - BlockUnitsCap commonfees.Dimensions + BlockUnitsCap commonfees.Dimensions `json:"block-unit-caps"` // BlockUnitsTarget contains, per each fee dimension, the // preferred block complexity that the dynamic fee algo // strive to converge to - BlockUnitsTarget commonfees.Dimensions + BlockUnitsTarget commonfees.Dimensions `json:"block-target-caps"` } func (c *DynamicFeesConfig) validate() error { From 377967f9365add82ef63c55641ff81c940b7c326 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 14 Mar 2024 10:13:29 +0100 Subject: [PATCH 121/190] fixed fee windows update --- vms/components/fees/manager.go | 61 +++++--------- vms/components/fees/manager_test.go | 87 ++++++++++++-------- vms/platformvm/block/builder/builder.go | 2 +- vms/platformvm/block/executor/manager.go | 2 +- vms/platformvm/block/executor/verifier.go | 3 +- vms/platformvm/config/dynamic_fees_config.go | 3 + 6 files changed, 78 insertions(+), 80 deletions(-) diff --git a/vms/components/fees/manager.go b/vms/components/fees/manager.go index 27a6cc049e76..f9dd80d43d14 100644 --- a/vms/components/fees/manager.go +++ b/vms/components/fees/manager.go @@ -100,55 +100,34 @@ func (m *Manager) RemoveUnits(unitsToRm Dimensions) error { return nil } -func (m *Manager) ComputeNext( +// [UpdateWindows] stores in the fee windows the units cumulated in current block +func (m *Manager) UpdateWindows(lastTime, currTime int64) { + var ( + since = int(currTime - lastTime) + latestIdx = WindowSize - 1 + ) + + for i := Dimension(0); i < FeeDimensions; i++ { + m.windows[i] = Roll(m.windows[i], since) + Update(&m.windows[i], latestIdx, m.cumulatedUnits[i]) + } +} + +func (m *Manager) UpdateUnitFees( lastTime, currTime int64, targetUnits, updateCoefficients, minUnitPrice Dimensions, -) *Manager { +) { since := int(currTime - lastTime) - nextManager := &Manager{} for i := Dimension(0); i < FeeDimensions; i++ { - nextUnitPrice, nextUnitWindow := computeNextPriceWindow( - m.windows[i], - m.cumulatedUnits[i], - m.unitFees[i], - targetUnits[i], - updateCoefficients[i], - minUnitPrice[i], - since, - ) - - nextManager.unitFees[i] = nextUnitPrice - nextManager.windows[i] = nextUnitWindow - // unit consumed are zeroed in nextManager + nextUnitWindow := Roll(m.windows[i], since) + totalUnitsConsumed := Sum(nextUnitWindow) + nextUnitFee := nextFeeRate(m.unitFees[i], updateCoefficients[i], totalUnitsConsumed, targetUnits[i]) + nextUnitFee = max(nextUnitFee, minUnitPrice[i]) + m.unitFees[i] = nextUnitFee } - return nextManager -} - -func computeNextPriceWindow( - current Window, - currentUnitsConsumed uint64, - currentUnitFee uint64, - target uint64, /* per window, must be non-zero */ - updateCoefficient uint64, - minUnitFee uint64, - since int, /* seconds */ -) (uint64, Window) { - newRollupWindow := Roll(current, since) - if since < WindowSize { - // add in the units used by the parent block in the correct place - // If the parent consumed units within the rollup window, add the consumed - // units in. - start := WindowSize - 1 - since - Update(&newRollupWindow, start, currentUnitsConsumed) - } - - totalUnitsConsumed := Sum(newRollupWindow) - nextUnitFee := nextFeeRate(currentUnitFee, updateCoefficient, totalUnitsConsumed, target) - nextUnitFee = max(nextUnitFee, minUnitFee) - return nextUnitFee, newRollupWindow } func nextFeeRate(currentUnitFee, updateCoefficient, unitsConsumed, target uint64) uint64 { diff --git a/vms/components/fees/manager_test.go b/vms/components/fees/manager_test.go index e5e1fc26c9c0..c4a8e9d28334 100644 --- a/vms/components/fees/manager_test.go +++ b/vms/components/fees/manager_test.go @@ -16,7 +16,7 @@ func TestComputeNextEmptyWindows(t *testing.T) { var ( initialUnitFees = Dimensions{1, 1, 1, 1} - consumedUnits = Dimensions{5, 25, 30, 2500} + consumedUnits = Dimensions{50, 100, 150, 2500} targetComplexity = Dimensions{25, 25, 25, 25} // last block happened within Window @@ -24,7 +24,7 @@ func TestComputeNextEmptyWindows(t *testing.T) { currBlkTime = lastBlkTime.Add(time.Second) updateCoefficient = Dimensions{1, 2, 5, 10} - minUnitFees = Dimensions{0, 0, 0, 0} + minUnitFees = Dimensions{1, 1, 1, 1} ) m := &Manager{ @@ -32,7 +32,7 @@ func TestComputeNextEmptyWindows(t *testing.T) { windows: [FeeDimensions]Window{}, cumulatedUnits: consumedUnits, } - next := m.ComputeNext( + m.UpdateUnitFees( lastBlkTime.Unix(), currBlkTime.Unix(), targetComplexity, @@ -41,19 +41,37 @@ func TestComputeNextEmptyWindows(t *testing.T) { ) // Bandwidth units are below target, next unit fees are pushed to the minimum - require.Equal(minUnitFees[Bandwidth], next.unitFees[Bandwidth]) + require.Equal(minUnitFees[Bandwidth], m.unitFees[Bandwidth]) // UTXORead units are at target, next unit fees are kept equal - require.Equal(initialUnitFees[UTXORead], next.unitFees[UTXORead]) + require.Equal(minUnitFees[UTXORead], m.unitFees[UTXORead]) // UTXOWrite units are above target, next unit fees increased - require.Equal(uint64(4), next.unitFees[UTXOWrite]) + require.Equal(minUnitFees[UTXOWrite], m.unitFees[UTXOWrite]) // Compute units are way above target, next unit fees are increased to the max - require.Equal(uint64(4*1<<60), next.unitFees[Compute]) + require.Equal(minUnitFees[Compute], m.unitFees[Compute]) + + m.UpdateWindows(lastBlkTime.Unix(), currBlkTime.Unix()) + m.UpdateUnitFees( + lastBlkTime.Unix(), + currBlkTime.Unix(), + targetComplexity, + updateCoefficient, + minUnitFees, + ) + + // Bandwidth units are below target, next unit fees are pushed to the minimum + require.Equal(uint64(4), m.unitFees[Bandwidth]) + + // UTXORead units are at target, next unit fees are kept equal + require.Equal(uint64(512), m.unitFees[UTXORead]) + + // UTXOWrite units are above target, next unit fees increased + require.Equal(uint64(0x2000000000), m.unitFees[UTXOWrite]) - // next cumulated units are zeroed - require.Equal(Dimensions{}, next.cumulatedUnits) + // Compute units are way above target, next unit fees are increased to the max + require.Equal(uint64(0x4000000000000000), m.unitFees[Compute]) } func TestComputeNextNonEmptyWindows(t *testing.T) { @@ -82,7 +100,7 @@ func TestComputeNextNonEmptyWindows(t *testing.T) { }, cumulatedUnits: consumedUnits, } - next := m.ComputeNext( + m.UpdateUnitFees( lastBlkTime.Unix(), currBlkTime.Unix(), targetComplexity, @@ -91,19 +109,16 @@ func TestComputeNextNonEmptyWindows(t *testing.T) { ) // Bandwidth units are below target, next unit fees are pushed to the minimum - require.Equal(minUnitFees[Bandwidth], next.unitFees[Bandwidth]) + require.Equal(minUnitFees[Bandwidth], m.unitFees[Bandwidth]) // UTXORead units are at above target, due to spike in window. Next unit fees are increased - require.Equal(uint64(4*1<<60), next.unitFees[UTXORead]) + require.Equal(uint64(4*1<<60), m.unitFees[UTXORead]) // UTXOWrite units are above target, even if they are decreasing within the window. Next unit fees increased. - require.Equal(uint64(2*1<<60), next.unitFees[UTXOWrite]) + require.Equal(uint64(2*1<<60), m.unitFees[UTXOWrite]) // Compute units are above target, next unit fees are increased. - require.Equal(uint64(4*1<<60), next.unitFees[Compute]) - - // next cumulated units are zeroed - require.Equal(Dimensions{}, next.cumulatedUnits) + require.Equal(uint64(4*1<<60), m.unitFees[Compute]) } func TestComputeNextEdgeCases(t *testing.T) { @@ -132,7 +147,8 @@ func TestComputeNextEdgeCases(t *testing.T) { }, cumulatedUnits: consumedUnits, } - next := m.ComputeNext( + + m.UpdateUnitFees( lastBlkTime.Unix(), currBlkTime.Unix(), targetComplexity, @@ -141,19 +157,16 @@ func TestComputeNextEdgeCases(t *testing.T) { ) // Bandwidth units are below target, next unit fees are pushed to the minimum - require.Equal(minUnitFees[Bandwidth], next.unitFees[Bandwidth]) + require.Equal(minUnitFees[Bandwidth], m.unitFees[Bandwidth]) // UTXORead units are at target, due to spike in window. Unit fees are kept unchanged. - require.Equal(initialUnitFees[UTXORead], next.unitFees[UTXORead]) + require.Equal(initialUnitFees[UTXORead], m.unitFees[UTXORead]) // UTXOWrite units are below target. Unit fees are decreased. - require.Equal(minUnitFees[UTXOWrite], next.unitFees[UTXOWrite]) + require.Equal(minUnitFees[UTXOWrite], m.unitFees[UTXOWrite]) // Compute units are below target. Unit fees are decreased. - require.Equal(minUnitFees[Compute], next.unitFees[Compute]) - - // next cumulated units are zeroed - require.Equal(Dimensions{}, next.cumulatedUnits) + require.Equal(minUnitFees[Compute], m.unitFees[Compute]) } func TestComputeNextStability(t *testing.T) { @@ -184,7 +197,8 @@ func TestComputeNextStability(t *testing.T) { windows: [FeeDimensions]Window{}, cumulatedUnits: consumedUnits1, } - next1 := m1.ComputeNext( + m1.UpdateWindows(lastBlkTime.Unix(), currBlkTime.Unix()) + m1.UpdateUnitFees( lastBlkTime.Unix(), currBlkTime.Unix(), targetComplexity, @@ -192,19 +206,20 @@ func TestComputeNextStability(t *testing.T) { minUnitFees, ) - require.Less(next1.unitFees[Bandwidth], initialUnitFees[Bandwidth]) - require.Less(next1.unitFees[UTXORead], initialUnitFees[UTXORead]) - require.Less(next1.unitFees[UTXOWrite], initialUnitFees[UTXOWrite]) - require.Less(next1.unitFees[Compute], initialUnitFees[Compute]) + require.Less(m1.unitFees[Bandwidth], initialUnitFees[Bandwidth]) + require.Less(m1.unitFees[UTXORead], initialUnitFees[UTXORead]) + require.Less(m1.unitFees[UTXOWrite], initialUnitFees[UTXOWrite]) + require.Less(m1.unitFees[Compute], initialUnitFees[Compute]) // step2: cumulated units go slight above target, so that average consumed units are at target. // Unit fees go back to the original value m2 := &Manager{ - unitFees: next1.unitFees, + unitFees: m1.unitFees, windows: [FeeDimensions]Window{}, cumulatedUnits: consumedUnits2, } - next2 := m2.ComputeNext( + m2.UpdateWindows(lastBlkTime.Unix(), currBlkTime.Unix()) + m2.UpdateUnitFees( lastBlkTime.Unix(), currBlkTime.Unix(), targetComplexity, @@ -212,8 +227,8 @@ func TestComputeNextStability(t *testing.T) { minUnitFees, ) - require.Equal(initialUnitFees[Bandwidth], next2.unitFees[Bandwidth]) - require.Equal(initialUnitFees[UTXORead], next2.unitFees[UTXORead]) - require.Equal(initialUnitFees[UTXOWrite], next2.unitFees[UTXOWrite]) - require.Equal(initialUnitFees[Compute], next2.unitFees[Compute]) + require.Equal(initialUnitFees[Bandwidth], m2.unitFees[Bandwidth]) + require.Equal(initialUnitFees[UTXORead], m2.unitFees[UTXORead]) + require.Equal(initialUnitFees[UTXOWrite], m2.unitFees[UTXOWrite]) + require.Equal(initialUnitFees[Compute], m2.unitFees[Compute]) } diff --git a/vms/platformvm/block/builder/builder.go b/vms/platformvm/block/builder/builder.go index 91cad709212e..4c32326b7ed2 100644 --- a/vms/platformvm/block/builder/builder.go +++ b/vms/platformvm/block/builder/builder.go @@ -352,7 +352,7 @@ func packBlockTxs( feeMan := commonfees.NewManager(unitFees, unitWindows) if isEActivated { - feeMan = feeMan.ComputeNext( + feeMan.UpdateUnitFees( parentState.GetTimestamp().Unix(), timestamp.Unix(), feesCfg.BlockUnitsTarget, diff --git a/vms/platformvm/block/executor/manager.go b/vms/platformvm/block/executor/manager.go index 77a0018da40f..dad8ecbb59e1 100644 --- a/vms/platformvm/block/executor/manager.go +++ b/vms/platformvm/block/executor/manager.go @@ -161,7 +161,7 @@ func (m *manager) VerifyTx(tx *txs.Tx) error { feeManager := fees.NewManager(unitFees, unitWindows) if isEActivated { - feeManager = feeManager.ComputeNext( + feeManager.UpdateUnitFees( chainTime.Unix(), nextBlkTime.Unix(), feesCfg.BlockUnitsTarget, diff --git a/vms/platformvm/block/executor/verifier.go b/vms/platformvm/block/executor/verifier.go index 6fa5486dbc68..2498e7c25029 100644 --- a/vms/platformvm/block/executor/verifier.go +++ b/vms/platformvm/block/executor/verifier.go @@ -470,7 +470,7 @@ func (v *verifier) processStandardTxs(txs []*txs.Tx, state state.Diff, parentID feeManager := fees.NewManager(unitFees, unitWindows) if isEActivated { - feeManager = feeManager.ComputeNext( + feeManager.UpdateUnitFees( currentTimestamp.Unix(), blkTimestamp.Unix(), feesCfg.BlockUnitsTarget, @@ -522,6 +522,7 @@ func (v *verifier) processStandardTxs(txs []*txs.Tx, state state.Diff, parentID } if isEActivated { + feeManager.UpdateWindows(currentTimestamp.Unix(), blkTimestamp.Unix()) state.SetUnitFees(feeManager.GetUnitFees()) state.SetFeeWindows(feeManager.GetFeeWindows()) } diff --git a/vms/platformvm/config/dynamic_fees_config.go b/vms/platformvm/config/dynamic_fees_config.go index ede5e2f3163e..55455d181edd 100644 --- a/vms/platformvm/config/dynamic_fees_config.go +++ b/vms/platformvm/config/dynamic_fees_config.go @@ -104,6 +104,9 @@ type DynamicFeesConfig struct { func (c *DynamicFeesConfig) validate() error { for i := commonfees.Dimension(0); i < commonfees.FeeDimensions; i++ { + // MinUnitFees can be zero, but that is a bit dangerous. if a fee ever becomes + // zero, the update mechanism will keep them to zero. + if c.InitialUnitFees[i] < c.MinUnitFees[i] { return fmt.Errorf("dimension %d, initial unit fee %d smaller than minimal unit fee %d", i, From 0cb4969cfc620525c13471c3cc4d969f9dc090ea Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 14 Mar 2024 16:45:27 +0100 Subject: [PATCH 122/190] refactored GetUnitFees api --- tests/e2e/p/workflow.go | 4 +-- vms/platformvm/client.go | 8 ++--- vms/platformvm/service.go | 55 ++++++++++++++++++++++++++++++---- vms/platformvm/service_test.go | 4 +-- wallet/chain/p/wallet.go | 2 +- 5 files changed, 59 insertions(+), 14 deletions(-) diff --git a/tests/e2e/p/workflow.go b/tests/e2e/p/workflow.go index c559e25cf5eb..c7bdd91af207 100644 --- a/tests/e2e/p/workflow.go +++ b/tests/e2e/p/workflow.go @@ -139,7 +139,7 @@ var _ = e2e.DescribePChain("[Workflow]", func() { ginkgo.By("export avax from P to X chain", func() { unitCaps := config.GetDynamicFeesConfig(true /*isEActive*/).BlockUnitsCap - unitFees, err := pChainClient.GetUnitFees(e2e.DefaultContext()) + _, nextUnitFees, err := pChainClient.GetUnitFees(e2e.DefaultContext()) require.NoError(err) feeWindows, err := pChainClient.GetFeeWindows(e2e.DefaultContext()) @@ -162,7 +162,7 @@ var _ = e2e.DescribePChain("[Workflow]", func() { // retrieve fees paid for the tx feeCalc := fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(unitFees, feeWindows), + FeeManager: commonfees.NewManager(nextUnitFees, feeWindows), ConsumedUnitsCap: unitCaps, Credentials: tx.Creds, } diff --git a/vms/platformvm/client.go b/vms/platformvm/client.go index 96a19d1c0edb..c0c8e8970263 100644 --- a/vms/platformvm/client.go +++ b/vms/platformvm/client.go @@ -134,8 +134,8 @@ type Client interface { // GetBlockByHeight returns the block at the given [height]. GetBlockByHeight(ctx context.Context, height uint64, options ...rpc.Option) ([]byte, error) - // GetUnitFees returns the current unit fees that a transaction must pay to be accepted - GetUnitFees(ctx context.Context, options ...rpc.Option) (commonfees.Dimensions, error) + // GetUnitFees returns the current unit fees and the next unit fees that a transaction must pay to be accepted + GetUnitFees(ctx context.Context, options ...rpc.Option) (commonfees.Dimensions, commonfees.Dimensions, error) // GetFeeWindows returns the fee window needed to calculate next block unit fees GetFeeWindows(ctx context.Context, options ...rpc.Option) (commonfees.Windows, error) @@ -554,10 +554,10 @@ func (c *client) GetBlockByHeight(ctx context.Context, height uint64, options .. return formatting.Decode(res.Encoding, res.Block) } -func (c *client) GetUnitFees(ctx context.Context, options ...rpc.Option) (commonfees.Dimensions, error) { +func (c *client) GetUnitFees(ctx context.Context, options ...rpc.Option) (commonfees.Dimensions, commonfees.Dimensions, error) { res := &GetUnitFeesReply{} err := c.requester.SendRequest(ctx, "platform.getUnitFees", struct{}{}, res, options...) - return res.UnitFees, err + return res.CurrentUnitFees, res.NextUnitFees, err } func (c *client) GetFeeWindows(ctx context.Context, options ...rpc.Option) (commonfees.Windows, error) { diff --git a/vms/platformvm/service.go b/vms/platformvm/service.go index 87e76103023b..09b5fafdc627 100644 --- a/vms/platformvm/service.go +++ b/vms/platformvm/service.go @@ -29,6 +29,7 @@ import ( "github.com/ava-labs/avalanchego/utils/set" "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/components/keystore" + "github.com/ava-labs/avalanchego/vms/platformvm/config" "github.com/ava-labs/avalanchego/vms/platformvm/fx" "github.com/ava-labs/avalanchego/vms/platformvm/reward" "github.com/ava-labs/avalanchego/vms/platformvm/signer" @@ -37,6 +38,7 @@ import ( "github.com/ava-labs/avalanchego/vms/platformvm/status" "github.com/ava-labs/avalanchego/vms/platformvm/txs" "github.com/ava-labs/avalanchego/vms/platformvm/txs/builder" + "github.com/ava-labs/avalanchego/vms/platformvm/txs/executor" "github.com/ava-labs/avalanchego/vms/secp256k1fx" avajson "github.com/ava-labs/avalanchego/utils/json" @@ -1821,8 +1823,8 @@ func (s *Service) GetBlockByHeight(_ *http.Request, args *api.GetBlockByHeightAr // GetUnitFeesReply is the response from GetUnitFees type GetUnitFeesReply struct { - // Current timestamp - UnitFees commonfees.Dimensions `json:"unitfees"` + CurrentUnitFees commonfees.Dimensions `json:"currentUnitFees"` + NextUnitFees commonfees.Dimensions `json:"nextUnitFees"` } // GetTimestamp returns the current timestamp on chain. @@ -1835,9 +1837,52 @@ func (s *Service) GetUnitFees(_ *http.Request, _ *struct{}, reply *GetUnitFeesRe s.vm.ctx.Lock.Lock() defer s.vm.ctx.Lock.Unlock() - var err error - reply.UnitFees, err = s.vm.state.GetUnitFees() - return err + preferredID := s.vm.manager.Preferred() + onAccept, ok := s.vm.manager.GetState(preferredID) + if !ok { + return fmt.Errorf("could not retrieve state for block %s", preferredID) + } + + currentUnitFees, err := onAccept.GetUnitFees() + if err != nil { + return err + } + reply.CurrentUnitFees = currentUnitFees + + nextTimestamp, _, err := executor.NextBlockTime(onAccept, &s.vm.clock) + if err != nil { + return fmt.Errorf("could not calculate next staker change time: %w", err) + } + isEActivated := s.vm.Config.IsEActivated(nextTimestamp) + + if !isEActivated { + reply.NextUnitFees = reply.CurrentUnitFees + return nil + } + + var ( + currentTimestamp = onAccept.GetTimestamp() + feesCfg = config.GetDynamicFeesConfig(isEActivated) + ) + + feeWindows, err := onAccept.GetFeeWindows() + if err != nil { + return err + } + + feeManager := commonfees.NewManager(currentUnitFees, feeWindows) + if isEActivated { + feeManager.UpdateUnitFees( + currentTimestamp.Unix(), + nextTimestamp.Unix(), + feesCfg.BlockUnitsTarget, + feesCfg.UpdateCoefficient, + feesCfg.MinUnitFees, + ) + } + reply.NextUnitFees = feeManager.GetUnitFees() + + return nil } // GetBlockUnitsCapReply is the response from GetBlockUnitsCap diff --git a/vms/platformvm/service_test.go b/vms/platformvm/service_test.go index 6259a5bccde8..3311f8b9fe1f 100644 --- a/vms/platformvm/service_test.go +++ b/vms/platformvm/service_test.go @@ -1018,7 +1018,7 @@ func TestGetUnitFees(t *testing.T) { unitFees, err := service.vm.state.GetUnitFees() require.NoError(err) - require.Equal(unitFees, reply.UnitFees) + require.Equal(unitFees, reply.CurrentUnitFees) updatedUnitFees := commonfees.Dimensions{ 123, @@ -1031,7 +1031,7 @@ func TestGetUnitFees(t *testing.T) { service.vm.ctx.Lock.Unlock() require.NoError(service.GetUnitFees(nil, nil, &reply)) - require.Equal(updatedUnitFees, reply.UnitFees) + require.Equal(updatedUnitFees, reply.CurrentUnitFees) } func TestGetFeeWindows(t *testing.T) { diff --git a/wallet/chain/p/wallet.go b/wallet/chain/p/wallet.go index 54064aff1484..241660dbc138 100644 --- a/wallet/chain/p/wallet.go +++ b/wallet/chain/p/wallet.go @@ -747,7 +747,7 @@ func (w *wallet) refreshFeesData(options ...common.Option) error { eUpgradeTime := version.GetEUpgradeTime(w.NetworkID()) w.isEForkActive = !chainTime.Before(eUpgradeTime) - w.unitFees, err = w.client.GetUnitFees(ctx) + _, w.unitFees, err = w.client.GetUnitFees(ctx) if err != nil { return err } From 5cfc639de51f8311fad8d981ee2f9c3897d61fc5 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 14 Mar 2024 18:00:08 +0100 Subject: [PATCH 123/190] consolidated fees config --- vms/components/fees/config.go | 60 +++++++++ vms/components/fees/manager.go | 8 +- vms/components/fees/manager_test.go | 121 +++++++++---------- vms/platformvm/block/builder/builder.go | 4 +- vms/platformvm/block/executor/manager.go | 4 +- vms/platformvm/block/executor/verifier.go | 4 +- vms/platformvm/config/dynamic_fees_config.go | 68 ++--------- vms/platformvm/config/execution_config.go | 4 +- vms/platformvm/service.go | 4 +- 9 files changed, 134 insertions(+), 143 deletions(-) create mode 100644 vms/components/fees/config.go diff --git a/vms/components/fees/config.go b/vms/components/fees/config.go new file mode 100644 index 000000000000..4009d8f816cb --- /dev/null +++ b/vms/components/fees/config.go @@ -0,0 +1,60 @@ +// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package fees + +import "fmt" + +type DynamicFeesConfig struct { + // InitialUnitFees contains, per each fee dimension, the + // unit fees valid as soon as fork introducing dynamic fees + // activates. Unit fees will be then updated by the dynamic fees algo. + InitialUnitFees Dimensions `json:"initial-unit-fees"` + + // MinUnitFees contains, per each fee dimension, the + // minimal unit fees enforced by the dynamic fees algo. + MinUnitFees Dimensions `json:"min-unit-fees"` + + // UpdateCoefficient contains, per each fee dimension, the + // exponential update coefficient. Setting an entry to 0 makes + // the corresponding fee rate constant. + UpdateCoefficient Dimensions `json:"update-coefficient"` + + // BlockUnitsCap contains, per each fee dimension, the + // maximal complexity a valid P-chain block can host + BlockUnitsCap Dimensions `json:"block-unit-caps"` + + // BlockUnitsTarget contains, per each fee dimension, the + // preferred block complexity that the dynamic fee algo + // strive to converge to + BlockUnitsTarget Dimensions `json:"block-target-caps"` +} + +func (c *DynamicFeesConfig) Validate() error { + for i := Dimension(0); i < FeeDimensions; i++ { + // MinUnitFees can be zero, but that is a bit dangerous. if a fee ever becomes + // zero, the update mechanism will keep them to zero. + + if c.InitialUnitFees[i] < c.MinUnitFees[i] { + return fmt.Errorf("dimension %d, initial unit fee %d smaller than minimal unit fee %d", + i, + c.InitialUnitFees[i], + c.MinUnitFees[i], + ) + } + + if c.BlockUnitsTarget[i] > c.BlockUnitsCap[i] { + return fmt.Errorf("dimension %d, block target units %d larger than block units cap %d", + i, + c.BlockUnitsTarget[i], + c.BlockUnitsCap[i], + ) + } + + if c.BlockUnitsTarget[i] == 0 { + return fmt.Errorf("dimension %d, block target units set to zero", i) + } + } + + return nil +} diff --git a/vms/components/fees/manager.go b/vms/components/fees/manager.go index f9dd80d43d14..1b838e0af622 100644 --- a/vms/components/fees/manager.go +++ b/vms/components/fees/manager.go @@ -116,16 +116,14 @@ func (m *Manager) UpdateWindows(lastTime, currTime int64) { func (m *Manager) UpdateUnitFees( lastTime, currTime int64, - targetUnits, - updateCoefficients, - minUnitPrice Dimensions, + feesConfig DynamicFeesConfig, ) { since := int(currTime - lastTime) for i := Dimension(0); i < FeeDimensions; i++ { nextUnitWindow := Roll(m.windows[i], since) totalUnitsConsumed := Sum(nextUnitWindow) - nextUnitFee := nextFeeRate(m.unitFees[i], updateCoefficients[i], totalUnitsConsumed, targetUnits[i]) - nextUnitFee = max(nextUnitFee, minUnitPrice[i]) + nextUnitFee := nextFeeRate(m.unitFees[i], feesConfig.UpdateCoefficient[i], totalUnitsConsumed, feesConfig.BlockUnitsTarget[i]) + nextUnitFee = max(nextUnitFee, feesConfig.MinUnitFees[i]) m.unitFees[i] = nextUnitFee } } diff --git a/vms/components/fees/manager_test.go b/vms/components/fees/manager_test.go index c4a8e9d28334..7a3f4e191f44 100644 --- a/vms/components/fees/manager_test.go +++ b/vms/components/fees/manager_test.go @@ -15,50 +15,47 @@ func TestComputeNextEmptyWindows(t *testing.T) { require := require.New(t) var ( - initialUnitFees = Dimensions{1, 1, 1, 1} - consumedUnits = Dimensions{50, 100, 150, 2500} - targetComplexity = Dimensions{25, 25, 25, 25} + feesCfg = DynamicFeesConfig{ + MinUnitFees: Dimensions{1, 1, 1, 1}, + UpdateCoefficient: Dimensions{1, 2, 5, 10}, + BlockUnitsTarget: Dimensions{25, 25, 25, 25}, + } + currentUnitFees = Dimensions{1, 1, 1, 1} + consumedUnits = Dimensions{50, 100, 150, 2500} // last block happened within Window lastBlkTime = time.Now().Truncate(time.Second) currBlkTime = lastBlkTime.Add(time.Second) - - updateCoefficient = Dimensions{1, 2, 5, 10} - minUnitFees = Dimensions{1, 1, 1, 1} ) m := &Manager{ - unitFees: initialUnitFees, + unitFees: currentUnitFees, windows: [FeeDimensions]Window{}, cumulatedUnits: consumedUnits, } m.UpdateUnitFees( lastBlkTime.Unix(), currBlkTime.Unix(), - targetComplexity, - updateCoefficient, - minUnitFees, + feesCfg, ) // Bandwidth units are below target, next unit fees are pushed to the minimum - require.Equal(minUnitFees[Bandwidth], m.unitFees[Bandwidth]) + require.Equal(feesCfg.MinUnitFees[Bandwidth], m.unitFees[Bandwidth]) // UTXORead units are at target, next unit fees are kept equal - require.Equal(minUnitFees[UTXORead], m.unitFees[UTXORead]) + require.Equal(feesCfg.MinUnitFees[UTXORead], m.unitFees[UTXORead]) // UTXOWrite units are above target, next unit fees increased - require.Equal(minUnitFees[UTXOWrite], m.unitFees[UTXOWrite]) + require.Equal(feesCfg.MinUnitFees[UTXOWrite], m.unitFees[UTXOWrite]) // Compute units are way above target, next unit fees are increased to the max - require.Equal(minUnitFees[Compute], m.unitFees[Compute]) + require.Equal(feesCfg.MinUnitFees[Compute], m.unitFees[Compute]) m.UpdateWindows(lastBlkTime.Unix(), currBlkTime.Unix()) m.UpdateUnitFees( lastBlkTime.Unix(), currBlkTime.Unix(), - targetComplexity, - updateCoefficient, - minUnitFees, + feesCfg, ) // Bandwidth units are below target, next unit fees are pushed to the minimum @@ -78,20 +75,21 @@ func TestComputeNextNonEmptyWindows(t *testing.T) { require := require.New(t) var ( - initialUnitFees = Dimensions{1, 1, 1, 1} - consumedUnits = Dimensions{0, 0, 0, 0} - targetComplexity = Dimensions{25, 25, 25, 25} + feesCfg = DynamicFeesConfig{ + MinUnitFees: Dimensions{0, 0, 0, 0}, + UpdateCoefficient: Dimensions{1, 2, 5, 10}, + BlockUnitsTarget: Dimensions{25, 25, 25, 25}, + } + currentUnitFees = Dimensions{1, 1, 1, 1} + consumedUnits = Dimensions{0, 0, 0, 0} // last block happened within Window lastBlkTime = time.Now().Truncate(time.Second) currBlkTime = lastBlkTime.Add(time.Second) - - updateCoefficient = Dimensions{1, 2, 5, 10} - minUnitFees = Dimensions{0, 0, 0, 0} ) m := &Manager{ - unitFees: initialUnitFees, + unitFees: currentUnitFees, windows: [FeeDimensions]Window{ {1, 1, 1, 2, 2, 3, 3, 4, 5, 0}, // increasing but overall below target {0, 0, math.MaxUint64, 0, 0, 0, 0, 0, 0, 0}, // spike within window @@ -103,13 +101,11 @@ func TestComputeNextNonEmptyWindows(t *testing.T) { m.UpdateUnitFees( lastBlkTime.Unix(), currBlkTime.Unix(), - targetComplexity, - updateCoefficient, - minUnitFees, + feesCfg, ) // Bandwidth units are below target, next unit fees are pushed to the minimum - require.Equal(minUnitFees[Bandwidth], m.unitFees[Bandwidth]) + require.Equal(feesCfg.MinUnitFees[Bandwidth], m.unitFees[Bandwidth]) // UTXORead units are at above target, due to spike in window. Next unit fees are increased require.Equal(uint64(4*1<<60), m.unitFees[UTXORead]) @@ -125,20 +121,21 @@ func TestComputeNextEdgeCases(t *testing.T) { require := require.New(t) var ( - initialUnitFees = Dimensions{1, 2, 2, 2} - consumedUnits = Dimensions{0, 0, 0, 0} - targetComplexity = Dimensions{math.MaxUint64, 1, 1, 1} // a very skewed requirement for block complexity + feesCfg = DynamicFeesConfig{ + MinUnitFees: Dimensions{1, 0, 0, 0}, + UpdateCoefficient: Dimensions{1, 1, 1, 1}, + BlockUnitsTarget: Dimensions{math.MaxUint64, 1, 1, 1}, // a very skewed requirement for block complexity + } + currentUnitFees = Dimensions{1, 2, 2, 2} + consumedUnits = Dimensions{0, 0, 0, 0} // last block happened within Window lastBlkTime = time.Now().Truncate(time.Second) currBlkTime = lastBlkTime.Add(time.Second) - - updateCoefficient = Dimensions{1, 1, 1, 1} - minUnitFees = Dimensions{1, 0, 0, 0} ) m := &Manager{ - unitFees: initialUnitFees, + unitFees: currentUnitFees, windows: [FeeDimensions]Window{ {0, 0, 0, math.MaxUint64, 0, 0, 0, 0, 0, 0}, // a huge spike in the past, on the non-constrained dimension {0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, // a small spike, but it hits the small constrain set for this dimension @@ -151,22 +148,20 @@ func TestComputeNextEdgeCases(t *testing.T) { m.UpdateUnitFees( lastBlkTime.Unix(), currBlkTime.Unix(), - targetComplexity, - updateCoefficient, - minUnitFees, + feesCfg, ) // Bandwidth units are below target, next unit fees are pushed to the minimum - require.Equal(minUnitFees[Bandwidth], m.unitFees[Bandwidth]) + require.Equal(feesCfg.MinUnitFees[Bandwidth], m.unitFees[Bandwidth]) // UTXORead units are at target, due to spike in window. Unit fees are kept unchanged. - require.Equal(initialUnitFees[UTXORead], m.unitFees[UTXORead]) + require.Equal(currentUnitFees[UTXORead], m.unitFees[UTXORead]) // UTXOWrite units are below target. Unit fees are decreased. - require.Equal(minUnitFees[UTXOWrite], m.unitFees[UTXOWrite]) + require.Equal(feesCfg.MinUnitFees[UTXOWrite], m.unitFees[UTXOWrite]) // Compute units are below target. Unit fees are decreased. - require.Equal(minUnitFees[Compute], m.unitFees[Compute]) + require.Equal(feesCfg.MinUnitFees[Compute], m.unitFees[Compute]) } func TestComputeNextStability(t *testing.T) { @@ -179,21 +174,23 @@ func TestComputeNextStability(t *testing.T) { require := require.New(t) var ( - initialUnitFees = Dimensions{10, 100, 1_000, 1_000_000_000} - consumedUnits1 = Dimensions{24, 45, 70, 500} - consumedUnits2 = Dimensions{26, 55, 130, 1500} - targetComplexity = Dimensions{25, 50, 100, 1000} + feesCfg = DynamicFeesConfig{ + MinUnitFees: Dimensions{0, 0, 0, 0}, + UpdateCoefficient: Dimensions{1, 2, 5, 10}, + BlockUnitsTarget: Dimensions{25, 50, 100, 1000}, + } + currentUnitFees = Dimensions{10, 100, 1_000, 1_000_000_000} + consumedUnits1 = Dimensions{24, 45, 70, 500} + consumedUnits2 = Dimensions{26, 55, 130, 1500} + // last block happened within Window lastBlkTime = time.Now().Truncate(time.Second) currBlkTime = lastBlkTime.Add(time.Second) - - updateCoefficient = Dimensions{1, 2, 5, 10} - minUnitFees = Dimensions{0, 0, 0, 0} ) // step1: cumulated units are below target. Unit fees must decrease m1 := &Manager{ - unitFees: initialUnitFees, + unitFees: currentUnitFees, windows: [FeeDimensions]Window{}, cumulatedUnits: consumedUnits1, } @@ -201,15 +198,13 @@ func TestComputeNextStability(t *testing.T) { m1.UpdateUnitFees( lastBlkTime.Unix(), currBlkTime.Unix(), - targetComplexity, - updateCoefficient, - minUnitFees, + feesCfg, ) - require.Less(m1.unitFees[Bandwidth], initialUnitFees[Bandwidth]) - require.Less(m1.unitFees[UTXORead], initialUnitFees[UTXORead]) - require.Less(m1.unitFees[UTXOWrite], initialUnitFees[UTXOWrite]) - require.Less(m1.unitFees[Compute], initialUnitFees[Compute]) + require.Less(m1.unitFees[Bandwidth], currentUnitFees[Bandwidth]) + require.Less(m1.unitFees[UTXORead], currentUnitFees[UTXORead]) + require.Less(m1.unitFees[UTXOWrite], currentUnitFees[UTXOWrite]) + require.Less(m1.unitFees[Compute], currentUnitFees[Compute]) // step2: cumulated units go slight above target, so that average consumed units are at target. // Unit fees go back to the original value @@ -222,13 +217,11 @@ func TestComputeNextStability(t *testing.T) { m2.UpdateUnitFees( lastBlkTime.Unix(), currBlkTime.Unix(), - targetComplexity, - updateCoefficient, - minUnitFees, + feesCfg, ) - require.Equal(initialUnitFees[Bandwidth], m2.unitFees[Bandwidth]) - require.Equal(initialUnitFees[UTXORead], m2.unitFees[UTXORead]) - require.Equal(initialUnitFees[UTXOWrite], m2.unitFees[UTXOWrite]) - require.Equal(initialUnitFees[Compute], m2.unitFees[Compute]) + require.Equal(currentUnitFees[Bandwidth], m2.unitFees[Bandwidth]) + require.Equal(currentUnitFees[UTXORead], m2.unitFees[UTXORead]) + require.Equal(currentUnitFees[UTXOWrite], m2.unitFees[UTXOWrite]) + require.Equal(currentUnitFees[Compute], m2.unitFees[Compute]) } diff --git a/vms/platformvm/block/builder/builder.go b/vms/platformvm/block/builder/builder.go index 4c32326b7ed2..c100db8ceaad 100644 --- a/vms/platformvm/block/builder/builder.go +++ b/vms/platformvm/block/builder/builder.go @@ -355,9 +355,7 @@ func packBlockTxs( feeMan.UpdateUnitFees( parentState.GetTimestamp().Unix(), timestamp.Unix(), - feesCfg.BlockUnitsTarget, - feesCfg.UpdateCoefficient, - feesCfg.MinUnitFees, + feesCfg, ) } diff --git a/vms/platformvm/block/executor/manager.go b/vms/platformvm/block/executor/manager.go index dad8ecbb59e1..30f32794ed21 100644 --- a/vms/platformvm/block/executor/manager.go +++ b/vms/platformvm/block/executor/manager.go @@ -164,9 +164,7 @@ func (m *manager) VerifyTx(tx *txs.Tx) error { feeManager.UpdateUnitFees( chainTime.Unix(), nextBlkTime.Unix(), - feesCfg.BlockUnitsTarget, - feesCfg.UpdateCoefficient, - feesCfg.MinUnitFees, + feesCfg, ) } diff --git a/vms/platformvm/block/executor/verifier.go b/vms/platformvm/block/executor/verifier.go index 2498e7c25029..6d28f587f8a6 100644 --- a/vms/platformvm/block/executor/verifier.go +++ b/vms/platformvm/block/executor/verifier.go @@ -473,9 +473,7 @@ func (v *verifier) processStandardTxs(txs []*txs.Tx, state state.Diff, parentID feeManager.UpdateUnitFees( currentTimestamp.Unix(), blkTimestamp.Unix(), - feesCfg.BlockUnitsTarget, - feesCfg.UpdateCoefficient, - feesCfg.MinUnitFees, + feesCfg, ) } diff --git a/vms/platformvm/config/dynamic_fees_config.go b/vms/platformvm/config/dynamic_fees_config.go index 55455d181edd..6b4a75abe124 100644 --- a/vms/platformvm/config/dynamic_fees_config.go +++ b/vms/platformvm/config/dynamic_fees_config.go @@ -15,19 +15,19 @@ import ( func init() { if customDynamicFeesConfig != nil { - if err := customDynamicFeesConfig.validate(); err != nil { + if err := customDynamicFeesConfig.Validate(); err != nil { panic(err) } } - if err := eUpgradeDynamicFeesConfig.validate(); err != nil { + if err := eUpgradeDynamicFeesConfig.Validate(); err != nil { panic(err) } } // eUpgradeDynamicFeesConfig to be tuned TODO ABENEGIA var ( - eUpgradeDynamicFeesConfig = DynamicFeesConfig{ + eUpgradeDynamicFeesConfig = commonfees.DynamicFeesConfig{ InitialUnitFees: commonfees.Dimensions{ 1 * units.NanoAvax, 2 * units.NanoAvax, @@ -46,15 +46,15 @@ var ( } // TODO ABENEGIA: decide if and how to validate preEUpgradeDynamicFeesConfig - preEUpgradeDynamicFeesConfig = DynamicFeesConfig{ + preEUpgradeDynamicFeesConfig = commonfees.DynamicFeesConfig{ InitialUnitFees: commonfees.Empty, BlockUnitsCap: commonfees.Max, } - customDynamicFeesConfig *DynamicFeesConfig + customDynamicFeesConfig *commonfees.DynamicFeesConfig ) -func GetDynamicFeesConfig(isEActive bool) DynamicFeesConfig { +func GetDynamicFeesConfig(isEActive bool) commonfees.DynamicFeesConfig { if !isEActive { return preEUpgradeDynamicFeesConfig } @@ -65,7 +65,7 @@ func GetDynamicFeesConfig(isEActive bool) DynamicFeesConfig { return eUpgradeDynamicFeesConfig } -func ResetDynamicFeesConfig(ctx *snow.Context, customFeesConfig *DynamicFeesConfig) error { +func ResetDynamicFeesConfig(ctx *snow.Context, customFeesConfig *commonfees.DynamicFeesConfig) error { if customFeesConfig == nil { return nil // nothing to do } @@ -76,57 +76,3 @@ func ResetDynamicFeesConfig(ctx *snow.Context, customFeesConfig *DynamicFeesConf customDynamicFeesConfig = customFeesConfig return nil } - -type DynamicFeesConfig struct { - // InitialUnitFees contains, per each fee dimension, the - // unit fees valid as soon as fork introducing dynamic fees - // activates. Unit fees will be then updated by the dynamic fees algo. - InitialUnitFees commonfees.Dimensions `json:"initial-unit-fees"` - - // MinUnitFees contains, per each fee dimension, the - // minimal unit fees enforced by the dynamic fees algo. - MinUnitFees commonfees.Dimensions `json:"min-unit-fees"` - - // UpdateCoefficient contains, per each fee dimension, the - // exponential update coefficient. Setting an entry to 0 makes - // the corresponding fee rate constant. - UpdateCoefficient commonfees.Dimensions `json:"update-coefficient"` - - // BlockUnitsCap contains, per each fee dimension, the - // maximal complexity a valid P-chain block can host - BlockUnitsCap commonfees.Dimensions `json:"block-unit-caps"` - - // BlockUnitsTarget contains, per each fee dimension, the - // preferred block complexity that the dynamic fee algo - // strive to converge to - BlockUnitsTarget commonfees.Dimensions `json:"block-target-caps"` -} - -func (c *DynamicFeesConfig) validate() error { - for i := commonfees.Dimension(0); i < commonfees.FeeDimensions; i++ { - // MinUnitFees can be zero, but that is a bit dangerous. if a fee ever becomes - // zero, the update mechanism will keep them to zero. - - if c.InitialUnitFees[i] < c.MinUnitFees[i] { - return fmt.Errorf("dimension %d, initial unit fee %d smaller than minimal unit fee %d", - i, - c.InitialUnitFees[i], - c.MinUnitFees[i], - ) - } - - if c.BlockUnitsTarget[i] > c.BlockUnitsCap[i] { - return fmt.Errorf("dimension %d, block target units %d larger than block units cap %d", - i, - c.BlockUnitsTarget[i], - c.BlockUnitsCap[i], - ) - } - - if c.BlockUnitsTarget[i] == 0 { - return fmt.Errorf("dimension %d, block target units set to zero", i) - } - } - - return nil -} diff --git a/vms/platformvm/config/execution_config.go b/vms/platformvm/config/execution_config.go index 4e4e8f8f0ccb..58fbc583d1ab 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" + + commonfees "github.com/ava-labs/avalanchego/vms/components/fees" ) var DefaultExecutionConfig = ExecutionConfig{ @@ -39,7 +41,7 @@ type ExecutionConfig struct { ChecksumsEnabled bool `json:"checksums-enabled"` MempoolPruneFrequency time.Duration `json:"mempool-prune-frequency"` - DynamicFeesConfig *DynamicFeesConfig `json:"dynamic-fees-config"` + DynamicFeesConfig *commonfees.DynamicFeesConfig `json:"dynamic-fees-config"` } // GetExecutionConfig returns an ExecutionConfig diff --git a/vms/platformvm/service.go b/vms/platformvm/service.go index 09b5fafdc627..3e72c4b2526d 100644 --- a/vms/platformvm/service.go +++ b/vms/platformvm/service.go @@ -1875,9 +1875,7 @@ func (s *Service) GetUnitFees(_ *http.Request, _ *struct{}, reply *GetUnitFeesRe feeManager.UpdateUnitFees( currentTimestamp.Unix(), nextTimestamp.Unix(), - feesCfg.BlockUnitsTarget, - feesCfg.UpdateCoefficient, - feesCfg.MinUnitFees, + feesCfg, ) } reply.NextUnitFees = feeManager.GetUnitFees() From 65d87da5ce4c7af19684f2ac21386e18c89c2885 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 14 Mar 2024 19:13:24 +0100 Subject: [PATCH 124/190] simplified feeManager --- tests/e2e/p/workflow.go | 5 +- vms/components/fees/manager.go | 22 ++--- vms/components/fees/manager_test.go | 78 +++++++++-------- vms/platformvm/block/builder/builder.go | 7 +- vms/platformvm/block/builder/helpers_test.go | 5 +- vms/platformvm/block/executor/helpers_test.go | 7 +- vms/platformvm/block/executor/manager.go | 7 +- vms/platformvm/block/executor/verifier.go | 11 +-- vms/platformvm/client.go | 9 -- vms/platformvm/service.go | 26 +----- vms/platformvm/service_test.go | 32 +------ vms/platformvm/txs/builder/builder.go | 78 +++-------------- .../txs/executor/atomic_tx_executor.go | 2 +- .../txs/executor/create_chain_test.go | 18 ++-- .../txs/executor/create_subnet_test.go | 4 +- vms/platformvm/txs/executor/helpers_test.go | 5 +- .../executor/staker_tx_verification_test.go | 2 +- .../txs/executor/standard_tx_executor_test.go | 62 ++++++------- vms/platformvm/txs/fees/calculator_test.go | 4 +- vms/platformvm/vm_test.go | 10 +-- wallet/chain/p/builder_test.go | 86 +++++++++---------- wallet/chain/p/wallet.go | 32 +++---- 22 files changed, 185 insertions(+), 327 deletions(-) diff --git a/tests/e2e/p/workflow.go b/tests/e2e/p/workflow.go index c7bdd91af207..5075abf25a2a 100644 --- a/tests/e2e/p/workflow.go +++ b/tests/e2e/p/workflow.go @@ -142,9 +142,6 @@ var _ = e2e.DescribePChain("[Workflow]", func() { _, nextUnitFees, err := pChainClient.GetUnitFees(e2e.DefaultContext()) require.NoError(err) - feeWindows, err := pChainClient.GetFeeWindows(e2e.DefaultContext()) - require.NoError(err) - tx, err := pWallet.IssueExportTx( xWallet.BlockchainID(), []*avax.TransferableOutput{ @@ -162,7 +159,7 @@ var _ = e2e.DescribePChain("[Workflow]", func() { // retrieve fees paid for the tx feeCalc := fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(nextUnitFees, feeWindows), + FeeManager: commonfees.NewManager(nextUnitFees), ConsumedUnitsCap: unitCaps, Credentials: tx.Creds, } diff --git a/vms/components/fees/manager.go b/vms/components/fees/manager.go index 1b838e0af622..0a96735f95b3 100644 --- a/vms/components/fees/manager.go +++ b/vms/components/fees/manager.go @@ -14,18 +14,14 @@ type Manager struct { // Avax denominated unit fees for all fee dimensions unitFees Dimensions - // consumed units window per each fee dimension. - windows Windows - // cumulatedUnits helps aggregating the units consumed by a block // so that we can verify it's not too big/build it properly. cumulatedUnits Dimensions } -func NewManager(unitFees Dimensions, windows Windows) *Manager { +func NewManager(unitFees Dimensions) *Manager { return &Manager{ unitFees: unitFees, - windows: windows, } } @@ -33,10 +29,6 @@ func (m *Manager) GetUnitFees() Dimensions { return m.unitFees } -func (m *Manager) GetFeeWindows() Windows { - return m.windows -} - func (m *Manager) GetCumulatedUnits() Dimensions { return m.cumulatedUnits } @@ -101,26 +93,26 @@ func (m *Manager) RemoveUnits(unitsToRm Dimensions) error { } // [UpdateWindows] stores in the fee windows the units cumulated in current block -func (m *Manager) UpdateWindows(lastTime, currTime int64) { +func (m *Manager) UpdateWindows(windows *Windows, lastTime, currTime int64) { var ( since = int(currTime - lastTime) latestIdx = WindowSize - 1 ) for i := Dimension(0); i < FeeDimensions; i++ { - m.windows[i] = Roll(m.windows[i], since) - Update(&m.windows[i], latestIdx, m.cumulatedUnits[i]) + windows[i] = Roll(windows[i], since) + Update(&windows[i], latestIdx, m.cumulatedUnits[i]) } } func (m *Manager) UpdateUnitFees( - lastTime, - currTime int64, feesConfig DynamicFeesConfig, + windows Windows, + lastTime, currTime int64, ) { since := int(currTime - lastTime) for i := Dimension(0); i < FeeDimensions; i++ { - nextUnitWindow := Roll(m.windows[i], since) + nextUnitWindow := Roll(windows[i], since) totalUnitsConsumed := Sum(nextUnitWindow) nextUnitFee := nextFeeRate(m.unitFees[i], feesConfig.UpdateCoefficient[i], totalUnitsConsumed, feesConfig.BlockUnitsTarget[i]) nextUnitFee = max(nextUnitFee, feesConfig.MinUnitFees[i]) diff --git a/vms/components/fees/manager_test.go b/vms/components/fees/manager_test.go index 7a3f4e191f44..d95a7db4aa3a 100644 --- a/vms/components/fees/manager_test.go +++ b/vms/components/fees/manager_test.go @@ -22,6 +22,7 @@ func TestComputeNextEmptyWindows(t *testing.T) { } currentUnitFees = Dimensions{1, 1, 1, 1} consumedUnits = Dimensions{50, 100, 150, 2500} + feeWindows = Windows{} // last block happened within Window lastBlkTime = time.Now().Truncate(time.Second) @@ -30,13 +31,13 @@ func TestComputeNextEmptyWindows(t *testing.T) { m := &Manager{ unitFees: currentUnitFees, - windows: [FeeDimensions]Window{}, cumulatedUnits: consumedUnits, } m.UpdateUnitFees( + feesCfg, + feeWindows, lastBlkTime.Unix(), currBlkTime.Unix(), - feesCfg, ) // Bandwidth units are below target, next unit fees are pushed to the minimum @@ -51,11 +52,12 @@ func TestComputeNextEmptyWindows(t *testing.T) { // Compute units are way above target, next unit fees are increased to the max require.Equal(feesCfg.MinUnitFees[Compute], m.unitFees[Compute]) - m.UpdateWindows(lastBlkTime.Unix(), currBlkTime.Unix()) + m.UpdateWindows(&feeWindows, lastBlkTime.Unix(), currBlkTime.Unix()) m.UpdateUnitFees( + feesCfg, + feeWindows, lastBlkTime.Unix(), currBlkTime.Unix(), - feesCfg, ) // Bandwidth units are below target, next unit fees are pushed to the minimum @@ -82,6 +84,12 @@ func TestComputeNextNonEmptyWindows(t *testing.T) { } currentUnitFees = Dimensions{1, 1, 1, 1} consumedUnits = Dimensions{0, 0, 0, 0} + feeWindows = Windows{ + {1, 1, 1, 2, 2, 3, 3, 4, 5, 0}, // increasing but overall below target + {0, 0, math.MaxUint64, 0, 0, 0, 0, 0, 0, 0}, // spike within window + {10, 20, 30, 40, 50, 35, 25, 15, 10, 10}, // decreasing but overall above target + {0, 0, 0, 0, 0, math.MaxUint64 / 2, math.MaxUint64 / 2, 0, 0, 0}, // again pretty spiky + } // last block happened within Window lastBlkTime = time.Now().Truncate(time.Second) @@ -89,19 +97,14 @@ func TestComputeNextNonEmptyWindows(t *testing.T) { ) m := &Manager{ - unitFees: currentUnitFees, - windows: [FeeDimensions]Window{ - {1, 1, 1, 2, 2, 3, 3, 4, 5, 0}, // increasing but overall below target - {0, 0, math.MaxUint64, 0, 0, 0, 0, 0, 0, 0}, // spike within window - {10, 20, 30, 40, 50, 35, 25, 15, 10, 10}, // decreasing but overall above target - {0, 0, 0, 0, 0, math.MaxUint64 / 2, math.MaxUint64 / 2, 0, 0, 0}, // again pretty spiky - }, + unitFees: currentUnitFees, cumulatedUnits: consumedUnits, } m.UpdateUnitFees( + feesCfg, + feeWindows, lastBlkTime.Unix(), currBlkTime.Unix(), - feesCfg, ) // Bandwidth units are below target, next unit fees are pushed to the minimum @@ -128,6 +131,12 @@ func TestComputeNextEdgeCases(t *testing.T) { } currentUnitFees = Dimensions{1, 2, 2, 2} consumedUnits = Dimensions{0, 0, 0, 0} + feeWindows = Windows{ + {0, 0, 0, math.MaxUint64, 0, 0, 0, 0, 0, 0}, // a huge spike in the past, on the non-constrained dimension + {0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, // a small spike, but it hits the small constrain set for this dimension + {}, + {}, + } // last block happened within Window lastBlkTime = time.Now().Truncate(time.Second) @@ -135,20 +144,15 @@ func TestComputeNextEdgeCases(t *testing.T) { ) m := &Manager{ - unitFees: currentUnitFees, - windows: [FeeDimensions]Window{ - {0, 0, 0, math.MaxUint64, 0, 0, 0, 0, 0, 0}, // a huge spike in the past, on the non-constrained dimension - {0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, // a small spike, but it hits the small constrain set for this dimension - {}, - {}, - }, + unitFees: currentUnitFees, cumulatedUnits: consumedUnits, } m.UpdateUnitFees( + feesCfg, + feeWindows, lastBlkTime.Unix(), currBlkTime.Unix(), - feesCfg, ) // Bandwidth units are below target, next unit fees are pushed to the minimum @@ -179,7 +183,9 @@ func TestComputeNextStability(t *testing.T) { UpdateCoefficient: Dimensions{1, 2, 5, 10}, BlockUnitsTarget: Dimensions{25, 50, 100, 1000}, } - currentUnitFees = Dimensions{10, 100, 1_000, 1_000_000_000} + initialUnitFees = Dimensions{10, 100, 1_000, 1_000_000_000} + feeWindows1 = Windows{} + feeWindows2 = Windows{} consumedUnits1 = Dimensions{24, 45, 70, 500} consumedUnits2 = Dimensions{26, 55, 130, 1500} @@ -190,38 +196,38 @@ func TestComputeNextStability(t *testing.T) { // step1: cumulated units are below target. Unit fees must decrease m1 := &Manager{ - unitFees: currentUnitFees, - windows: [FeeDimensions]Window{}, + unitFees: initialUnitFees, cumulatedUnits: consumedUnits1, } - m1.UpdateWindows(lastBlkTime.Unix(), currBlkTime.Unix()) + m1.UpdateWindows(&feeWindows1, lastBlkTime.Unix(), currBlkTime.Unix()) m1.UpdateUnitFees( + feesCfg, + feeWindows1, lastBlkTime.Unix(), currBlkTime.Unix(), - feesCfg, ) - require.Less(m1.unitFees[Bandwidth], currentUnitFees[Bandwidth]) - require.Less(m1.unitFees[UTXORead], currentUnitFees[UTXORead]) - require.Less(m1.unitFees[UTXOWrite], currentUnitFees[UTXOWrite]) - require.Less(m1.unitFees[Compute], currentUnitFees[Compute]) + require.Less(m1.unitFees[Bandwidth], initialUnitFees[Bandwidth]) + require.Less(m1.unitFees[UTXORead], initialUnitFees[UTXORead]) + require.Less(m1.unitFees[UTXOWrite], initialUnitFees[UTXOWrite]) + require.Less(m1.unitFees[Compute], initialUnitFees[Compute]) // step2: cumulated units go slight above target, so that average consumed units are at target. // Unit fees go back to the original value m2 := &Manager{ unitFees: m1.unitFees, - windows: [FeeDimensions]Window{}, cumulatedUnits: consumedUnits2, } - m2.UpdateWindows(lastBlkTime.Unix(), currBlkTime.Unix()) + m2.UpdateWindows(&feeWindows2, lastBlkTime.Unix(), currBlkTime.Unix()) m2.UpdateUnitFees( + feesCfg, + feeWindows2, lastBlkTime.Unix(), currBlkTime.Unix(), - feesCfg, ) - require.Equal(currentUnitFees[Bandwidth], m2.unitFees[Bandwidth]) - require.Equal(currentUnitFees[UTXORead], m2.unitFees[UTXORead]) - require.Equal(currentUnitFees[UTXOWrite], m2.unitFees[UTXOWrite]) - require.Equal(currentUnitFees[Compute], m2.unitFees[Compute]) + require.Equal(initialUnitFees[Bandwidth], m2.unitFees[Bandwidth]) + require.Equal(initialUnitFees[UTXORead], m2.unitFees[UTXORead]) + require.Equal(initialUnitFees[UTXOWrite], m2.unitFees[UTXOWrite]) + require.Equal(initialUnitFees[Compute], m2.unitFees[Compute]) } diff --git a/vms/platformvm/block/builder/builder.go b/vms/platformvm/block/builder/builder.go index c100db8ceaad..346f1740b014 100644 --- a/vms/platformvm/block/builder/builder.go +++ b/vms/platformvm/block/builder/builder.go @@ -337,7 +337,7 @@ func packBlockTxs( if err != nil { return nil, err } - unitWindows, err := stateDiff.GetFeeWindows() + feeWindows, err := stateDiff.GetFeeWindows() if err != nil { return nil, err } @@ -350,12 +350,13 @@ func packBlockTxs( inputs set.Set[ids.ID] ) - feeMan := commonfees.NewManager(unitFees, unitWindows) + feeMan := commonfees.NewManager(unitFees) if isEActivated { feeMan.UpdateUnitFees( + feesCfg, + feeWindows, parentState.GetTimestamp().Unix(), timestamp.Unix(), - feesCfg, ) } diff --git a/vms/platformvm/block/builder/helpers_test.go b/vms/platformvm/block/builder/helpers_test.go index c0920aa9cd79..0bf9c9865585 100644 --- a/vms/platformvm/block/builder/helpers_test.go +++ b/vms/platformvm/block/builder/helpers_test.go @@ -266,14 +266,11 @@ func addSubnet(t *testing.T, env *environment) { unitFees, err := env.state.GetUnitFees() require.NoError(err) - unitWindows, err := env.state.GetFeeWindows() - require.NoError(err) - chainTime := env.state.GetTimestamp() feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := txexecutor.StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(unitFees, unitWindows), + BlkFeeManager: fees.NewManager(unitFees), UnitCaps: feeCfg.BlockUnitsCap, State: stateDiff, Tx: testSubnet1, diff --git a/vms/platformvm/block/executor/helpers_test.go b/vms/platformvm/block/executor/helpers_test.go index b866892b1b77..caebd3c179a2 100644 --- a/vms/platformvm/block/executor/helpers_test.go +++ b/vms/platformvm/block/executor/helpers_test.go @@ -284,16 +284,11 @@ func addSubnet(env *environment) { panic(err) } - unitWindows, err := env.state.GetFeeWindows() - if err != nil { - panic(err) - } - chainTime := env.state.GetTimestamp() feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := executor.StandardTxExecutor{ Backend: env.backend, - BlkFeeManager: fees.NewManager(unitFees, unitWindows), + BlkFeeManager: fees.NewManager(unitFees), UnitCaps: feeCfg.BlockUnitsCap, State: stateDiff, Tx: testSubnet1, diff --git a/vms/platformvm/block/executor/manager.go b/vms/platformvm/block/executor/manager.go index 30f32794ed21..732a717e28b6 100644 --- a/vms/platformvm/block/executor/manager.go +++ b/vms/platformvm/block/executor/manager.go @@ -148,7 +148,7 @@ func (m *manager) VerifyTx(tx *txs.Tx) error { if err != nil { return err } - unitWindows, err := stateDiff.GetFeeWindows() + feeWindows, err := stateDiff.GetFeeWindows() if err != nil { return err } @@ -159,12 +159,13 @@ func (m *manager) VerifyTx(tx *txs.Tx) error { feesCfg = config.GetDynamicFeesConfig(isEActivated) ) - feeManager := fees.NewManager(unitFees, unitWindows) + feeManager := fees.NewManager(unitFees) if isEActivated { feeManager.UpdateUnitFees( + feesCfg, + feeWindows, chainTime.Unix(), nextBlkTime.Unix(), - feesCfg, ) } diff --git a/vms/platformvm/block/executor/verifier.go b/vms/platformvm/block/executor/verifier.go index 6d28f587f8a6..80d88dba3fbe 100644 --- a/vms/platformvm/block/executor/verifier.go +++ b/vms/platformvm/block/executor/verifier.go @@ -452,7 +452,7 @@ func (v *verifier) processStandardTxs(txs []*txs.Tx, state state.Diff, parentID if err != nil { return nil, nil, nil, nil, err } - unitWindows, err := state.GetFeeWindows() + feeWindows, err := state.GetFeeWindows() if err != nil { return nil, nil, nil, nil, err } @@ -468,12 +468,13 @@ func (v *verifier) processStandardTxs(txs []*txs.Tx, state state.Diff, parentID atomicRequests = make(map[ids.ID]*atomic.Requests) ) - feeManager := fees.NewManager(unitFees, unitWindows) + feeManager := fees.NewManager(unitFees) if isEActivated { feeManager.UpdateUnitFees( + feesCfg, + feeWindows, currentTimestamp.Unix(), blkTimestamp.Unix(), - feesCfg, ) } @@ -520,9 +521,9 @@ func (v *verifier) processStandardTxs(txs []*txs.Tx, state state.Diff, parentID } if isEActivated { - feeManager.UpdateWindows(currentTimestamp.Unix(), blkTimestamp.Unix()) + feeManager.UpdateWindows(&feeWindows, currentTimestamp.Unix(), blkTimestamp.Unix()) state.SetUnitFees(feeManager.GetUnitFees()) - state.SetFeeWindows(feeManager.GetFeeWindows()) + state.SetFeeWindows(feeWindows) } if numFuncs := len(funcs); numFuncs == 1 { diff --git a/vms/platformvm/client.go b/vms/platformvm/client.go index c0c8e8970263..bca8935c7dc5 100644 --- a/vms/platformvm/client.go +++ b/vms/platformvm/client.go @@ -136,9 +136,6 @@ type Client interface { // GetUnitFees returns the current unit fees and the next unit fees that a transaction must pay to be accepted GetUnitFees(ctx context.Context, options ...rpc.Option) (commonfees.Dimensions, commonfees.Dimensions, error) - - // GetFeeWindows returns the fee window needed to calculate next block unit fees - GetFeeWindows(ctx context.Context, options ...rpc.Option) (commonfees.Windows, error) } // Client implementation for interacting with the P Chain endpoint @@ -559,9 +556,3 @@ func (c *client) GetUnitFees(ctx context.Context, options ...rpc.Option) (common err := c.requester.SendRequest(ctx, "platform.getUnitFees", struct{}{}, res, options...) return res.CurrentUnitFees, res.NextUnitFees, err } - -func (c *client) GetFeeWindows(ctx context.Context, options ...rpc.Option) (commonfees.Windows, error) { - res := &GetFeeWindowsReply{} - err := c.requester.SendRequest(ctx, "platform.getFeeWindows", struct{}{}, res, options...) - return res.FeeWindows, err -} diff --git a/vms/platformvm/service.go b/vms/platformvm/service.go index 3e72c4b2526d..7c25096effac 100644 --- a/vms/platformvm/service.go +++ b/vms/platformvm/service.go @@ -1870,12 +1870,13 @@ func (s *Service) GetUnitFees(_ *http.Request, _ *struct{}, reply *GetUnitFeesRe return err } - feeManager := commonfees.NewManager(currentUnitFees, feeWindows) + feeManager := commonfees.NewManager(currentUnitFees) if isEActivated { feeManager.UpdateUnitFees( + feesCfg, + feeWindows, currentTimestamp.Unix(), nextTimestamp.Unix(), - feesCfg, ) } reply.NextUnitFees = feeManager.GetUnitFees() @@ -1883,27 +1884,6 @@ func (s *Service) GetUnitFees(_ *http.Request, _ *struct{}, reply *GetUnitFeesRe return nil } -// GetBlockUnitsCapReply is the response from GetBlockUnitsCap -type GetFeeWindowsReply struct { - // Current timestamp - FeeWindows commonfees.Windows `json:"feeWindows"` -} - -// GetTimestamp returns the current timestamp on chain. -func (s *Service) GetFeeWindows(_ *http.Request, _ *struct{}, reply *GetFeeWindowsReply) error { - s.vm.ctx.Log.Debug("API called", - zap.String("service", "platform"), - zap.String("method", "getBlockUnitsCap"), - ) - - s.vm.ctx.Lock.Lock() - defer s.vm.ctx.Lock.Unlock() - - var err error - reply.FeeWindows, err = s.vm.state.GetFeeWindows() - return err -} - func (s *Service) getAPIUptime(staker *state.Staker) (*avajson.Float32, error) { // Only report uptimes that we have been actively tracking. if constants.PrimaryNetworkID != staker.SubnetID && !s.vm.TrackedSubnets.Contains(staker.SubnetID) { diff --git a/vms/platformvm/service_test.go b/vms/platformvm/service_test.go index 3311f8b9fe1f..83a6abb7ed20 100644 --- a/vms/platformvm/service_test.go +++ b/vms/platformvm/service_test.go @@ -356,13 +356,10 @@ func TestGetBalance(t *testing.T) { unitFees, err := service.vm.state.GetUnitFees() require.NoError(err) - feeWindows, err := service.vm.state.GetFeeWindows() - require.NoError(err) - var ( chainTime = service.vm.state.GetTimestamp() feeCfg = config.GetDynamicFeesConfig(service.vm.Config.IsEActivated(chainTime)) - feeMan = commonfees.NewManager(unitFees, feeWindows) + feeMan = commonfees.NewManager(unitFees) feeCalc = &fees.Calculator{ IsEUpgradeActive: service.vm.IsEActivated(chainTime), Config: &service.vm.Config, @@ -1033,30 +1030,3 @@ func TestGetUnitFees(t *testing.T) { require.NoError(service.GetUnitFees(nil, nil, &reply)) require.Equal(updatedUnitFees, reply.CurrentUnitFees) } - -func TestGetFeeWindows(t *testing.T) { - require := require.New(t) - service, _ := defaultService(t) - - reply := GetFeeWindowsReply{} - require.NoError(service.GetFeeWindows(nil, nil, &reply)) - - service.vm.ctx.Lock.Lock() - - feeWindows, err := service.vm.state.GetFeeWindows() - require.NoError(err) - require.Equal(feeWindows, reply.FeeWindows) - - updatedFeeWindows := commonfees.Windows{ - commonfees.Window{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, - commonfees.Window{11, 12, 13, 14, 15, 16, 17, 18, 19, 20}, - commonfees.Window{math.MaxUint64, 0, math.MaxUint64, 0, math.MaxUint64, 0, math.MaxUint64, 0, math.MaxUint64, 0}, - commonfees.Window{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, - } - service.vm.state.SetFeeWindows(updatedFeeWindows) - - service.vm.ctx.Lock.Unlock() - - require.NoError(service.GetFeeWindows(nil, nil, &reply)) - require.Equal(updatedFeeWindows, reply.FeeWindows) -} diff --git a/vms/platformvm/txs/builder/builder.go b/vms/platformvm/txs/builder/builder.go index b807d859803b..277155795bc3 100644 --- a/vms/platformvm/txs/builder/builder.go +++ b/vms/platformvm/txs/builder/builder.go @@ -285,10 +285,6 @@ func (b *builder) NewImportTx( if err != nil { return nil, err } - unitWindows, err := b.state.GetFeeWindows() - if err != nil { - return nil, err - } var ( pBuilder, pSigner = b.builders(keys) @@ -300,7 +296,7 @@ func (b *builder) NewImportTx( IsEUpgradeActive: isEUpgradeActive, Config: b.cfg, ChainTime: chainTime, - FeeManager: commonfees.NewManager(unitFees, unitWindows), + FeeManager: commonfees.NewManager(unitFees), ConsumedUnitsCap: feeCfg.BlockUnitsCap, } ) @@ -341,10 +337,6 @@ func (b *builder) NewExportTx( if err != nil { return nil, err } - unitWindows, err := b.state.GetFeeWindows() - if err != nil { - return nil, err - } var ( pBuilder, pSigner = b.builders(keys) @@ -356,7 +348,7 @@ func (b *builder) NewExportTx( IsEUpgradeActive: isEUpgradeActive, Config: b.cfg, ChainTime: chainTime, - FeeManager: commonfees.NewManager(unitFees, unitWindows), + FeeManager: commonfees.NewManager(unitFees), ConsumedUnitsCap: feeCfg.BlockUnitsCap, } ) @@ -404,10 +396,6 @@ func (b *builder) NewCreateChainTx( if err != nil { return nil, err } - unitWindows, err := b.state.GetFeeWindows() - if err != nil { - return nil, err - } var ( pBuilder, pSigner = b.builders(keys) @@ -419,7 +407,7 @@ func (b *builder) NewCreateChainTx( IsEUpgradeActive: isEUpgradeActive, Config: b.cfg, ChainTime: chainTime, - FeeManager: commonfees.NewManager(unitFees, unitWindows), + FeeManager: commonfees.NewManager(unitFees), ConsumedUnitsCap: feeCfg.BlockUnitsCap, } ) @@ -455,10 +443,6 @@ func (b *builder) NewCreateSubnetTx( if err != nil { return nil, err } - unitWindows, err := b.state.GetFeeWindows() - if err != nil { - return nil, err - } var ( pBuilder, pSigner = b.builders(keys) @@ -470,7 +454,7 @@ func (b *builder) NewCreateSubnetTx( IsEUpgradeActive: isEUpgradeActive, Config: b.cfg, ChainTime: chainTime, - FeeManager: commonfees.NewManager(unitFees, unitWindows), + FeeManager: commonfees.NewManager(unitFees), ConsumedUnitsCap: feeCfg.BlockUnitsCap, } ) @@ -520,10 +504,6 @@ func (b *builder) NewTransformSubnetTx( if err != nil { return nil, err } - unitWindows, err := b.state.GetFeeWindows() - if err != nil { - return nil, err - } var ( pBuilder, pSigner = b.builders(keys) @@ -535,7 +515,7 @@ func (b *builder) NewTransformSubnetTx( IsEUpgradeActive: isEUpgradeActive, Config: b.cfg, ChainTime: chainTime, - FeeManager: commonfees.NewManager(unitFees, unitWindows), + FeeManager: commonfees.NewManager(unitFees), ConsumedUnitsCap: feeCfg.BlockUnitsCap, } ) @@ -584,10 +564,6 @@ func (b *builder) NewAddValidatorTx( if err != nil { return nil, err } - unitWindows, err := b.state.GetFeeWindows() - if err != nil { - return nil, err - } var ( pBuilder, pSigner = b.builders(keys) @@ -599,7 +575,7 @@ func (b *builder) NewAddValidatorTx( IsEUpgradeActive: isEUpgradeActive, Config: b.cfg, ChainTime: chainTime, - FeeManager: commonfees.NewManager(unitFees, unitWindows), + FeeManager: commonfees.NewManager(unitFees), ConsumedUnitsCap: feeCfg.BlockUnitsCap, } ) @@ -650,10 +626,6 @@ func (b *builder) NewAddPermissionlessValidatorTx( if err != nil { return nil, err } - unitWindows, err := b.state.GetFeeWindows() - if err != nil { - return nil, err - } var ( pBuilder, pSigner = b.builders(keys) @@ -665,7 +637,7 @@ func (b *builder) NewAddPermissionlessValidatorTx( IsEUpgradeActive: isEUpgradeActive, Config: b.cfg, ChainTime: chainTime, - FeeManager: commonfees.NewManager(unitFees, unitWindows), + FeeManager: commonfees.NewManager(unitFees), ConsumedUnitsCap: feeCfg.BlockUnitsCap, } ) @@ -720,10 +692,6 @@ func (b *builder) NewAddDelegatorTx( if err != nil { return nil, err } - unitWindows, err := b.state.GetFeeWindows() - if err != nil { - return nil, err - } var ( pBuilder, pSigner = b.builders(keys) @@ -735,7 +703,7 @@ func (b *builder) NewAddDelegatorTx( IsEUpgradeActive: isEUpgradeActive, Config: b.cfg, ChainTime: chainTime, - FeeManager: commonfees.NewManager(unitFees, unitWindows), + FeeManager: commonfees.NewManager(unitFees), ConsumedUnitsCap: feeCfg.BlockUnitsCap, } ) @@ -783,10 +751,6 @@ func (b *builder) NewAddPermissionlessDelegatorTx( if err != nil { return nil, err } - unitWindows, err := b.state.GetFeeWindows() - if err != nil { - return nil, err - } var ( pBuilder, pSigner = b.builders(keys) @@ -798,7 +762,7 @@ func (b *builder) NewAddPermissionlessDelegatorTx( IsEUpgradeActive: isEUpgradeActive, Config: b.cfg, ChainTime: chainTime, - FeeManager: commonfees.NewManager(unitFees, unitWindows), + FeeManager: commonfees.NewManager(unitFees), ConsumedUnitsCap: feeCfg.BlockUnitsCap, } ) @@ -850,10 +814,6 @@ func (b *builder) NewAddSubnetValidatorTx( if err != nil { return nil, err } - unitWindows, err := b.state.GetFeeWindows() - if err != nil { - return nil, err - } var ( pBuilder, pSigner = b.builders(keys) @@ -865,7 +825,7 @@ func (b *builder) NewAddSubnetValidatorTx( IsEUpgradeActive: isEUpgradeActive, Config: b.cfg, ChainTime: chainTime, - FeeManager: commonfees.NewManager(unitFees, unitWindows), + FeeManager: commonfees.NewManager(unitFees), ConsumedUnitsCap: feeCfg.BlockUnitsCap, } ) @@ -907,10 +867,6 @@ func (b *builder) NewRemoveSubnetValidatorTx( if err != nil { return nil, err } - unitWindows, err := b.state.GetFeeWindows() - if err != nil { - return nil, err - } var ( pBuilder, pSigner = b.builders(keys) @@ -922,7 +878,7 @@ func (b *builder) NewRemoveSubnetValidatorTx( IsEUpgradeActive: isEUpgradeActive, Config: b.cfg, ChainTime: chainTime, - FeeManager: commonfees.NewManager(unitFees, unitWindows), + FeeManager: commonfees.NewManager(unitFees), ConsumedUnitsCap: feeCfg.BlockUnitsCap, } ) @@ -956,10 +912,6 @@ func (b *builder) NewTransferSubnetOwnershipTx( if err != nil { return nil, err } - unitWindows, err := b.state.GetFeeWindows() - if err != nil { - return nil, err - } var ( pBuilder, pSigner = b.builders(keys) @@ -971,7 +923,7 @@ func (b *builder) NewTransferSubnetOwnershipTx( IsEUpgradeActive: isEUpgradeActive, Config: b.cfg, ChainTime: chainTime, - FeeManager: commonfees.NewManager(unitFees, unitWindows), + FeeManager: commonfees.NewManager(unitFees), ConsumedUnitsCap: feeCfg.BlockUnitsCap, } ) @@ -1010,10 +962,6 @@ func (b *builder) NewBaseTx( if err != nil { return nil, err } - unitWindows, err := b.state.GetFeeWindows() - if err != nil { - return nil, err - } var ( pBuilder, pSigner = b.builders(keys) @@ -1025,7 +973,7 @@ func (b *builder) NewBaseTx( IsEUpgradeActive: isEUpgradeActive, Config: b.cfg, ChainTime: chainTime, - FeeManager: commonfees.NewManager(unitFees, unitWindows), + FeeManager: commonfees.NewManager(unitFees), ConsumedUnitsCap: feeCfg.BlockUnitsCap, } ) diff --git a/vms/platformvm/txs/executor/atomic_tx_executor.go b/vms/platformvm/txs/executor/atomic_tx_executor.go index 08f7af5ef853..791da5fe912b 100644 --- a/vms/platformvm/txs/executor/atomic_tx_executor.go +++ b/vms/platformvm/txs/executor/atomic_tx_executor.go @@ -104,7 +104,7 @@ func (e *AtomicTxExecutor) atomicTx(tx txs.UnsignedTx) error { feesCfg := config.GetDynamicFeesConfig(false /*isEActive*/) executor := StandardTxExecutor{ Backend: e.Backend, - BlkFeeManager: commonfees.NewManager(commonfees.Empty, commonfees.EmptyWindows), + BlkFeeManager: commonfees.NewManager(commonfees.Empty), UnitCaps: feesCfg.BlockUnitsCap, State: e.OnAccept, Tx: e.Tx, diff --git a/vms/platformvm/txs/executor/create_chain_test.go b/vms/platformvm/txs/executor/create_chain_test.go index a821f7bf4b70..96b5153262ea 100644 --- a/vms/platformvm/txs/executor/create_chain_test.go +++ b/vms/platformvm/txs/executor/create_chain_test.go @@ -58,7 +58,7 @@ func TestCreateChainTxInsufficientControlSigs(t *testing.T) { feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(feeCfg.InitialUnitFees, commonfees.EmptyWindows), + BlkFeeManager: commonfees.NewManager(feeCfg.InitialUnitFees), UnitCaps: feeCfg.BlockUnitsCap, State: stateDiff, Tx: tx, @@ -102,7 +102,7 @@ func TestCreateChainTxWrongControlSig(t *testing.T) { feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(feeCfg.InitialUnitFees, commonfees.EmptyWindows), + BlkFeeManager: commonfees.NewManager(feeCfg.InitialUnitFees), UnitCaps: feeCfg.BlockUnitsCap, State: stateDiff, Tx: tx, @@ -139,14 +139,11 @@ func TestCreateChainTxNoSuchSubnet(t *testing.T) { unitFees, err := env.state.GetUnitFees() require.NoError(err) - unitWindows, err := env.state.GetFeeWindows() - require.NoError(err) - currentTime := stateDiff.GetTimestamp() feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(currentTime)) executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(unitFees, unitWindows), + BlkFeeManager: commonfees.NewManager(unitFees), UnitCaps: feeCfg.BlockUnitsCap, State: stateDiff, Tx: tx, @@ -180,14 +177,11 @@ func TestCreateChainTxValid(t *testing.T) { unitFees, err := env.state.GetUnitFees() require.NoError(err) - unitWindows, err := env.state.GetFeeWindows() - require.NoError(err) - currentTime := stateDiff.GetTimestamp() feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(currentTime)) executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(unitFees, unitWindows), + BlkFeeManager: commonfees.NewManager(unitFees), UnitCaps: feeCfg.BlockUnitsCap, State: stateDiff, Tx: tx, @@ -248,7 +242,7 @@ func TestCreateChainTxAP3FeeChange(t *testing.T) { IsEUpgradeActive: false, Config: &cfg, ChainTime: test.time, - FeeManager: commonfees.NewManager(feeCfg.InitialUnitFees, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(feeCfg.InitialUnitFees), ConsumedUnitsCap: feeCfg.BlockUnitsCap, } ) @@ -278,7 +272,7 @@ func TestCreateChainTxAP3FeeChange(t *testing.T) { feeCfg = config.GetDynamicFeesConfig(env.config.IsEActivated(currentTime)) executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(feeCfg.InitialUnitFees, commonfees.EmptyWindows), + BlkFeeManager: commonfees.NewManager(feeCfg.InitialUnitFees), UnitCaps: feeCfg.BlockUnitsCap, State: stateDiff, Tx: tx, diff --git a/vms/platformvm/txs/executor/create_subnet_test.go b/vms/platformvm/txs/executor/create_subnet_test.go index ba3f36584f62..2deee5cee984 100644 --- a/vms/platformvm/txs/executor/create_subnet_test.go +++ b/vms/platformvm/txs/executor/create_subnet_test.go @@ -78,7 +78,7 @@ func TestCreateSubnetTxAP3FeeChange(t *testing.T) { IsEUpgradeActive: false, Config: &cfg, ChainTime: test.time, - FeeManager: commonfees.NewManager(feeCfg.InitialUnitFees, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(feeCfg.InitialUnitFees), ConsumedUnitsCap: feeCfg.BlockUnitsCap, Fee: test.fee, @@ -106,7 +106,7 @@ func TestCreateSubnetTxAP3FeeChange(t *testing.T) { feeCfg = config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(feeCfg.InitialUnitFees, commonfees.EmptyWindows), + BlkFeeManager: commonfees.NewManager(feeCfg.InitialUnitFees), UnitCaps: feeCfg.BlockUnitsCap, State: stateDiff, Tx: tx, diff --git a/vms/platformvm/txs/executor/helpers_test.go b/vms/platformvm/txs/executor/helpers_test.go index dd3b8ca99c66..6b0b15fdecd3 100644 --- a/vms/platformvm/txs/executor/helpers_test.go +++ b/vms/platformvm/txs/executor/helpers_test.go @@ -238,14 +238,11 @@ func addSubnet( unitFees, err := env.state.GetUnitFees() require.NoError(err) - unitWindows, err := env.state.GetFeeWindows() - require.NoError(err) - chainTime := env.state.GetTimestamp() feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(unitFees, unitWindows), + BlkFeeManager: fees.NewManager(unitFees), UnitCaps: feeCfg.BlockUnitsCap, State: stateDiff, Tx: testSubnet1, diff --git a/vms/platformvm/txs/executor/staker_tx_verification_test.go b/vms/platformvm/txs/executor/staker_tx_verification_test.go index 0bf9ebcf1399..05e84e55ce06 100644 --- a/vms/platformvm/txs/executor/staker_tx_verification_test.go +++ b/vms/platformvm/txs/executor/staker_tx_verification_test.go @@ -515,7 +515,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { var ( backend = tt.backendF(ctrl) - feeManager = fees.NewManager(fees.Empty, fees.EmptyWindows) + feeManager = fees.NewManager(fees.Empty) state = tt.stateF(ctrl) sTx = tt.sTxF() tx = tt.txF() diff --git a/vms/platformvm/txs/executor/standard_tx_executor_test.go b/vms/platformvm/txs/executor/standard_tx_executor_test.go index ee008e91f701..cb9e32d942e4 100644 --- a/vms/platformvm/txs/executor/standard_tx_executor_test.go +++ b/vms/platformvm/txs/executor/standard_tx_executor_test.go @@ -93,7 +93,7 @@ func TestStandardTxExecutorAddValidatorTxEmptyID(t *testing.T) { feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(feeCfg.InitialUnitFees, fees.EmptyWindows), + BlkFeeManager: fees.NewManager(feeCfg.InitialUnitFees), UnitCaps: feeCfg.BlockUnitsCap, State: stateDiff, Tx: tx, @@ -344,7 +344,7 @@ func TestStandardTxExecutorAddDelegator(t *testing.T) { feeCfg := config.GetDynamicFeesConfig(freshTH.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ Backend: &freshTH.backend, - BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + BlkFeeManager: fees.NewManager(fees.Empty), UnitCaps: feeCfg.BlockUnitsCap, State: onAcceptState, Tx: tx, @@ -387,7 +387,7 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + BlkFeeManager: fees.NewManager(fees.Empty), UnitCaps: feeCfg.BlockUnitsCap, State: onAcceptState, Tx: tx, @@ -420,7 +420,7 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + BlkFeeManager: fees.NewManager(fees.Empty), UnitCaps: feeCfg.BlockUnitsCap, State: onAcceptState, Tx: tx, @@ -468,7 +468,7 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + BlkFeeManager: fees.NewManager(fees.Empty), UnitCaps: feeCfg.BlockUnitsCap, State: onAcceptState, Tx: tx, @@ -516,7 +516,7 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + BlkFeeManager: fees.NewManager(fees.Empty), UnitCaps: feeCfg.BlockUnitsCap, State: onAcceptState, Tx: tx, @@ -547,7 +547,7 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + BlkFeeManager: fees.NewManager(fees.Empty), UnitCaps: feeCfg.BlockUnitsCap, State: onAcceptState, Tx: tx, @@ -578,7 +578,7 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + BlkFeeManager: fees.NewManager(fees.Empty), UnitCaps: feeCfg.BlockUnitsCap, State: onAcceptState, Tx: tx, @@ -611,7 +611,7 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + BlkFeeManager: fees.NewManager(fees.Empty), UnitCaps: feeCfg.BlockUnitsCap, State: onAcceptState, Tx: tx, @@ -673,7 +673,7 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + BlkFeeManager: fees.NewManager(fees.Empty), UnitCaps: feeCfg.BlockUnitsCap, State: onAcceptState, Tx: duplicateSubnetTx, @@ -715,7 +715,7 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + BlkFeeManager: fees.NewManager(fees.Empty), UnitCaps: feeCfg.BlockUnitsCap, State: onAcceptState, Tx: tx, @@ -753,7 +753,7 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + BlkFeeManager: fees.NewManager(fees.Empty), UnitCaps: feeCfg.BlockUnitsCap, State: onAcceptState, Tx: tx, @@ -789,7 +789,7 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + BlkFeeManager: fees.NewManager(fees.Empty), UnitCaps: feeCfg.BlockUnitsCap, State: onAcceptState, Tx: tx, @@ -835,7 +835,7 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + BlkFeeManager: fees.NewManager(fees.Empty), UnitCaps: feeCfg.BlockUnitsCap, State: onAcceptState, Tx: tx, @@ -875,7 +875,7 @@ func TestBanffStandardTxExecutorAddValidator(t *testing.T) { feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + BlkFeeManager: fees.NewManager(fees.Empty), UnitCaps: feeCfg.BlockUnitsCap, State: onAcceptState, Tx: tx, @@ -919,7 +919,7 @@ func TestBanffStandardTxExecutorAddValidator(t *testing.T) { feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + BlkFeeManager: fees.NewManager(fees.Empty), UnitCaps: feeCfg.BlockUnitsCap, State: onAcceptState, Tx: tx, @@ -960,7 +960,7 @@ func TestBanffStandardTxExecutorAddValidator(t *testing.T) { feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + BlkFeeManager: fees.NewManager(fees.Empty), UnitCaps: feeCfg.BlockUnitsCap, State: onAcceptState, Tx: tx, @@ -1000,7 +1000,7 @@ func TestBanffStandardTxExecutorAddValidator(t *testing.T) { feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + BlkFeeManager: fees.NewManager(fees.Empty), UnitCaps: feeCfg.BlockUnitsCap, State: onAcceptState, Tx: tx, @@ -1587,7 +1587,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + BlkFeeManager: fees.NewManager(fees.Empty), UnitCaps: feeCfg.BlockUnitsCap, Tx: env.tx, State: env.state, @@ -1614,7 +1614,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + BlkFeeManager: fees.NewManager(fees.Empty), UnitCaps: feeCfg.BlockUnitsCap, Tx: env.tx, State: env.state, @@ -1644,7 +1644,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + BlkFeeManager: fees.NewManager(fees.Empty), UnitCaps: feeCfg.BlockUnitsCap, Tx: env.tx, State: env.state, @@ -1677,7 +1677,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + BlkFeeManager: fees.NewManager(fees.Empty), UnitCaps: feeCfg.BlockUnitsCap, Tx: env.tx, State: env.state, @@ -1708,7 +1708,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + BlkFeeManager: fees.NewManager(fees.Empty), UnitCaps: feeCfg.BlockUnitsCap, Tx: env.tx, State: env.state, @@ -1738,7 +1738,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + BlkFeeManager: fees.NewManager(fees.Empty), UnitCaps: feeCfg.BlockUnitsCap, Tx: env.tx, State: env.state, @@ -1770,7 +1770,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + BlkFeeManager: fees.NewManager(fees.Empty), UnitCaps: feeCfg.BlockUnitsCap, Tx: env.tx, State: env.state, @@ -1805,7 +1805,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + BlkFeeManager: fees.NewManager(fees.Empty), UnitCaps: feeCfg.BlockUnitsCap, Tx: env.tx, State: env.state, @@ -1962,7 +1962,7 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + BlkFeeManager: fees.NewManager(fees.Empty), UnitCaps: feeCfg.BlockUnitsCap, Tx: env.tx, State: env.state, @@ -1991,7 +1991,7 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + BlkFeeManager: fees.NewManager(fees.Empty), UnitCaps: feeCfg.BlockUnitsCap, Tx: env.tx, State: env.state, @@ -2022,7 +2022,7 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + BlkFeeManager: fees.NewManager(fees.Empty), UnitCaps: feeCfg.BlockUnitsCap, Tx: env.tx, State: env.state, @@ -2058,7 +2058,7 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + BlkFeeManager: fees.NewManager(fees.Empty), UnitCaps: feeCfg.BlockUnitsCap, Tx: env.tx, State: env.state, @@ -2099,7 +2099,7 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(fees.Empty, fees.EmptyWindows), + BlkFeeManager: fees.NewManager(fees.Empty), UnitCaps: feeCfg.BlockUnitsCap, Tx: env.tx, State: env.state, diff --git a/vms/platformvm/txs/fees/calculator_test.go b/vms/platformvm/txs/fees/calculator_test.go index e0c21467fa61..aa418b2eebe6 100644 --- a/vms/platformvm/txs/fees/calculator_test.go +++ b/vms/platformvm/txs/fees/calculator_test.go @@ -71,7 +71,7 @@ func TestAddAndRemoveFees(t *testing.T) { fc := &Calculator{ IsEUpgradeActive: true, - FeeManager: fees.NewManager(testUnitFees, fees.EmptyWindows), + FeeManager: fees.NewManager(testUnitFees), ConsumedUnitsCap: testBlockMaxConsumedUnits, } @@ -924,7 +924,7 @@ func TestTxFees(t *testing.T) { IsEUpgradeActive: cfg.IsEActivated(chainTime), Config: cfg, ChainTime: chainTime, - FeeManager: fees.NewManager(testUnitFees, fees.EmptyWindows), + FeeManager: fees.NewManager(testUnitFees), ConsumedUnitsCap: consumedUnitCaps, Credentials: sTx.Creds, } diff --git a/vms/platformvm/vm_test.go b/vms/platformvm/vm_test.go index 80e3acd1ad57..865f4a665904 100644 --- a/vms/platformvm/vm_test.go +++ b/vms/platformvm/vm_test.go @@ -376,15 +376,12 @@ func TestGenesis(t *testing.T) { unitFees, err := vm.state.GetUnitFees() require.NoError(err) - feeWindows, err := vm.state.GetFeeWindows() - require.NoError(err) - // we use the first key to fund a subnet creation in [defaultGenesis]. // As such we need to account for the subnet creation fee var ( chainTime = vm.state.GetTimestamp() feeCfg = config.GetDynamicFeesConfig(vm.Config.IsEActivated(chainTime)) - feeMan = commonfees.NewManager(unitFees, feeWindows) + feeMan = commonfees.NewManager(unitFees) feeCalc = &fees.Calculator{ IsEUpgradeActive: vm.IsEActivated(chainTime), Config: &vm.Config, @@ -2278,13 +2275,10 @@ func TestBaseTx(t *testing.T) { unitFees, err := vm.state.GetUnitFees() require.NoError(err) - feeWindows, err := vm.state.GetFeeWindows() - require.NoError(err) - var ( chainTime = vm.state.GetTimestamp() feeCfg = config.GetDynamicFeesConfig(vm.Config.IsEActivated(chainTime)) - feeMan = commonfees.NewManager(unitFees, feeWindows) + feeMan = commonfees.NewManager(unitFees) feeCalc = &fees.Calculator{ IsEUpgradeActive: vm.IsEActivated(chainTime), Config: &vm.Config, diff --git a/wallet/chain/p/builder_test.go b/wallet/chain/p/builder_test.go index e5b13a774821..b550635146e5 100644 --- a/wallet/chain/p/builder_test.go +++ b/wallet/chain/p/builder_test.go @@ -103,7 +103,7 @@ func TestBaseTx(t *testing.T) { { // Post E-Upgrade feeCalc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(testUnitFees), ConsumedUnitsCap: testBlockMaxConsumedUnits, } utx, err := builder.NewBaseTx( @@ -117,7 +117,7 @@ func TestBaseTx(t *testing.T) { fc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(testUnitFees), ConsumedUnitsCap: testBlockMaxConsumedUnits, Credentials: tx.Creds, } @@ -142,7 +142,7 @@ func TestBaseTx(t *testing.T) { Config: &config.Config{ TxFee: testCtx.CreateSubnetTxFee(), }, - FeeManager: commonfees.NewManager(commonfees.Empty, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(commonfees.Empty), ConsumedUnitsCap: commonfees.Max, } utx, err := builder.NewBaseTx( @@ -159,7 +159,7 @@ func TestBaseTx(t *testing.T) { Config: &config.Config{ TxFee: testCtx.CreateSubnetTxFee(), }, - FeeManager: commonfees.NewManager(commonfees.Empty, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(commonfees.Empty), ConsumedUnitsCap: commonfees.Max, Credentials: tx.Creds, } @@ -232,7 +232,7 @@ func TestAddSubnetValidatorTx(t *testing.T) { { // Post E-Upgrade feeCalc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(testUnitFees), ConsumedUnitsCap: testBlockMaxConsumedUnits, } utx, err := builder.NewAddSubnetValidatorTx(subnetValidator, feeCalc) @@ -246,7 +246,7 @@ func TestAddSubnetValidatorTx(t *testing.T) { Config: &config.Config{ AddSubnetValidatorFee: units.MilliAvax, }, - FeeManager: commonfees.NewManager(testUnitFees, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(testUnitFees), ConsumedUnitsCap: testBlockMaxConsumedUnits, Credentials: tx.Creds, } @@ -270,7 +270,7 @@ func TestAddSubnetValidatorTx(t *testing.T) { Config: &config.Config{ AddSubnetValidatorFee: testCtx.AddSubnetValidatorFee(), }, - FeeManager: commonfees.NewManager(commonfees.Empty, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(commonfees.Empty), ConsumedUnitsCap: commonfees.Max, } utx, err := builder.NewAddSubnetValidatorTx(subnetValidator, feeCalc) @@ -284,7 +284,7 @@ func TestAddSubnetValidatorTx(t *testing.T) { Config: &config.Config{ AddSubnetValidatorFee: testCtx.AddSubnetValidatorFee(), }, - FeeManager: commonfees.NewManager(commonfees.Empty, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(commonfees.Empty), ConsumedUnitsCap: commonfees.Max, Credentials: tx.Creds, } @@ -348,7 +348,7 @@ func TestRemoveSubnetValidatorTx(t *testing.T) { { // Post E-Upgrade feeCalc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(testUnitFees), ConsumedUnitsCap: testBlockMaxConsumedUnits, } utx, err := builder.NewRemoveSubnetValidatorTx( @@ -363,7 +363,7 @@ func TestRemoveSubnetValidatorTx(t *testing.T) { fc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(testUnitFees), ConsumedUnitsCap: testBlockMaxConsumedUnits, Credentials: tx.Creds, } @@ -388,7 +388,7 @@ func TestRemoveSubnetValidatorTx(t *testing.T) { Config: &config.Config{ TxFee: testCtx.BaseTxFee(), }, - FeeManager: commonfees.NewManager(commonfees.Empty, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(commonfees.Empty), ConsumedUnitsCap: commonfees.Max, } utx, err := builder.NewRemoveSubnetValidatorTx( @@ -406,7 +406,7 @@ func TestRemoveSubnetValidatorTx(t *testing.T) { Config: &config.Config{ TxFee: testCtx.BaseTxFee(), }, - FeeManager: commonfees.NewManager(commonfees.Empty, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(commonfees.Empty), ConsumedUnitsCap: commonfees.Max, Credentials: tx.Creds, } @@ -476,7 +476,7 @@ func TestCreateChainTx(t *testing.T) { { // Post E-Upgrade feeCalc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(testUnitFees), ConsumedUnitsCap: testBlockMaxConsumedUnits, } utx, err := builder.NewCreateChainTx( @@ -494,7 +494,7 @@ func TestCreateChainTx(t *testing.T) { fc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(testUnitFees), ConsumedUnitsCap: testBlockMaxConsumedUnits, Credentials: tx.Creds, } @@ -518,7 +518,7 @@ func TestCreateChainTx(t *testing.T) { Config: &config.Config{ CreateBlockchainTxFee: testCtx.CreateBlockchainTxFee(), }, - FeeManager: commonfees.NewManager(commonfees.Empty, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(commonfees.Empty), ConsumedUnitsCap: commonfees.Max, } utx, err := builder.NewCreateChainTx( @@ -602,7 +602,7 @@ func TestCreateSubnetTx(t *testing.T) { { // Post E-Upgrade feeCalc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(testUnitFees), ConsumedUnitsCap: testBlockMaxConsumedUnits, } utx, err := builder.NewCreateSubnetTx( @@ -616,7 +616,7 @@ func TestCreateSubnetTx(t *testing.T) { fc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(testUnitFees), ConsumedUnitsCap: testBlockMaxConsumedUnits, Credentials: tx.Creds, } @@ -640,7 +640,7 @@ func TestCreateSubnetTx(t *testing.T) { Config: &config.Config{ CreateSubnetTxFee: testCtx.CreateSubnetTxFee(), }, - FeeManager: commonfees.NewManager(commonfees.Empty, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(commonfees.Empty), ConsumedUnitsCap: commonfees.Max, } utx, err := builder.NewCreateSubnetTx( @@ -657,7 +657,7 @@ func TestCreateSubnetTx(t *testing.T) { Config: &config.Config{ CreateSubnetTxFee: testCtx.CreateSubnetTxFee(), }, - FeeManager: commonfees.NewManager(commonfees.Empty, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(commonfees.Empty), ConsumedUnitsCap: commonfees.Max, Credentials: tx.Creds, } @@ -721,7 +721,7 @@ func TestTransferSubnetOwnershipTx(t *testing.T) { { // Post E-Upgrade feeCalc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(testUnitFees), ConsumedUnitsCap: testBlockMaxConsumedUnits, } utx, err := builder.NewTransferSubnetOwnershipTx( @@ -736,7 +736,7 @@ func TestTransferSubnetOwnershipTx(t *testing.T) { fc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(testUnitFees), ConsumedUnitsCap: testBlockMaxConsumedUnits, Credentials: tx.Creds, } @@ -760,7 +760,7 @@ func TestTransferSubnetOwnershipTx(t *testing.T) { Config: &config.Config{ TxFee: testCtx.BaseTxFee(), }, - FeeManager: commonfees.NewManager(commonfees.Empty, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(commonfees.Empty), ConsumedUnitsCap: commonfees.Max, } utx, err := builder.NewTransferSubnetOwnershipTx( @@ -778,7 +778,7 @@ func TestTransferSubnetOwnershipTx(t *testing.T) { Config: &config.Config{ TxFee: testCtx.BaseTxFee(), }, - FeeManager: commonfees.NewManager(commonfees.Empty, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(commonfees.Empty), ConsumedUnitsCap: commonfees.Max, Credentials: tx.Creds, } @@ -836,7 +836,7 @@ func TestImportTx(t *testing.T) { { // Post E-Upgrade feeCalc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(testUnitFees), ConsumedUnitsCap: testBlockMaxConsumedUnits, } utx, err := builder.NewImportTx( @@ -851,7 +851,7 @@ func TestImportTx(t *testing.T) { fc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(testUnitFees), ConsumedUnitsCap: testBlockMaxConsumedUnits, Credentials: tx.Creds, } @@ -877,7 +877,7 @@ func TestImportTx(t *testing.T) { Config: &config.Config{ TxFee: testCtx.BaseTxFee(), }, - FeeManager: commonfees.NewManager(commonfees.Empty, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(commonfees.Empty), ConsumedUnitsCap: commonfees.Max, } utx, err := builder.NewImportTx( @@ -895,7 +895,7 @@ func TestImportTx(t *testing.T) { Config: &config.Config{ TxFee: testCtx.BaseTxFee(), }, - FeeManager: commonfees.NewManager(commonfees.Empty, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(commonfees.Empty), ConsumedUnitsCap: commonfees.Max, Credentials: tx.Creds, } @@ -955,7 +955,7 @@ func TestExportTx(t *testing.T) { { // Post E-Upgrade feeCalc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(testUnitFees), ConsumedUnitsCap: testBlockMaxConsumedUnits, } utx, err := builder.NewExportTx( @@ -970,7 +970,7 @@ func TestExportTx(t *testing.T) { fc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(testUnitFees), ConsumedUnitsCap: testBlockMaxConsumedUnits, Credentials: tx.Creds, } @@ -995,7 +995,7 @@ func TestExportTx(t *testing.T) { Config: &config.Config{ TxFee: testCtx.BaseTxFee(), }, - FeeManager: commonfees.NewManager(commonfees.Empty, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(commonfees.Empty), ConsumedUnitsCap: commonfees.Max, } utx, err := builder.NewExportTx( @@ -1013,7 +1013,7 @@ func TestExportTx(t *testing.T) { Config: &config.Config{ TxFee: testCtx.BaseTxFee(), }, - FeeManager: commonfees.NewManager(commonfees.Empty, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(commonfees.Empty), ConsumedUnitsCap: commonfees.Max, Credentials: tx.Creds, } @@ -1082,7 +1082,7 @@ func TestTransformSubnetTx(t *testing.T) { { // Post E-Upgrade feeCalc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(testUnitFees), ConsumedUnitsCap: testBlockMaxConsumedUnits, } utx, err := builder.NewTransformSubnetTx( @@ -1109,7 +1109,7 @@ func TestTransformSubnetTx(t *testing.T) { fc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(testUnitFees), ConsumedUnitsCap: testBlockMaxConsumedUnits, Credentials: tx.Creds, } @@ -1136,7 +1136,7 @@ func TestTransformSubnetTx(t *testing.T) { Config: &config.Config{ TransformSubnetTxFee: testCtx.TransformSubnetTxFee(), }, - FeeManager: commonfees.NewManager(commonfees.Empty, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(commonfees.Empty), ConsumedUnitsCap: commonfees.Max, } utx, err := builder.NewTransformSubnetTx( @@ -1166,7 +1166,7 @@ func TestTransformSubnetTx(t *testing.T) { Config: &config.Config{ TransformSubnetTxFee: testCtx.TransformSubnetTxFee(), }, - FeeManager: commonfees.NewManager(commonfees.Empty, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(commonfees.Empty), ConsumedUnitsCap: commonfees.Max, Credentials: tx.Creds, } @@ -1233,7 +1233,7 @@ func TestAddPermissionlessValidatorTx(t *testing.T) { { // Post E-Upgrade feeCalc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(testUnitFees), ConsumedUnitsCap: testBlockMaxConsumedUnits, } utx, err := builder.NewAddPermissionlessValidatorTx( @@ -1259,7 +1259,7 @@ func TestAddPermissionlessValidatorTx(t *testing.T) { fc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(testUnitFees), ConsumedUnitsCap: testBlockMaxConsumedUnits, Credentials: tx.Creds, } @@ -1288,7 +1288,7 @@ func TestAddPermissionlessValidatorTx(t *testing.T) { Config: &config.Config{ AddPrimaryNetworkValidatorFee: testCtx.AddPrimaryNetworkValidatorFee(), }, - FeeManager: commonfees.NewManager(commonfees.Empty, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(commonfees.Empty), ConsumedUnitsCap: commonfees.Max, } utx, err := builder.NewAddPermissionlessValidatorTx( @@ -1317,7 +1317,7 @@ func TestAddPermissionlessValidatorTx(t *testing.T) { Config: &config.Config{ AddPrimaryNetworkValidatorFee: testCtx.AddPrimaryNetworkValidatorFee(), }, - FeeManager: commonfees.NewManager(commonfees.Empty, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(commonfees.Empty), ConsumedUnitsCap: commonfees.Max, Credentials: tx.Creds, } @@ -1377,7 +1377,7 @@ func TestAddPermissionlessDelegatorTx(t *testing.T) { { // Post E-Upgrade feeCalc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(testUnitFees), ConsumedUnitsCap: testBlockMaxConsumedUnits, } utx, err := builder.NewAddPermissionlessDelegatorTx( @@ -1400,7 +1400,7 @@ func TestAddPermissionlessDelegatorTx(t *testing.T) { fc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(testUnitFees), ConsumedUnitsCap: testBlockMaxConsumedUnits, Credentials: tx.Creds, } @@ -1429,7 +1429,7 @@ func TestAddPermissionlessDelegatorTx(t *testing.T) { Config: &config.Config{ AddPrimaryNetworkDelegatorFee: testCtx.AddPrimaryNetworkDelegatorFee(), }, - FeeManager: commonfees.NewManager(commonfees.Empty, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(commonfees.Empty), ConsumedUnitsCap: commonfees.Max, } utx, err := builder.NewAddPermissionlessDelegatorTx( @@ -1455,7 +1455,7 @@ func TestAddPermissionlessDelegatorTx(t *testing.T) { Config: &config.Config{ AddPrimaryNetworkDelegatorFee: testCtx.AddPrimaryNetworkDelegatorFee(), }, - FeeManager: commonfees.NewManager(commonfees.Empty, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(commonfees.Empty), ConsumedUnitsCap: commonfees.Max, Credentials: tx.Creds, } diff --git a/wallet/chain/p/wallet.go b/wallet/chain/p/wallet.go index 241660dbc138..196095e5d615 100644 --- a/wallet/chain/p/wallet.go +++ b/wallet/chain/p/wallet.go @@ -283,7 +283,6 @@ type wallet struct { builder backends.Builder signer backends.Signer unitFees, unitCaps commonfees.Dimensions - feeWindows commonfees.Windows } func (w *wallet) Builder() backends.Builder { @@ -311,7 +310,7 @@ func (w *wallet) IssueBaseTx( Config: &config.Config{ CreateSubnetTxFee: w.CreateSubnetTxFee(), }, - FeeManager: commonfees.NewManager(w.unitFees, w.feeWindows), + FeeManager: commonfees.NewManager(w.unitFees), ConsumedUnitsCap: w.unitCaps, } ) @@ -339,7 +338,7 @@ func (w *wallet) IssueAddValidatorTx( Config: &config.Config{ AddPrimaryNetworkValidatorFee: w.AddPrimaryNetworkValidatorFee(), }, - FeeManager: commonfees.NewManager(w.unitFees, w.feeWindows), + FeeManager: commonfees.NewManager(w.unitFees), ConsumedUnitsCap: w.unitCaps, } @@ -363,7 +362,7 @@ func (w *wallet) IssueAddSubnetValidatorTx( Config: &config.Config{ TxFee: w.BaseTxFee(), }, - FeeManager: commonfees.NewManager(w.unitFees, w.feeWindows), + FeeManager: commonfees.NewManager(w.unitFees), ConsumedUnitsCap: w.unitCaps, } @@ -389,7 +388,7 @@ func (w *wallet) IssueRemoveSubnetValidatorTx( Config: &config.Config{ TxFee: w.BaseTxFee(), }, - FeeManager: commonfees.NewManager(w.unitFees, w.feeWindows), + FeeManager: commonfees.NewManager(w.unitFees), ConsumedUnitsCap: w.unitCaps, } @@ -415,7 +414,7 @@ func (w *wallet) IssueAddDelegatorTx( Config: &config.Config{ AddPrimaryNetworkDelegatorFee: w.AddPrimaryNetworkDelegatorFee(), }, - FeeManager: commonfees.NewManager(w.unitFees, w.feeWindows), + FeeManager: commonfees.NewManager(w.unitFees), ConsumedUnitsCap: w.unitCaps, } @@ -443,7 +442,7 @@ func (w *wallet) IssueCreateChainTx( Config: &config.Config{ CreateBlockchainTxFee: w.CreateBlockchainTxFee(), }, - FeeManager: commonfees.NewManager(w.unitFees, w.feeWindows), + FeeManager: commonfees.NewManager(w.unitFees), ConsumedUnitsCap: w.unitCaps, } @@ -468,7 +467,7 @@ func (w *wallet) IssueCreateSubnetTx( Config: &config.Config{ CreateSubnetTxFee: w.CreateSubnetTxFee(), }, - FeeManager: commonfees.NewManager(w.unitFees, w.feeWindows), + FeeManager: commonfees.NewManager(w.unitFees), ConsumedUnitsCap: w.unitCaps, } utx, err := w.builder.NewCreateSubnetTx(owner, feeCalc, options...) @@ -493,7 +492,7 @@ func (w *wallet) IssueTransferSubnetOwnershipTx( Config: &config.Config{ TxFee: w.BaseTxFee(), }, - FeeManager: commonfees.NewManager(w.unitFees, w.feeWindows), + FeeManager: commonfees.NewManager(w.unitFees), ConsumedUnitsCap: w.unitCaps, } @@ -518,7 +517,7 @@ func (w *wallet) IssueImportTx( Config: &config.Config{ TxFee: w.BaseTxFee(), }, - FeeManager: commonfees.NewManager(w.unitFees, w.feeWindows), + FeeManager: commonfees.NewManager(w.unitFees), ConsumedUnitsCap: w.unitCaps, } @@ -544,7 +543,7 @@ func (w *wallet) IssueExportTx( Config: &config.Config{ TxFee: w.BaseTxFee(), }, - FeeManager: commonfees.NewManager(w.unitFees, w.feeWindows), + FeeManager: commonfees.NewManager(w.unitFees), ConsumedUnitsCap: w.unitCaps, } @@ -582,7 +581,7 @@ func (w *wallet) IssueTransformSubnetTx( Config: &config.Config{ TransformSubnetTxFee: w.TransformSubnetTxFee(), }, - FeeManager: commonfees.NewManager(w.unitFees, w.feeWindows), + FeeManager: commonfees.NewManager(w.unitFees), ConsumedUnitsCap: w.unitCaps, } utx, err := w.builder.NewTransformSubnetTx( @@ -629,7 +628,7 @@ func (w *wallet) IssueAddPermissionlessValidatorTx( AddPrimaryNetworkValidatorFee: w.AddPrimaryNetworkValidatorFee(), AddSubnetValidatorFee: w.AddSubnetValidatorFee(), }, - FeeManager: commonfees.NewManager(w.unitFees, w.feeWindows), + FeeManager: commonfees.NewManager(w.unitFees), ConsumedUnitsCap: w.unitCaps, } @@ -666,7 +665,7 @@ func (w *wallet) IssueAddPermissionlessDelegatorTx( AddPrimaryNetworkDelegatorFee: w.AddPrimaryNetworkDelegatorFee(), AddSubnetDelegatorFee: w.AddSubnetDelegatorFee(), }, - FeeManager: commonfees.NewManager(w.unitFees, w.feeWindows), + FeeManager: commonfees.NewManager(w.unitFees), ConsumedUnitsCap: w.unitCaps, } @@ -752,11 +751,6 @@ func (w *wallet) refreshFeesData(options ...common.Option) error { return err } - w.feeWindows, err = w.client.GetFeeWindows(ctx) - if err != nil { - return err - } - feeCfg := config.GetDynamicFeesConfig(w.isEForkActive) w.unitCaps = feeCfg.BlockUnitsCap return nil From a18732f2cb68f08b15e8edc9b0e2b89bc7ac026a Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 14 Mar 2024 20:50:14 +0100 Subject: [PATCH 125/190] fixed unit fees update --- vms/components/fees/manager.go | 11 +++--- vms/platformvm/block/builder/builder.go | 5 ++- vms/platformvm/block/executor/manager.go | 8 +++-- vms/platformvm/block/executor/verifier.go | 43 +++++++++++++++++------ 4 files changed, 48 insertions(+), 19 deletions(-) diff --git a/vms/components/fees/manager.go b/vms/components/fees/manager.go index 0a96735f95b3..7a28975cea3f 100644 --- a/vms/components/fees/manager.go +++ b/vms/components/fees/manager.go @@ -94,14 +94,15 @@ func (m *Manager) RemoveUnits(unitsToRm Dimensions) error { // [UpdateWindows] stores in the fee windows the units cumulated in current block func (m *Manager) UpdateWindows(windows *Windows, lastTime, currTime int64) { - var ( - since = int(currTime - lastTime) - latestIdx = WindowSize - 1 - ) + since := int(currTime - lastTime) + idx := 0 + if since < WindowSize { + idx = WindowSize - 1 - since + } for i := Dimension(0); i < FeeDimensions; i++ { windows[i] = Roll(windows[i], since) - Update(&windows[i], latestIdx, m.cumulatedUnits[i]) + Update(&windows[i], idx, m.cumulatedUnits[i]) } } diff --git a/vms/platformvm/block/builder/builder.go b/vms/platformvm/block/builder/builder.go index 346f1740b014..8d1661b4d2ad 100644 --- a/vms/platformvm/block/builder/builder.go +++ b/vms/platformvm/block/builder/builder.go @@ -324,6 +324,9 @@ func packBlockTxs( timestamp time.Time, remainingSize int, ) ([]*txs.Tx, error) { + // retrieve parent block time before moving time forward + parentBlkTime := parentState.GetTimestamp() + stateDiff, err := state.NewDiffOn(parentState) if err != nil { return nil, err @@ -355,7 +358,7 @@ func packBlockTxs( feeMan.UpdateUnitFees( feesCfg, feeWindows, - parentState.GetTimestamp().Unix(), + parentBlkTime.Unix(), timestamp.Unix(), ) } diff --git a/vms/platformvm/block/executor/manager.go b/vms/platformvm/block/executor/manager.go index 732a717e28b6..cf3e6b21a76b 100644 --- a/vms/platformvm/block/executor/manager.go +++ b/vms/platformvm/block/executor/manager.go @@ -134,6 +134,9 @@ func (m *manager) VerifyTx(tx *txs.Tx) error { return err } + // retrieve parent block time before moving time forward + parentBlkTime := stateDiff.GetTimestamp() + nextBlkTime, _, err := executor.NextBlockTime(stateDiff, m.txExecutorBackend.Clk) if err != nil { return err @@ -154,8 +157,7 @@ func (m *manager) VerifyTx(tx *txs.Tx) error { } var ( - chainTime = stateDiff.GetTimestamp() - isEActivated = m.txExecutorBackend.Config.IsEActivated(chainTime) + isEActivated = m.txExecutorBackend.Config.IsEActivated(nextBlkTime) feesCfg = config.GetDynamicFeesConfig(isEActivated) ) @@ -164,7 +166,7 @@ func (m *manager) VerifyTx(tx *txs.Tx) error { feeManager.UpdateUnitFees( feesCfg, feeWindows, - chainTime.Unix(), + parentBlkTime.Unix(), nextBlkTime.Unix(), ) } diff --git a/vms/platformvm/block/executor/verifier.go b/vms/platformvm/block/executor/verifier.go index 80d88dba3fbe..2d7cdfb3902c 100644 --- a/vms/platformvm/block/executor/verifier.go +++ b/vms/platformvm/block/executor/verifier.go @@ -63,13 +63,22 @@ 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 } - inputs, feesMan, atomicRequests, onAcceptFunc, err := v.processStandardTxs(b.Transactions, onDecisionState, b.Parent(), b.Timestamp()) + inputs, feesMan, atomicRequests, onAcceptFunc, err := v.processStandardTxs( + b.Transactions, + onDecisionState, + b.Parent(), + parentBlkTime, + b.Timestamp(), + ) if err != nil { return err } @@ -107,6 +116,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, @@ -123,7 +135,7 @@ func (v *verifier) BanffStandardBlock(b *block.BanffStandardBlock) error { return errBanffStandardBlockWithoutChanges } - return v.standardBlock(&b.ApricotStandardBlock, b.Timestamp(), onAcceptState) + return v.standardBlock(&b.ApricotStandardBlock, parentBlkTime, b.Timestamp(), onAcceptState) } func (v *verifier) ApricotAbortBlock(b *block.ApricotAbortBlock) error { @@ -169,7 +181,7 @@ func (v *verifier) ApricotStandardBlock(b *block.ApricotStandardBlock) error { return err } - return v.standardBlock(b, time.Time{}, onAcceptState) + return v.standardBlock(b, time.Time{}, time.Time{}, onAcceptState) } func (v *verifier) ApricotAtomicBlock(b *block.ApricotAtomicBlock) error { @@ -416,10 +428,17 @@ func (v *verifier) proposalBlock( // standardBlock populates the state of this block if [nil] is returned func (v *verifier) standardBlock( b *block.ApricotStandardBlock, + parentBlkTime time.Time, blkTimestamp time.Time, onAcceptState state.Diff, ) error { - inputs, feeMan, atomicRequests, onAcceptFunc, err := v.processStandardTxs(b.Transactions, onAcceptState, b.Parent(), blkTimestamp) + inputs, feeMan, atomicRequests, onAcceptFunc, err := v.processStandardTxs( + b.Transactions, + onAcceptState, + b.Parent(), + parentBlkTime, + blkTimestamp, + ) if err != nil { return err } @@ -441,7 +460,12 @@ func (v *verifier) standardBlock( return nil } -func (v *verifier) processStandardTxs(txs []*txs.Tx, state state.Diff, parentID ids.ID, blkTimestamp time.Time) ( +func (v *verifier) processStandardTxs( + txs []*txs.Tx, + state state.Diff, + parentID ids.ID, + parentBlkTime, blkTimestamp time.Time, +) ( set.Set[ids.ID], *fees.Manager, map[ids.ID]*atomic.Requests, @@ -458,9 +482,8 @@ func (v *verifier) processStandardTxs(txs []*txs.Tx, state state.Diff, parentID } var ( - currentTimestamp = state.GetTimestamp() - isEActivated = v.txExecutorBackend.Config.IsEActivated(currentTimestamp) - feesCfg = config.GetDynamicFeesConfig(isEActivated) + isEActivated = v.txExecutorBackend.Config.IsEActivated(parentBlkTime) + feesCfg = config.GetDynamicFeesConfig(isEActivated) onAcceptFunc func() inputs set.Set[ids.ID] @@ -473,7 +496,7 @@ func (v *verifier) processStandardTxs(txs []*txs.Tx, state state.Diff, parentID feeManager.UpdateUnitFees( feesCfg, feeWindows, - currentTimestamp.Unix(), + parentBlkTime.Unix(), blkTimestamp.Unix(), ) } @@ -521,7 +544,7 @@ func (v *verifier) processStandardTxs(txs []*txs.Tx, state state.Diff, parentID } if isEActivated { - feeManager.UpdateWindows(&feeWindows, currentTimestamp.Unix(), blkTimestamp.Unix()) + feeManager.UpdateWindows(&feeWindows, parentBlkTime.Unix(), blkTimestamp.Unix()) state.SetUnitFees(feeManager.GetUnitFees()) state.SetFeeWindows(feeWindows) } From a3ae61abc6e343f9a3dc5968a1bd313ba236fdc0 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 18 Mar 2024 14:19:38 +0100 Subject: [PATCH 126/190] removed floats from fee update algo --- vms/components/fees/manager.go | 14 ++++----- vms/components/fees/manager_test.go | 48 ++++++++++++++--------------- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/vms/components/fees/manager.go b/vms/components/fees/manager.go index 7a28975cea3f..8fc2344e4547 100644 --- a/vms/components/fees/manager.go +++ b/vms/components/fees/manager.go @@ -123,22 +123,22 @@ func (m *Manager) UpdateUnitFees( func nextFeeRate(currentUnitFee, updateCoefficient, unitsConsumed, target uint64) uint64 { // We update the fee rate with the formula e^{k(u-t)/t} == 2^{1/ln(2) * k(u-t)/t} - // We approximate 1/ln(2) with 1,442695 and we round the exponent to a uint64 + // We approximate 1/ln(2) with 1_442/1_000 and we round the exponent to a uint64 switch { case unitsConsumed > target: - exp := float64(1.442695) * float64(updateCoefficient*(unitsConsumed-target)) / float64(target) - intExp := min(uint64(math.Ceil(exp)), 62) // we cap the exponent to avoid an overflow of uint64 type - res, over := safemath.Mul64(currentUnitFee, 1< Date: Wed, 20 Mar 2024 15:06:23 +0100 Subject: [PATCH 127/190] fixed unitFees initialization in state package --- vms/platformvm/state/state.go | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/vms/platformvm/state/state.go b/vms/platformvm/state/state.go index 6b1a7cb72274..6e3d9a8e46ec 100644 --- a/vms/platformvm/state/state.go +++ b/vms/platformvm/state/state.go @@ -344,7 +344,7 @@ type state struct { // The persisted fields represent the current database value timestamp, persistedTimestamp time.Time - unitFees commonfees.Dimensions + unitFees *commonfees.Dimensions // pointer, to allow customization for test networks feesWindows commonfees.Windows currentSupply, persistedCurrentSupply uint64 lastAccepted, persistedLastAccepted ids.ID @@ -1002,11 +1002,12 @@ func (s *state) GetStartTime(nodeID ids.NodeID, subnetID ids.ID) (time.Time, err } func (s *state) GetUnitFees() (commonfees.Dimensions, error) { - return s.unitFees, nil + return *s.unitFees, nil } func (s *state) SetUnitFees(uf commonfees.Dimensions) { - s.unitFees = uf + unitFees := uf + s.unitFees = &unitFees } func (s *state) GetFeeWindows() (commonfees.Windows, error) { @@ -1352,6 +1353,7 @@ func (s *state) loadMetadata() error { s.persistedTimestamp = timestamp s.SetTimestamp(timestamp) + s.unitFees = new(commonfees.Dimensions) switch unitFeesBytes, err := s.singletonDB.Get(UnitFeesKey); err { case nil: if err := s.unitFees.FromBytes(unitFeesBytes); err != nil { @@ -1363,7 +1365,7 @@ func (s *state) loadMetadata() error { // hence we may have never stored unit fees. Load from config // TODO: remove once fork is active isEActive := s.cfg.IsEActivated(timestamp) - s.unitFees = config.GetDynamicFeesConfig(isEActive).InitialUnitFees + *s.unitFees = config.GetDynamicFeesConfig(isEActive).InitialUnitFees default: return err @@ -2394,8 +2396,11 @@ func (s *state) writeMetadata() error { } s.persistedTimestamp = s.timestamp } - if err := s.singletonDB.Put(UnitFeesKey, s.unitFees.Bytes()); err != nil { - return fmt.Errorf("failed to write unit fees: %w", err) + + if s.unitFees != nil { + if err := s.singletonDB.Put(UnitFeesKey, s.unitFees.Bytes()); err != nil { + return fmt.Errorf("failed to write unit fees: %w", err) + } } if err := s.singletonDB.Put(FeesWindowsKey, s.feesWindows.Bytes()); err != nil { return fmt.Errorf("failed to write unit fees: %w", err) From 1f3bf48f76ec1175db96610dcd16007961b5c230 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Wed, 20 Mar 2024 15:35:06 +0100 Subject: [PATCH 128/190] wip: adding dynamic fees e2e test --- tests/e2e/p/dynamic_fees.go | 122 ++++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 tests/e2e/p/dynamic_fees.go diff --git a/tests/e2e/p/dynamic_fees.go b/tests/e2e/p/dynamic_fees.go new file mode 100644 index 000000000000..63979f63cc0d --- /dev/null +++ b/tests/e2e/p/dynamic_fees.go @@ -0,0 +1,122 @@ +// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package p + +import ( + "fmt" + "math" + + "github.com/stretchr/testify/require" + + "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/tests" + "github.com/ava-labs/avalanchego/tests/fixture/e2e" + "github.com/ava-labs/avalanchego/tests/fixture/tmpnet" + "github.com/ava-labs/avalanchego/vms/platformvm" + "github.com/ava-labs/avalanchego/vms/secp256k1fx" + + commonfees "github.com/ava-labs/avalanchego/vms/components/fees" + ginkgo "github.com/onsi/ginkgo/v2" +) + +var _ = ginkgo.Describe("[Dynamic Fees]", func() { + require := require.New(ginkgo.GinkgoT()) + + ginkgo.It("should ensure that the dynamic multifees are affected by load", func() { + customDynamicFeesConfig := commonfees.DynamicFeesConfig{ + InitialUnitFees: commonfees.Dimensions{1, 2, 3, 4}, + MinUnitFees: commonfees.Dimensions{1, 1, 1, 1}, + UpdateCoefficient: commonfees.Dimensions{1, 1, 1, 1}, + BlockUnitsCap: commonfees.Dimensions{math.MaxUint64, math.MaxUint64, math.MaxUint64, math.MaxUint64}, + BlockUnitsTarget: commonfees.Dimensions{1_000, 1_000, 1_000, 3_000}, + } + + ginkgo.By("creating a new private network to ensure isolation from other tests") + privateNetwork := &tmpnet.Network{ + Owner: "avalanchego-e2e-dynamic-fees", + ChainConfigs: map[string]tmpnet.FlagsMap{ + "P": { + "dynamic-fees-config": customDynamicFeesConfig, + }, + }, + } + e2e.Env.StartPrivateNetwork(privateNetwork) + + ginkgo.By("setup a wallet and a P-chain client") + node := privateNetwork.Nodes[0] + nodeURI := tmpnet.NodeURI{ + NodeID: node.NodeID, + URI: node.URI, + } + keychain := secp256k1fx.NewKeychain(privateNetwork.PreFundedKeys...) + baseWallet := e2e.NewWallet(keychain, nodeURI) + pWallet := baseWallet.P() + pChainClient := platformvm.NewClient(nodeURI.URI) + + // retrieve initial balances + pBuilder := pWallet.Builder() + pContext := pBuilder.Context() + avaxAssetID := pContext.AVAXAssetID + pBalances, err := pWallet.Builder().GetBalance() + require.NoError(err) + pStartBalance := pBalances[avaxAssetID] + tests.Outf("{{blue}} P-chain balance before P->X export: %d {{/}}\n", pStartBalance) + + ginkgo.By("checking that initial fee values match with configured ones", func() { + currUnitFees, _, err := pChainClient.GetUnitFees(e2e.DefaultContext()) + require.NoError(err) + require.Equal(customDynamicFeesConfig.InitialUnitFees, currUnitFees) + }) + + ginkgo.By("issue expensive transactions so to increase the unit fees to be paid for accepting the transactons", + func() { + initialOwner := &secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{ + keychain.Keys[0].Address(), + }, + } + + var subnetID ids.ID + ginkgo.By("create a permissioned subnet", func() { + subnetTx, err := pWallet.IssueCreateSubnetTx( + initialOwner, + e2e.WithDefaultContext(), + ) + require.NoError(err) + + subnetID = subnetTx.ID() + }) + + currUnitFees, _, err := pChainClient.GetUnitFees(e2e.DefaultContext()) + require.NoError(err) + ginkgo.By(fmt.Sprintf("current unit fees: %v", currUnitFees)) + + ginkgo.By("repeatedly change the permissioned subnet owner", func() { + txsCount := 10 + for i := 0; i < txsCount; i++ { + nextOwner := &secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{ + keychain.Keys[1].Address(), + }, + } + + _, err = pWallet.IssueTransferSubnetOwnershipTx( + subnetID, + nextOwner, + e2e.WithDefaultContext(), + ) + require.NoError(err) + + updatedUnitFees, _, err := pChainClient.GetUnitFees(e2e.DefaultContext()) + require.NoError(err) + ginkgo.By(fmt.Sprintf("current unit fees: %v", updatedUnitFees)) + currUnitFees = updatedUnitFees + } + }) + }, + ) + }) +}) From 3412187318255f430f8ee3772ebad4a26573e9aa Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 21 Mar 2024 09:29:04 +0100 Subject: [PATCH 129/190] increased block target units to avoid e2e failures --- vms/platformvm/config/dynamic_fees_config.go | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/vms/platformvm/config/dynamic_fees_config.go b/vms/platformvm/config/dynamic_fees_config.go index 6b4a75abe124..ffc9057745e6 100644 --- a/vms/platformvm/config/dynamic_fees_config.go +++ b/vms/platformvm/config/dynamic_fees_config.go @@ -34,15 +34,20 @@ var ( 3 * units.NanoAvax, 4 * units.NanoAvax, }, - MinUnitFees: commonfees.Dimensions{}, + MinUnitFees: commonfees.Empty, UpdateCoefficient: commonfees.Dimensions{ 1, 1, 1, 1, }, - BlockUnitsCap: commonfees.Max, - BlockUnitsTarget: commonfees.Dimensions{1, 1, 1, 1}, + BlockUnitsCap: commonfees.Max, + BlockUnitsTarget: commonfees.Dimensions{ + 1000, + 1000, + 1000, + 1000, + }, } // TODO ABENEGIA: decide if and how to validate preEUpgradeDynamicFeesConfig From 39eac30f9954158e675efd54340404afe5982ede Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 21 Mar 2024 10:33:30 +0100 Subject: [PATCH 130/190] futher increase of block target units --- vms/platformvm/config/dynamic_fees_config.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/vms/platformvm/config/dynamic_fees_config.go b/vms/platformvm/config/dynamic_fees_config.go index ffc9057745e6..73bfa08fbf8d 100644 --- a/vms/platformvm/config/dynamic_fees_config.go +++ b/vms/platformvm/config/dynamic_fees_config.go @@ -43,10 +43,10 @@ var ( }, BlockUnitsCap: commonfees.Max, BlockUnitsTarget: commonfees.Dimensions{ - 1000, - 1000, - 1000, - 1000, + 2000, + 2000, + 2000, + 4000, }, } From db739334a9ae861d5ee04621e027ed5079d68ca4 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 21 Mar 2024 11:51:14 +0100 Subject: [PATCH 131/190] dynamic fees e2e test, added checks --- tests/e2e/p/dynamic_fees.go | 26 +++++++++++++++++++++----- vms/components/fees/dimensions.go | 3 +++ 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/tests/e2e/p/dynamic_fees.go b/tests/e2e/p/dynamic_fees.go index 63979f63cc0d..90f304fcdf85 100644 --- a/tests/e2e/p/dynamic_fees.go +++ b/tests/e2e/p/dynamic_fees.go @@ -4,7 +4,6 @@ package p import ( - "fmt" "math" "github.com/stretchr/testify/require" @@ -29,7 +28,9 @@ var _ = ginkgo.Describe("[Dynamic Fees]", func() { MinUnitFees: commonfees.Dimensions{1, 1, 1, 1}, UpdateCoefficient: commonfees.Dimensions{1, 1, 1, 1}, BlockUnitsCap: commonfees.Dimensions{math.MaxUint64, math.MaxUint64, math.MaxUint64, math.MaxUint64}, - BlockUnitsTarget: commonfees.Dimensions{1_000, 1_000, 1_000, 3_000}, + + // BlockUnitsTarget are set to cause an increase of fees while simple transactions are issued + BlockUnitsTarget: commonfees.Dimensions{1_000, 1_000, 1_000, 3_000}, } ginkgo.By("creating a new private network to ensure isolation from other tests") @@ -91,9 +92,9 @@ var _ = ginkgo.Describe("[Dynamic Fees]", func() { currUnitFees, _, err := pChainClient.GetUnitFees(e2e.DefaultContext()) require.NoError(err) - ginkgo.By(fmt.Sprintf("current unit fees: %v", currUnitFees)) + tests.Outf("{{blue}} current unit fees: %v {{/}}\n", currUnitFees) - ginkgo.By("repeatedly change the permissioned subnet owner", func() { + ginkgo.By("repeatedly change the permissioned subnet owner to increase unit fees", func() { txsCount := 10 for i := 0; i < txsCount; i++ { nextOwner := &secp256k1fx.OutputOwners{ @@ -112,10 +113,25 @@ var _ = ginkgo.Describe("[Dynamic Fees]", func() { updatedUnitFees, _, err := pChainClient.GetUnitFees(e2e.DefaultContext()) require.NoError(err) - ginkgo.By(fmt.Sprintf("current unit fees: %v", updatedUnitFees)) + tests.Outf("{{blue}} current unit fees: %v {{/}}\n", updatedUnitFees) + + ginkgo.By("check that unit fees components have increased") + require.True(commonfees.Compare(currUnitFees, updatedUnitFees)) currUnitFees = updatedUnitFees } }) + + ginkgo.By("wait for the unit fees to decrease", func() { + initialUnitFees := currUnitFees + e2e.Eventually(func() bool { + var err error + _, currUnitFees, err = pChainClient.GetUnitFees(e2e.DefaultContext()) + require.NoError(err) + tests.Outf("{{blue}} next unit fees: %v {{/}}\n", currUnitFees) + return commonfees.Compare(initialUnitFees, currUnitFees) + }, e2e.DefaultTimeout, e2e.DefaultPollingInterval, "failed to see gas price decrease before timeout") + tests.Outf("\n{{blue}}unit fees have decreased to %v{{/}}\n", currUnitFees) + }) }, ) }) diff --git a/vms/components/fees/dimensions.go b/vms/components/fees/dimensions.go index a42e55226f00..36a35f438ab0 100644 --- a/vms/components/fees/dimensions.go +++ b/vms/components/fees/dimensions.go @@ -72,6 +72,9 @@ func Add(lhs, rhs Dimensions) (Dimensions, error) { return res, nil } +// [Compare] returns true only if rhs[i] >= lhs[i] for each dimensions +// Arrays ordering is not total, so we avoided naming [Compare] as [Less] +// to discourage improper use func Compare(lhs, rhs Dimensions) bool { for i := 0; i < FeeDimensions; i++ { if lhs[i] > rhs[i] { From 38cbc9c93e56a27e98ed013fdd7cd276a1c983e0 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 21 Mar 2024 13:33:43 +0100 Subject: [PATCH 132/190] restructured fee rate update algo --- tests/e2e/p/dynamic_fees.go | 44 +-- tests/e2e/p/permissionless_subnets.go | 2 +- tests/e2e/p/workflow.go | 6 +- vms/components/fees/config.go | 55 ++-- vms/components/fees/manager.go | 115 +++---- vms/components/fees/manager_test.go | 259 ++++++---------- vms/platformvm/block/builder/builder.go | 26 +- vms/platformvm/block/builder/helpers_test.go | 12 +- vms/platformvm/block/executor/helpers_test.go | 12 +- vms/platformvm/block/executor/manager.go | 25 +- .../block/executor/proposal_block_test.go | 4 +- .../block/executor/standard_block_test.go | 8 +- vms/platformvm/block/executor/verifier.go | 33 +- .../block/executor/verifier_test.go | 8 +- vms/platformvm/client.go | 8 +- vms/platformvm/config/dynamic_fees_config.go | 12 +- vms/platformvm/service.go | 22 +- vms/platformvm/service_test.go | 18 +- vms/platformvm/state/diff.go | 54 ++-- vms/platformvm/state/mock_state.go | 180 +++++------ vms/platformvm/state/state.go | 56 ++-- vms/platformvm/txs/builder/builder.go | 78 ++--- .../txs/executor/atomic_tx_executor.go | 10 +- .../txs/executor/create_chain_test.go | 58 ++-- .../txs/executor/create_subnet_test.go | 14 +- vms/platformvm/txs/executor/helpers_test.go | 12 +- .../txs/executor/standard_tx_executor.go | 30 +- .../txs/executor/standard_tx_executor_test.go | 284 +++++++++--------- vms/platformvm/txs/fees/calculator.go | 4 +- vms/platformvm/txs/fees/calculator_test.go | 30 +- vms/platformvm/vm_test.go | 10 +- wallet/chain/p/wallet.go | 60 ++-- 32 files changed, 740 insertions(+), 809 deletions(-) diff --git a/tests/e2e/p/dynamic_fees.go b/tests/e2e/p/dynamic_fees.go index 90f304fcdf85..bc10b700839a 100644 --- a/tests/e2e/p/dynamic_fees.go +++ b/tests/e2e/p/dynamic_fees.go @@ -24,13 +24,13 @@ var _ = ginkgo.Describe("[Dynamic Fees]", func() { ginkgo.It("should ensure that the dynamic multifees are affected by load", func() { customDynamicFeesConfig := commonfees.DynamicFeesConfig{ - InitialUnitFees: commonfees.Dimensions{1, 2, 3, 4}, - MinUnitFees: commonfees.Dimensions{1, 1, 1, 1}, - UpdateCoefficient: commonfees.Dimensions{1, 1, 1, 1}, - BlockUnitsCap: commonfees.Dimensions{math.MaxUint64, math.MaxUint64, math.MaxUint64, math.MaxUint64}, + InitialFeeRate: commonfees.Dimensions{1, 2, 3, 4}, + MinFeeRate: commonfees.Dimensions{1, 1, 1, 1}, + UpdateCoefficient: commonfees.Dimensions{1, 1, 1, 1}, + BlockMaxComplexity: commonfees.Dimensions{math.MaxUint64, math.MaxUint64, math.MaxUint64, math.MaxUint64}, // BlockUnitsTarget are set to cause an increase of fees while simple transactions are issued - BlockUnitsTarget: commonfees.Dimensions{1_000, 1_000, 1_000, 3_000}, + BlockTargetComplexityRate: commonfees.Dimensions{1_000, 1_000, 1_000, 3_000}, } ginkgo.By("creating a new private network to ensure isolation from other tests") @@ -65,12 +65,12 @@ var _ = ginkgo.Describe("[Dynamic Fees]", func() { tests.Outf("{{blue}} P-chain balance before P->X export: %d {{/}}\n", pStartBalance) ginkgo.By("checking that initial fee values match with configured ones", func() { - currUnitFees, _, err := pChainClient.GetUnitFees(e2e.DefaultContext()) + currFeeRates, _, err := pChainClient.GetFeeRates(e2e.DefaultContext()) require.NoError(err) - require.Equal(customDynamicFeesConfig.InitialUnitFees, currUnitFees) + require.Equal(customDynamicFeesConfig.InitialFeeRate, currFeeRates) }) - ginkgo.By("issue expensive transactions so to increase the unit fees to be paid for accepting the transactons", + ginkgo.By("issue expensive transactions so to increase the fee rates to be paid for accepting the transactons", func() { initialOwner := &secp256k1fx.OutputOwners{ Threshold: 1, @@ -90,11 +90,11 @@ var _ = ginkgo.Describe("[Dynamic Fees]", func() { subnetID = subnetTx.ID() }) - currUnitFees, _, err := pChainClient.GetUnitFees(e2e.DefaultContext()) + currFeeRates, _, err := pChainClient.GetFeeRates(e2e.DefaultContext()) require.NoError(err) - tests.Outf("{{blue}} current unit fees: %v {{/}}\n", currUnitFees) + tests.Outf("{{blue}} current fee rates: %v {{/}}\n", currFeeRates) - ginkgo.By("repeatedly change the permissioned subnet owner to increase unit fees", func() { + ginkgo.By("repeatedly change the permissioned subnet owner to increase fee rates", func() { txsCount := 10 for i := 0; i < txsCount; i++ { nextOwner := &secp256k1fx.OutputOwners{ @@ -111,26 +111,26 @@ var _ = ginkgo.Describe("[Dynamic Fees]", func() { ) require.NoError(err) - updatedUnitFees, _, err := pChainClient.GetUnitFees(e2e.DefaultContext()) + updatedFeeRates, _, err := pChainClient.GetFeeRates(e2e.DefaultContext()) require.NoError(err) - tests.Outf("{{blue}} current unit fees: %v {{/}}\n", updatedUnitFees) + tests.Outf("{{blue}} current fee rates: %v {{/}}\n", updatedFeeRates) - ginkgo.By("check that unit fees components have increased") - require.True(commonfees.Compare(currUnitFees, updatedUnitFees)) - currUnitFees = updatedUnitFees + ginkgo.By("check that fee rates components have increased") + require.True(commonfees.Compare(currFeeRates, updatedFeeRates)) + currFeeRates = updatedFeeRates } }) - ginkgo.By("wait for the unit fees to decrease", func() { - initialUnitFees := currUnitFees + ginkgo.By("wait for the fee rates to decrease", func() { + initialUnitFees := currFeeRates e2e.Eventually(func() bool { var err error - _, currUnitFees, err = pChainClient.GetUnitFees(e2e.DefaultContext()) + _, currFeeRates, err = pChainClient.GetFeeRates(e2e.DefaultContext()) require.NoError(err) - tests.Outf("{{blue}} next unit fees: %v {{/}}\n", currUnitFees) - return commonfees.Compare(initialUnitFees, currUnitFees) + tests.Outf("{{blue}} next fee rates: %v {{/}}\n", currFeeRates) + return commonfees.Compare(initialUnitFees, currFeeRates) }, e2e.DefaultTimeout, e2e.DefaultPollingInterval, "failed to see gas price decrease before timeout") - tests.Outf("\n{{blue}}unit fees have decreased to %v{{/}}\n", currUnitFees) + tests.Outf("\n{{blue}}fee rates have decreased to %v{{/}}\n", currFeeRates) }) }, ) diff --git a/tests/e2e/p/permissionless_subnets.go b/tests/e2e/p/permissionless_subnets.go index dc92bdd60d5c..bb3dfec0e949 100644 --- a/tests/e2e/p/permissionless_subnets.go +++ b/tests/e2e/p/permissionless_subnets.go @@ -61,9 +61,9 @@ var _ = e2e.DescribePChain("[Permissionless Subnets]", func() { owner, e2e.WithDefaultContext(), ) + require.NoError(err) subnetID = subnetTx.ID() - require.NoError(err) require.NotEqual(subnetID, constants.PrimaryNetworkID) }) diff --git a/tests/e2e/p/workflow.go b/tests/e2e/p/workflow.go index e9e1d40956e5..87a40fb54a38 100644 --- a/tests/e2e/p/workflow.go +++ b/tests/e2e/p/workflow.go @@ -141,9 +141,9 @@ var _ = e2e.DescribePChain("[Workflow]", func() { pChainExportFee := uint64(0) ginkgo.By("export avax from P to X chain", func() { - unitCaps := config.GetDynamicFeesConfig(true /*isEActive*/).BlockUnitsCap + unitCaps := config.GetDynamicFeesConfig(true /*isEActive*/).BlockMaxComplexity - _, nextUnitFees, err := pChainClient.GetUnitFees(e2e.DefaultContext()) + _, nextFeeRates, err := pChainClient.GetFeeRates(e2e.DefaultContext()) require.NoError(err) tx, err := pWallet.IssueExportTx( @@ -163,7 +163,7 @@ var _ = e2e.DescribePChain("[Workflow]", func() { // retrieve fees paid for the tx feeCalc := fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(nextUnitFees), + FeeManager: commonfees.NewManager(nextFeeRates), ConsumedUnitsCap: unitCaps, Credentials: tx.Creds, } diff --git a/vms/components/fees/config.go b/vms/components/fees/config.go index 4009d8f816cb..eb9b4af12d9a 100644 --- a/vms/components/fees/config.go +++ b/vms/components/fees/config.go @@ -6,53 +6,56 @@ package fees import "fmt" type DynamicFeesConfig struct { - // InitialUnitFees contains, per each fee dimension, the - // unit fees valid as soon as fork introducing dynamic fees - // activates. Unit fees will be then updated by the dynamic fees algo. - InitialUnitFees Dimensions `json:"initial-unit-fees"` + // InitialFeeRate contains, per each fee dimension, the + // fee rate, i.e. the fee per unit of complexity. Fee rates are + // valid as soon as fork introducing dynamic fees activates. + // Fee rates will be then updated by the dynamic fees algo. + InitialFeeRate Dimensions `json:"initial-fee-rate"` - // MinUnitFees contains, per each fee dimension, the - // minimal unit fees enforced by the dynamic fees algo. - MinUnitFees Dimensions `json:"min-unit-fees"` + // MinFeeRate contains, per each fee dimension, the + // minimal fee rate, i.e. the fee per unit of complexity, + // enforced by the dynamic fees algo. + MinFeeRate Dimensions `json:"minimal-fee-rate"` // UpdateCoefficient contains, per each fee dimension, the // exponential update coefficient. Setting an entry to 0 makes // the corresponding fee rate constant. UpdateCoefficient Dimensions `json:"update-coefficient"` - // BlockUnitsCap contains, per each fee dimension, the - // maximal complexity a valid P-chain block can host - BlockUnitsCap Dimensions `json:"block-unit-caps"` - - // BlockUnitsTarget contains, per each fee dimension, the + // BlockTargetComplexityRate contains, per each fee dimension, the // preferred block complexity that the dynamic fee algo - // strive to converge to - BlockUnitsTarget Dimensions `json:"block-target-caps"` + // strive to converge to, per second. + BlockTargetComplexityRate Dimensions `json:"block-target-complexity-rate"` + + // BlockMaxComplexity contains, per each fee dimension, the + // maximal complexity a valid P-chain block can host. + BlockMaxComplexity Dimensions `json:"block-max-complexity-rate"` } func (c *DynamicFeesConfig) Validate() error { for i := Dimension(0); i < FeeDimensions; i++ { - // MinUnitFees can be zero, but that is a bit dangerous. if a fee ever becomes + // MinFeeRate can be zero, but that is a bit dangerous. If a fee rate ever becomes // zero, the update mechanism will keep them to zero. - - if c.InitialUnitFees[i] < c.MinUnitFees[i] { - return fmt.Errorf("dimension %d, initial unit fee %d smaller than minimal unit fee %d", + if c.InitialFeeRate[i] < c.MinFeeRate[i] { + return fmt.Errorf("dimension %d, initial fee rate %d smaller than minimal fee rate %d", i, - c.InitialUnitFees[i], - c.MinUnitFees[i], + c.InitialFeeRate[i], + c.MinFeeRate[i], ) } - if c.BlockUnitsTarget[i] > c.BlockUnitsCap[i] { - return fmt.Errorf("dimension %d, block target units %d larger than block units cap %d", + if c.BlockTargetComplexityRate[i] > c.BlockMaxComplexity[i] { + return fmt.Errorf("dimension %d, block target complexity rate %d larger than block max complexity rate %d", i, - c.BlockUnitsTarget[i], - c.BlockUnitsCap[i], + c.BlockTargetComplexityRate[i], + c.BlockMaxComplexity[i], ) } - if c.BlockUnitsTarget[i] == 0 { - return fmt.Errorf("dimension %d, block target units set to zero", i) + // The update algorithm normalizes complexity delta by [BlockTargetComplexityRate]. + // So we enforce [BlockTargetComplexityRate] to be non-zero. + if c.BlockTargetComplexityRate[i] == 0 { + return fmt.Errorf("dimension %d, block target complexity rate set to zero", i) } } diff --git a/vms/components/fees/manager.go b/vms/components/fees/manager.go index 8fc2344e4547..4bf9b7c43297 100644 --- a/vms/components/fees/manager.go +++ b/vms/components/fees/manager.go @@ -11,26 +11,26 @@ import ( ) type Manager struct { - // Avax denominated unit fees for all fee dimensions - unitFees Dimensions + // Avax denominated fee rates, i.e. fees per unit of complexity. + feeRates Dimensions - // cumulatedUnits helps aggregating the units consumed by a block - // so that we can verify it's not too big/build it properly. - cumulatedUnits Dimensions + // cumulatedComplexity helps aggregating the units of complexity consumed + // by a block so that we can verify it's not too big/build it properly. + cumulatedComplexity Dimensions } -func NewManager(unitFees Dimensions) *Manager { +func NewManager(feeRate Dimensions) *Manager { return &Manager{ - unitFees: unitFees, + feeRates: feeRate, } } -func (m *Manager) GetUnitFees() Dimensions { - return m.unitFees +func (m *Manager) GetFeeRates() Dimensions { + return m.feeRates } -func (m *Manager) GetCumulatedUnits() Dimensions { - return m.cumulatedUnits +func (m *Manager) GetCumulatedComplexity() Dimensions { + return m.cumulatedComplexity } // CalculateFee must be a stateless method @@ -38,7 +38,7 @@ func (m *Manager) CalculateFee(units Dimensions) (uint64, error) { fee := uint64(0) for i := Dimension(0); i < FeeDimensions; i++ { - contribution, err := safemath.Mul64(m.unitFees[i], units[i]) + contribution, err := safemath.Mul64(m.feeRates[i], units[i]) if err != nil { return 0, err } @@ -50,13 +50,13 @@ func (m *Manager) CalculateFee(units Dimensions) (uint64, error) { return fee, nil } -// CumulateUnits tries to cumulate the consumed units [units]. Before +// CumulateComplexity tries to cumulate the consumed complexity [units]. Before // actually cumulating them, it checks whether the result would breach [bounds]. // If so, it returns the first dimension to breach bounds. -func (m *Manager) CumulateUnits(units, bounds Dimensions) (bool, Dimension) { +func (m *Manager) CumulateComplexity(units, bounds Dimensions) (bool, Dimension) { // Ensure we can consume (don't want partial update of values) for i := Dimension(0); i < FeeDimensions; i++ { - consumed, err := safemath.Add64(m.cumulatedUnits[i], units[i]) + consumed, err := safemath.Add64(m.cumulatedComplexity[i], units[i]) if err != nil { return true, i } @@ -67,80 +67,87 @@ func (m *Manager) CumulateUnits(units, bounds Dimensions) (bool, Dimension) { // Commit to consumption for i := Dimension(0); i < FeeDimensions; i++ { - consumed, err := safemath.Add64(m.cumulatedUnits[i], units[i]) + consumed, err := safemath.Add64(m.cumulatedComplexity[i], units[i]) if err != nil { return true, i } - m.cumulatedUnits[i] = consumed + m.cumulatedComplexity[i] = consumed } return false, 0 } -// Sometimes, e.g. while building a tx, we'd like freedom to speculatively add units -// and to remove them later on. [RemoveUnits] grants this freedom -func (m *Manager) RemoveUnits(unitsToRm Dimensions) error { +// Sometimes, e.g. while building a tx, we'd like freedom to speculatively add complexity +// and to remove it later on. [RemoveComplexity] grants this freedom +func (m *Manager) RemoveComplexity(unitsToRm Dimensions) error { var revertedUnits Dimensions for i := Dimension(0); i < FeeDimensions; i++ { - prev, err := safemath.Sub(m.cumulatedUnits[i], unitsToRm[i]) + prev, err := safemath.Sub(m.cumulatedComplexity[i], unitsToRm[i]) if err != nil { return fmt.Errorf("%w: dimension %d", err, i) } revertedUnits[i] = prev } - m.cumulatedUnits = revertedUnits + m.cumulatedComplexity = revertedUnits return nil } -// [UpdateWindows] stores in the fee windows the units cumulated in current block -func (m *Manager) UpdateWindows(windows *Windows, lastTime, currTime int64) { - since := int(currTime - lastTime) - idx := 0 - if since < WindowSize { - idx = WindowSize - 1 - since +func (m *Manager) UpdateFeeRates( + feesConfig DynamicFeesConfig, + parentBlkComplexity Dimensions, + parentBlkTime, childBlkTime int64, +) error { + if childBlkTime < parentBlkTime { + return fmt.Errorf("unexpected block times, parentBlkTim %v, childBlkTime %v", parentBlkTime, childBlkTime) } + elapsedTime := uint64(childBlkTime - parentBlkTime) for i := Dimension(0); i < FeeDimensions; i++ { - windows[i] = Roll(windows[i], since) - Update(&windows[i], idx, m.cumulatedUnits[i]) + nextUnitFee := nextFeeRate( + m.feeRates[i], + feesConfig.UpdateCoefficient[i], + parentBlkComplexity[i], + feesConfig.BlockTargetComplexityRate[i], + elapsedTime, + ) + nextUnitFee = max(nextUnitFee, feesConfig.MinFeeRate[i]) + m.feeRates[i] = nextUnitFee } + return nil } -func (m *Manager) UpdateUnitFees( - feesConfig DynamicFeesConfig, - windows Windows, - lastTime, currTime int64, -) { - since := int(currTime - lastTime) - for i := Dimension(0); i < FeeDimensions; i++ { - nextUnitWindow := Roll(windows[i], since) - totalUnitsConsumed := Sum(nextUnitWindow) - nextUnitFee := nextFeeRate(m.unitFees[i], feesConfig.UpdateCoefficient[i], totalUnitsConsumed, feesConfig.BlockUnitsTarget[i]) - nextUnitFee = max(nextUnitFee, feesConfig.MinUnitFees[i]) - m.unitFees[i] = nextUnitFee +func nextFeeRate(currentFeeRate, coeff, parentBlkComplexity, targetComplexityRate, elapsedTime uint64) uint64 { + // We update the fee rate with the formula: + // feeRate_{t+1} = feeRate_t * exp{coeff * (parentComplexity - targetComplexity)/(targetComplexity) } + // where [targetComplexity] is the complexity expected in the elapsed time. + // + // We simplify the exponential for integer math. Specifically we approximate 1/ln(2) with 1_442/1_000 + // so that exp { x } == 2^{ 1/ln(2) * x } ≈≈ 2^{1_442/1_000 * x} + // Finally we round the exponent to a uint64 + + // parent and child block may have the same timestamp. In this case targetComplexity will match targetComplexityRate + elapsedTime = max(1, elapsedTime) + targetComplexity, over := safemath.Mul64(targetComplexityRate, elapsedTime) + if over != nil { + targetComplexity = math.MaxUint64 } -} - -func nextFeeRate(currentUnitFee, updateCoefficient, unitsConsumed, target uint64) uint64 { - // We update the fee rate with the formula e^{k(u-t)/t} == 2^{1/ln(2) * k(u-t)/t} - // We approximate 1/ln(2) with 1_442/1_000 and we round the exponent to a uint64 switch { - case unitsConsumed > target: - exp := 1442 * updateCoefficient * (unitsConsumed - target) / target / 1000 + case parentBlkComplexity > targetComplexity: + exp := 1442 * coeff * (parentBlkComplexity - targetComplexity) / targetComplexity / 1000 exp = min(exp, 62) // we cap the exponent to avoid an overflow of uint64 type - res, over := safemath.Mul64(currentUnitFee, 1< remainingSize) || - (isEActivated && !commonfees.Compare(feeMan.GetCumulatedUnits(), feesCfg.BlockUnitsTarget)) + (isEActivated && !commonfees.Compare(feeMan.GetCumulatedComplexity(), feesCfg.BlockTargetComplexityRate)) if targetSizeReached { break } @@ -388,11 +390,11 @@ func packBlockTxs( } executor := &txexecutor.StandardTxExecutor{ - Backend: backend, - BlkFeeManager: feeMan, - UnitCaps: feesCfg.BlockUnitsCap, - State: txDiff, - Tx: tx, + Backend: backend, + BlkFeeManager: feeMan, + BlockMaxComplexity: feesCfg.BlockMaxComplexity, + State: txDiff, + Tx: tx, } err = tx.Unsigned.Visit(executor) diff --git a/vms/platformvm/block/builder/helpers_test.go b/vms/platformvm/block/builder/helpers_test.go index 2866452eb5a5..b731052148ad 100644 --- a/vms/platformvm/block/builder/helpers_test.go +++ b/vms/platformvm/block/builder/helpers_test.go @@ -262,17 +262,17 @@ func addSubnet(t *testing.T, env *environment) { stateDiff, err := state.NewDiff(genesisID, env.blkManager) require.NoError(err) - unitFees, err := env.state.GetUnitFees() + feeRates, err := env.state.GetFeeRates() require.NoError(err) chainTime := env.state.GetTimestamp() feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := txexecutor.StandardTxExecutor{ - Backend: &env.backend, - BlkFeeManager: fees.NewManager(unitFees), - UnitCaps: feeCfg.BlockUnitsCap, - State: stateDiff, - Tx: testSubnet1, + Backend: &env.backend, + BlkFeeManager: fees.NewManager(feeRates), + BlockMaxComplexity: feeCfg.BlockMaxComplexity, + State: stateDiff, + Tx: testSubnet1, } require.NoError(testSubnet1.Unsigned.Visit(&executor)) diff --git a/vms/platformvm/block/executor/helpers_test.go b/vms/platformvm/block/executor/helpers_test.go index ec4ac9c5c832..fb64153d61ff 100644 --- a/vms/platformvm/block/executor/helpers_test.go +++ b/vms/platformvm/block/executor/helpers_test.go @@ -279,7 +279,7 @@ func addSubnet(env *environment) { panic(err) } - unitFees, err := env.state.GetUnitFees() + feeRates, err := env.state.GetFeeRates() if err != nil { panic(err) } @@ -287,11 +287,11 @@ func addSubnet(env *environment) { chainTime := env.state.GetTimestamp() feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := executor.StandardTxExecutor{ - Backend: env.backend, - BlkFeeManager: fees.NewManager(unitFees), - UnitCaps: feeCfg.BlockUnitsCap, - State: stateDiff, - Tx: testSubnet1, + Backend: env.backend, + BlkFeeManager: fees.NewManager(feeRates), + BlockMaxComplexity: feeCfg.BlockMaxComplexity, + State: stateDiff, + Tx: testSubnet1, } err = testSubnet1.Unsigned.Visit(&executor) if err != nil { diff --git a/vms/platformvm/block/executor/manager.go b/vms/platformvm/block/executor/manager.go index cf3e6b21a76b..b7abbb7e85a9 100644 --- a/vms/platformvm/block/executor/manager.go +++ b/vms/platformvm/block/executor/manager.go @@ -5,6 +5,7 @@ package executor import ( "errors" + "fmt" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/snow/consensus/snowman" @@ -147,11 +148,11 @@ func (m *manager) VerifyTx(tx *txs.Tx) error { return err } - unitFees, err := stateDiff.GetUnitFees() + feeRates, err := stateDiff.GetFeeRates() if err != nil { return err } - feeWindows, err := stateDiff.GetFeeWindows() + parentBlkComplexitty, err := stateDiff.GetLastBlockComplexity() if err != nil { return err } @@ -161,22 +162,24 @@ func (m *manager) VerifyTx(tx *txs.Tx) error { feesCfg = config.GetDynamicFeesConfig(isEActivated) ) - feeManager := fees.NewManager(unitFees) + feeManager := fees.NewManager(feeRates) if isEActivated { - feeManager.UpdateUnitFees( + if err := feeManager.UpdateFeeRates( feesCfg, - feeWindows, + parentBlkComplexitty, parentBlkTime.Unix(), nextBlkTime.Unix(), - ) + ); err != nil { + return fmt.Errorf("failed updating fee rates, %w", err) + } } return tx.Unsigned.Visit(&executor.StandardTxExecutor{ - Backend: m.txExecutorBackend, - BlkFeeManager: feeManager, - UnitCaps: feesCfg.BlockUnitsCap, - State: stateDiff, - Tx: tx, + Backend: m.txExecutorBackend, + BlkFeeManager: feeManager, + BlockMaxComplexity: feesCfg.BlockMaxComplexity, + State: stateDiff, + Tx: tx, }) } diff --git a/vms/platformvm/block/executor/proposal_block_test.go b/vms/platformvm/block/executor/proposal_block_test.go index e79f6eb63fbe..9cd41f375cb6 100644 --- a/vms/platformvm/block/executor/proposal_block_test.go +++ b/vms/platformvm/block/executor/proposal_block_test.go @@ -159,8 +159,8 @@ func TestBanffProposalBlockTimeVerification(t *testing.T) { onParentAccept := state.NewMockDiff(ctrl) onParentAccept.EXPECT().GetTimestamp().Return(parentTime).AnyTimes() - onParentAccept.EXPECT().GetUnitFees().Return(commonfees.Empty, nil).Times(2) - onParentAccept.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows, nil).Times(2) + onParentAccept.EXPECT().GetFeeRates().Return(commonfees.Empty, nil).Times(2) + onParentAccept.EXPECT().GetLastBlockComplexity().Return(commonfees.Empty, nil).Times(2) 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 230f8a2256a8..c7e6246b7354 100644 --- a/vms/platformvm/block/executor/standard_block_test.go +++ b/vms/platformvm/block/executor/standard_block_test.go @@ -57,8 +57,8 @@ 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().GetUnitFees().Return(commonfees.Empty, nil).AnyTimes() - onParentAccept.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows, nil).AnyTimes() + onParentAccept.EXPECT().GetFeeRates().Return(commonfees.Empty, nil).AnyTimes() + onParentAccept.EXPECT().GetLastBlockComplexity().Return(commonfees.Empty, nil).AnyTimes() // wrong height apricotChildBlk, err := block.NewApricotStandardBlock( @@ -152,8 +152,8 @@ func TestBanffStandardBlockTimeVerification(t *testing.T) { } utxoID := utxo.InputID() onParentAccept.EXPECT().GetUTXO(utxoID).Return(utxo, nil).AnyTimes() - onParentAccept.EXPECT().GetUnitFees().Return(commonfees.Empty, nil).AnyTimes() - onParentAccept.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows, nil).AnyTimes() + onParentAccept.EXPECT().GetFeeRates().Return(commonfees.Empty, nil).AnyTimes() + onParentAccept.EXPECT().GetLastBlockComplexity().Return(commonfees.Empty, 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 2d7cdfb3902c..ed5ef76615f2 100644 --- a/vms/platformvm/block/executor/verifier.go +++ b/vms/platformvm/block/executor/verifier.go @@ -98,7 +98,7 @@ func (v *verifier) BanffProposalBlock(b *block.BanffProposalBlock) error { onDecisionState, onCommitState, onAbortState, - feesMan.GetCumulatedUnits(), + feesMan.GetCumulatedComplexity(), inputs, atomicRequests, onAcceptFunc, @@ -453,7 +453,7 @@ func (v *verifier) standardBlock( onAcceptFunc: onAcceptFunc, timestamp: onAcceptState.GetTimestamp(), - blockComplexity: feeMan.GetCumulatedUnits(), + blockComplexity: feeMan.GetCumulatedComplexity(), inputs: inputs, atomicRequests: atomicRequests, } @@ -472,11 +472,11 @@ func (v *verifier) processStandardTxs( func(), error, ) { - unitFees, err := state.GetUnitFees() + feeRates, err := state.GetFeeRates() if err != nil { return nil, nil, nil, nil, err } - feeWindows, err := state.GetFeeWindows() + parentBlkComplexity, err := state.GetLastBlockComplexity() if err != nil { return nil, nil, nil, nil, err } @@ -491,23 +491,25 @@ func (v *verifier) processStandardTxs( atomicRequests = make(map[ids.ID]*atomic.Requests) ) - feeManager := fees.NewManager(unitFees) + feeManager := fees.NewManager(feeRates) if isEActivated { - feeManager.UpdateUnitFees( + if err := feeManager.UpdateFeeRates( feesCfg, - feeWindows, + parentBlkComplexity, parentBlkTime.Unix(), blkTimestamp.Unix(), - ) + ); err != nil { + return nil, nil, nil, nil, fmt.Errorf("failed updating fee rates, %w", err) + } } for _, tx := range txs { txExecutor := executor.StandardTxExecutor{ - Backend: v.txExecutorBackend, - BlkFeeManager: feeManager, - UnitCaps: feesCfg.BlockUnitsCap, - State: state, - Tx: tx, + Backend: v.txExecutorBackend, + BlkFeeManager: feeManager, + BlockMaxComplexity: feesCfg.BlockMaxComplexity, + State: state, + Tx: tx, } if err := tx.Unsigned.Visit(&txExecutor); err != nil { txID := tx.ID() @@ -544,9 +546,8 @@ func (v *verifier) processStandardTxs( } if isEActivated { - feeManager.UpdateWindows(&feeWindows, parentBlkTime.Unix(), blkTimestamp.Unix()) - state.SetUnitFees(feeManager.GetUnitFees()) - state.SetFeeWindows(feeWindows) + state.SetUnitFees(feeManager.GetFeeRates()) + state.SetLastBlockComplexity(feeManager.GetCumulatedComplexity()) } if numFuncs := len(funcs); numFuncs == 1 { diff --git a/vms/platformvm/block/executor/verifier_test.go b/vms/platformvm/block/executor/verifier_test.go index 23e613042434..9878d009f7d5 100644 --- a/vms/platformvm/block/executor/verifier_test.go +++ b/vms/platformvm/block/executor/verifier_test.go @@ -289,8 +289,8 @@ func TestVerifierVisitStandardBlock(t *testing.T) { // Set expectations for dependencies. timestamp := time.Now() parentState.EXPECT().GetTimestamp().Return(timestamp).Times(1) - parentState.EXPECT().GetUnitFees().Return(commonfees.Empty, nil) - parentState.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows, nil) + parentState.EXPECT().GetFeeRates().Return(commonfees.Empty, nil) + parentState.EXPECT().GetLastBlockComplexity().Return(commonfees.Empty, nil) parentStatelessBlk.EXPECT().Height().Return(uint64(1)).Times(1) mempool.EXPECT().Remove(apricotBlk.Txs()).Times(1) @@ -773,8 +773,8 @@ func TestVerifierVisitStandardBlockWithDuplicateInputs(t *testing.T) { timestamp := time.Now() parentStatelessBlk.EXPECT().Height().Return(uint64(1)).Times(1) parentState.EXPECT().GetTimestamp().Return(timestamp).Times(1) - parentState.EXPECT().GetUnitFees().Return(commonfees.Empty, nil) - parentState.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows, nil) + parentState.EXPECT().GetFeeRates().Return(commonfees.Empty, nil) + parentState.EXPECT().GetLastBlockComplexity().Return(commonfees.Empty, nil) parentStatelessBlk.EXPECT().Parent().Return(grandParentID).Times(1) diff --git a/vms/platformvm/client.go b/vms/platformvm/client.go index bca8935c7dc5..e7b5af6fcbfa 100644 --- a/vms/platformvm/client.go +++ b/vms/platformvm/client.go @@ -134,8 +134,8 @@ type Client interface { // GetBlockByHeight returns the block at the given [height]. GetBlockByHeight(ctx context.Context, height uint64, options ...rpc.Option) ([]byte, error) - // GetUnitFees returns the current unit fees and the next unit fees that a transaction must pay to be accepted - GetUnitFees(ctx context.Context, options ...rpc.Option) (commonfees.Dimensions, commonfees.Dimensions, error) + // GetFeeRates returns the current unit fees and the next unit fees that a transaction must pay to be accepted + GetFeeRates(ctx context.Context, options ...rpc.Option) (commonfees.Dimensions, commonfees.Dimensions, error) } // Client implementation for interacting with the P Chain endpoint @@ -551,8 +551,8 @@ func (c *client) GetBlockByHeight(ctx context.Context, height uint64, options .. return formatting.Decode(res.Encoding, res.Block) } -func (c *client) GetUnitFees(ctx context.Context, options ...rpc.Option) (commonfees.Dimensions, commonfees.Dimensions, error) { +func (c *client) GetFeeRates(ctx context.Context, options ...rpc.Option) (commonfees.Dimensions, commonfees.Dimensions, error) { res := &GetUnitFeesReply{} - err := c.requester.SendRequest(ctx, "platform.getUnitFees", struct{}{}, res, options...) + err := c.requester.SendRequest(ctx, "platform.getFeeRates", struct{}{}, res, options...) return res.CurrentUnitFees, res.NextUnitFees, err } diff --git a/vms/platformvm/config/dynamic_fees_config.go b/vms/platformvm/config/dynamic_fees_config.go index 73bfa08fbf8d..9323cb9ee2cd 100644 --- a/vms/platformvm/config/dynamic_fees_config.go +++ b/vms/platformvm/config/dynamic_fees_config.go @@ -28,21 +28,21 @@ func init() { // eUpgradeDynamicFeesConfig to be tuned TODO ABENEGIA var ( eUpgradeDynamicFeesConfig = commonfees.DynamicFeesConfig{ - InitialUnitFees: commonfees.Dimensions{ + InitialFeeRate: commonfees.Dimensions{ 1 * units.NanoAvax, 2 * units.NanoAvax, 3 * units.NanoAvax, 4 * units.NanoAvax, }, - MinUnitFees: commonfees.Empty, + MinFeeRate: commonfees.Empty, UpdateCoefficient: commonfees.Dimensions{ 1, 1, 1, 1, }, - BlockUnitsCap: commonfees.Max, - BlockUnitsTarget: commonfees.Dimensions{ + BlockMaxComplexity: commonfees.Max, + BlockTargetComplexityRate: commonfees.Dimensions{ 2000, 2000, 2000, @@ -52,8 +52,8 @@ var ( // TODO ABENEGIA: decide if and how to validate preEUpgradeDynamicFeesConfig preEUpgradeDynamicFeesConfig = commonfees.DynamicFeesConfig{ - InitialUnitFees: commonfees.Empty, - BlockUnitsCap: commonfees.Max, + InitialFeeRate: commonfees.Empty, + BlockMaxComplexity: commonfees.Max, } customDynamicFeesConfig *commonfees.DynamicFeesConfig diff --git a/vms/platformvm/service.go b/vms/platformvm/service.go index 7c25096effac..d79e45261514 100644 --- a/vms/platformvm/service.go +++ b/vms/platformvm/service.go @@ -1821,14 +1821,14 @@ func (s *Service) GetBlockByHeight(_ *http.Request, args *api.GetBlockByHeightAr return err } -// GetUnitFeesReply is the response from GetUnitFees +// GetUnitFeesReply is the response from GetFeeRates type GetUnitFeesReply struct { CurrentUnitFees commonfees.Dimensions `json:"currentUnitFees"` NextUnitFees commonfees.Dimensions `json:"nextUnitFees"` } // GetTimestamp returns the current timestamp on chain. -func (s *Service) GetUnitFees(_ *http.Request, _ *struct{}, reply *GetUnitFeesReply) error { +func (s *Service) GetFeeRates(_ *http.Request, _ *struct{}, reply *GetUnitFeesReply) error { s.vm.ctx.Log.Debug("API called", zap.String("service", "platform"), zap.String("method", "getUnitFees"), @@ -1843,11 +1843,11 @@ func (s *Service) GetUnitFees(_ *http.Request, _ *struct{}, reply *GetUnitFeesRe return fmt.Errorf("could not retrieve state for block %s", preferredID) } - currentUnitFees, err := onAccept.GetUnitFees() + currentFeeRate, err := onAccept.GetFeeRates() if err != nil { return err } - reply.CurrentUnitFees = currentUnitFees + reply.CurrentUnitFees = currentFeeRate nextTimestamp, _, err := executor.NextBlockTime(onAccept, &s.vm.clock) if err != nil { @@ -1865,21 +1865,23 @@ func (s *Service) GetUnitFees(_ *http.Request, _ *struct{}, reply *GetUnitFeesRe feesCfg = config.GetDynamicFeesConfig(isEActivated) ) - feeWindows, err := onAccept.GetFeeWindows() + parentBlkComplexity, err := onAccept.GetLastBlockComplexity() if err != nil { return err } - feeManager := commonfees.NewManager(currentUnitFees) + feeManager := commonfees.NewManager(currentFeeRate) if isEActivated { - feeManager.UpdateUnitFees( + if err := feeManager.UpdateFeeRates( feesCfg, - feeWindows, + parentBlkComplexity, currentTimestamp.Unix(), nextTimestamp.Unix(), - ) + ); err != nil { + return fmt.Errorf("failed updating fee rates, %w", err) + } } - reply.NextUnitFees = feeManager.GetUnitFees() + reply.NextUnitFees = feeManager.GetFeeRates() return nil } diff --git a/vms/platformvm/service_test.go b/vms/platformvm/service_test.go index 83a6abb7ed20..c9da8dc20162 100644 --- a/vms/platformvm/service_test.go +++ b/vms/platformvm/service_test.go @@ -353,7 +353,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 - unitFees, err := service.vm.state.GetUnitFees() + unitFees, err := service.vm.state.GetFeeRates() require.NoError(err) var ( @@ -365,7 +365,7 @@ func TestGetBalance(t *testing.T) { Config: &service.vm.Config, ChainTime: chainTime, FeeManager: feeMan, - ConsumedUnitsCap: feeCfg.BlockUnitsCap, + ConsumedUnitsCap: feeCfg.BlockMaxComplexity, Credentials: testSubnet1.Creds, } ) @@ -1009,24 +1009,24 @@ func TestGetUnitFees(t *testing.T) { service, _ := defaultService(t) reply := GetUnitFeesReply{} - require.NoError(service.GetUnitFees(nil, nil, &reply)) + require.NoError(service.GetFeeRates(nil, nil, &reply)) service.vm.ctx.Lock.Lock() - unitFees, err := service.vm.state.GetUnitFees() + feeRates, err := service.vm.state.GetFeeRates() require.NoError(err) - require.Equal(unitFees, reply.CurrentUnitFees) + require.Equal(feeRates, reply.CurrentUnitFees) - updatedUnitFees := commonfees.Dimensions{ + updatedFeeRates := commonfees.Dimensions{ 123, 456, 789, 1011, } - service.vm.state.SetUnitFees(updatedUnitFees) + service.vm.state.SetUnitFees(updatedFeeRates) service.vm.ctx.Lock.Unlock() - require.NoError(service.GetUnitFees(nil, nil, &reply)) - require.Equal(updatedUnitFees, reply.CurrentUnitFees) + require.NoError(service.GetFeeRates(nil, nil, &reply)) + require.Equal(updatedFeeRates, reply.CurrentUnitFees) } diff --git a/vms/platformvm/state/diff.go b/vms/platformvm/state/diff.go index e0f43371c2a1..2328d597c36f 100644 --- a/vms/platformvm/state/diff.go +++ b/vms/platformvm/state/diff.go @@ -37,8 +37,8 @@ type diff struct { timestamp time.Time - unitFees *commonfees.Dimensions - feesWindows *commonfees.Windows + feeRates *commonfees.Dimensions + lastBlkComplexity *commonfees.Dimensions // Subnet ID --> supply of native asset of the subnet currentSupply map[ids.ID]uint64 @@ -94,54 +94,54 @@ func NewDiffOn(parentState Chain) (Diff, error) { }) } -func (d *diff) GetUnitFees() (commonfees.Dimensions, error) { - if d.unitFees == nil { +func (d *diff) GetFeeRates() (commonfees.Dimensions, error) { + if d.feeRates == nil { parentState, ok := d.stateVersions.GetState(d.parentID) if !ok { return commonfees.Empty, fmt.Errorf("%w: %s", ErrMissingParentState, d.parentID) } - parentUnitFees, err := parentState.GetUnitFees() + parentUnitFees, err := parentState.GetFeeRates() if err != nil { return commonfees.Empty, err } - d.unitFees = new(commonfees.Dimensions) - *d.unitFees = parentUnitFees + d.feeRates = new(commonfees.Dimensions) + *d.feeRates = parentUnitFees } - return *d.unitFees, nil + return *d.feeRates, nil } func (d *diff) SetUnitFees(uf commonfees.Dimensions) { - if d.unitFees == nil { - d.unitFees = new(commonfees.Dimensions) + if d.feeRates == nil { + d.feeRates = new(commonfees.Dimensions) } - *d.unitFees = uf + *d.feeRates = uf } -func (d *diff) GetFeeWindows() (commonfees.Windows, error) { - if d.feesWindows == nil { +func (d *diff) GetLastBlockComplexity() (commonfees.Dimensions, error) { + if d.lastBlkComplexity == nil { parentState, ok := d.stateVersions.GetState(d.parentID) if !ok { - return commonfees.EmptyWindows, fmt.Errorf("%w: %s", ErrMissingParentState, d.parentID) + return commonfees.Empty, fmt.Errorf("%w: %s", ErrMissingParentState, d.parentID) } - parentFeeWindows, err := parentState.GetFeeWindows() + parentLastComplexity, err := parentState.GetLastBlockComplexity() if err != nil { - return commonfees.EmptyWindows, err + return commonfees.Empty, err } - d.feesWindows = new(commonfees.Windows) - *d.feesWindows = parentFeeWindows + d.lastBlkComplexity = new(commonfees.Dimensions) + *d.lastBlkComplexity = parentLastComplexity } - return *d.feesWindows, nil + return *d.lastBlkComplexity, nil } -func (d *diff) SetFeeWindows(windows commonfees.Windows) { - if d.feesWindows == nil { - d.feesWindows = new(commonfees.Windows) +func (d *diff) SetLastBlockComplexity(complexity commonfees.Dimensions) { + if d.lastBlkComplexity == nil { + d.lastBlkComplexity = new(commonfees.Dimensions) } - *d.feesWindows = windows + *d.lastBlkComplexity = complexity } func (d *diff) GetTimestamp() time.Time { @@ -456,11 +456,11 @@ func (d *diff) DeleteUTXO(utxoID ids.ID) { func (d *diff) Apply(baseState Chain) error { baseState.SetTimestamp(d.timestamp) - if d.unitFees != nil { - baseState.SetUnitFees(*d.unitFees) + if d.feeRates != nil { + baseState.SetUnitFees(*d.feeRates) } - if d.feesWindows != nil { - baseState.SetFeeWindows(*d.feesWindows) + if d.lastBlkComplexity != nil { + baseState.SetLastBlockComplexity(*d.lastBlkComplexity) } 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 469dbd23dc27..720c804a700e 100644 --- a/vms/platformvm/state/mock_state.go +++ b/vms/platformvm/state/mock_state.go @@ -256,19 +256,34 @@ func (mr *MockChainMockRecorder) GetDelegateeReward(arg0, arg1 any) *gomock.Call return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDelegateeReward", reflect.TypeOf((*MockChain)(nil).GetDelegateeReward), arg0, arg1) } -// GetFeeWindows mocks base method. -func (m *MockChain) GetFeeWindows() (fees.Windows, error) { +// GetFeeRates mocks base method. +func (m *MockChain) GetFeeRates() (fees.Dimensions, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetFeeWindows") - ret0, _ := ret[0].(fees.Windows) + ret := m.ctrl.Call(m, "GetFeeRates") + ret0, _ := ret[0].(fees.Dimensions) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetFeeRates indicates an expected call of GetFeeRates. +func (mr *MockChainMockRecorder) GetFeeRates() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFeeRates", reflect.TypeOf((*MockChain)(nil).GetFeeRates)) +} + +// GetLastBlockComplexity mocks base method. +func (m *MockChain) GetLastBlockComplexity() (fees.Dimensions, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetLastBlockComplexity") + ret0, _ := ret[0].(fees.Dimensions) ret1, _ := ret[1].(error) return ret0, ret1 } -// GetFeeWindows indicates an expected call of GetFeeWindows. -func (mr *MockChainMockRecorder) GetFeeWindows() *gomock.Call { +// GetLastBlockComplexity indicates an expected call of GetLastBlockComplexity. +func (mr *MockChainMockRecorder) GetLastBlockComplexity() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFeeWindows", reflect.TypeOf((*MockChain)(nil).GetFeeWindows)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLastBlockComplexity", reflect.TypeOf((*MockChain)(nil).GetLastBlockComplexity)) } // GetPendingDelegatorIterator mocks base method. @@ -391,21 +406,6 @@ func (mr *MockChainMockRecorder) GetUTXO(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUTXO", reflect.TypeOf((*MockChain)(nil).GetUTXO), arg0) } -// GetUnitFees mocks base method. -func (m *MockChain) GetUnitFees() (fees.Dimensions, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetUnitFees") - ret0, _ := ret[0].(fees.Dimensions) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetUnitFees indicates an expected call of GetUnitFees. -func (mr *MockChainMockRecorder) GetUnitFees() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUnitFees", reflect.TypeOf((*MockChain)(nil).GetUnitFees)) -} - // PutCurrentDelegator mocks base method. func (m *MockChain) PutCurrentDelegator(arg0 *Staker) { m.ctrl.T.Helper() @@ -480,16 +480,16 @@ func (mr *MockChainMockRecorder) SetDelegateeReward(arg0, arg1, arg2 any) *gomoc return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetDelegateeReward", reflect.TypeOf((*MockChain)(nil).SetDelegateeReward), arg0, arg1, arg2) } -// SetFeeWindows mocks base method. -func (m *MockChain) SetFeeWindows(arg0 fees.Windows) { +// SetLastBlockComplexity mocks base method. +func (m *MockChain) SetLastBlockComplexity(arg0 fees.Dimensions) { m.ctrl.T.Helper() - m.ctrl.Call(m, "SetFeeWindows", arg0) + m.ctrl.Call(m, "SetLastBlockComplexity", arg0) } -// SetFeeWindows indicates an expected call of SetFeeWindows. -func (mr *MockChainMockRecorder) SetFeeWindows(arg0 any) *gomock.Call { +// SetLastBlockComplexity indicates an expected call of SetLastBlockComplexity. +func (mr *MockChainMockRecorder) SetLastBlockComplexity(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetFeeWindows", reflect.TypeOf((*MockChain)(nil).SetFeeWindows), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetLastBlockComplexity", reflect.TypeOf((*MockChain)(nil).SetLastBlockComplexity), arg0) } // SetSubnetOwner mocks base method. @@ -772,19 +772,34 @@ func (mr *MockDiffMockRecorder) GetDelegateeReward(arg0, arg1 any) *gomock.Call return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDelegateeReward", reflect.TypeOf((*MockDiff)(nil).GetDelegateeReward), arg0, arg1) } -// GetFeeWindows mocks base method. -func (m *MockDiff) GetFeeWindows() (fees.Windows, error) { +// GetFeeRates mocks base method. +func (m *MockDiff) GetFeeRates() (fees.Dimensions, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetFeeWindows") - ret0, _ := ret[0].(fees.Windows) + ret := m.ctrl.Call(m, "GetFeeRates") + ret0, _ := ret[0].(fees.Dimensions) ret1, _ := ret[1].(error) return ret0, ret1 } -// GetFeeWindows indicates an expected call of GetFeeWindows. -func (mr *MockDiffMockRecorder) GetFeeWindows() *gomock.Call { +// GetFeeRates indicates an expected call of GetFeeRates. +func (mr *MockDiffMockRecorder) GetFeeRates() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFeeWindows", reflect.TypeOf((*MockDiff)(nil).GetFeeWindows)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFeeRates", reflect.TypeOf((*MockDiff)(nil).GetFeeRates)) +} + +// GetLastBlockComplexity mocks base method. +func (m *MockDiff) GetLastBlockComplexity() (fees.Dimensions, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetLastBlockComplexity") + ret0, _ := ret[0].(fees.Dimensions) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetLastBlockComplexity indicates an expected call of GetLastBlockComplexity. +func (mr *MockDiffMockRecorder) GetLastBlockComplexity() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLastBlockComplexity", reflect.TypeOf((*MockDiff)(nil).GetLastBlockComplexity)) } // GetPendingDelegatorIterator mocks base method. @@ -907,21 +922,6 @@ func (mr *MockDiffMockRecorder) GetUTXO(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUTXO", reflect.TypeOf((*MockDiff)(nil).GetUTXO), arg0) } -// GetUnitFees mocks base method. -func (m *MockDiff) GetUnitFees() (fees.Dimensions, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetUnitFees") - ret0, _ := ret[0].(fees.Dimensions) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetUnitFees indicates an expected call of GetUnitFees. -func (mr *MockDiffMockRecorder) GetUnitFees() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUnitFees", reflect.TypeOf((*MockDiff)(nil).GetUnitFees)) -} - // PutCurrentDelegator mocks base method. func (m *MockDiff) PutCurrentDelegator(arg0 *Staker) { m.ctrl.T.Helper() @@ -996,16 +996,16 @@ func (mr *MockDiffMockRecorder) SetDelegateeReward(arg0, arg1, arg2 any) *gomock return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetDelegateeReward", reflect.TypeOf((*MockDiff)(nil).SetDelegateeReward), arg0, arg1, arg2) } -// SetFeeWindows mocks base method. -func (m *MockDiff) SetFeeWindows(arg0 fees.Windows) { +// SetLastBlockComplexity mocks base method. +func (m *MockDiff) SetLastBlockComplexity(arg0 fees.Dimensions) { m.ctrl.T.Helper() - m.ctrl.Call(m, "SetFeeWindows", arg0) + m.ctrl.Call(m, "SetLastBlockComplexity", arg0) } -// SetFeeWindows indicates an expected call of SetFeeWindows. -func (mr *MockDiffMockRecorder) SetFeeWindows(arg0 any) *gomock.Call { +// SetLastBlockComplexity indicates an expected call of SetLastBlockComplexity. +func (mr *MockDiffMockRecorder) SetLastBlockComplexity(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetFeeWindows", reflect.TypeOf((*MockDiff)(nil).SetFeeWindows), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetLastBlockComplexity", reflect.TypeOf((*MockDiff)(nil).SetLastBlockComplexity), arg0) } // SetSubnetOwner mocks base method. @@ -1413,19 +1413,19 @@ func (mr *MockStateMockRecorder) GetDelegateeReward(arg0, arg1 any) *gomock.Call return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDelegateeReward", reflect.TypeOf((*MockState)(nil).GetDelegateeReward), arg0, arg1) } -// GetFeeWindows mocks base method. -func (m *MockState) GetFeeWindows() (fees.Windows, error) { +// GetFeeRates mocks base method. +func (m *MockState) GetFeeRates() (fees.Dimensions, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetFeeWindows") - ret0, _ := ret[0].(fees.Windows) + ret := m.ctrl.Call(m, "GetFeeRates") + ret0, _ := ret[0].(fees.Dimensions) ret1, _ := ret[1].(error) return ret0, ret1 } -// GetFeeWindows indicates an expected call of GetFeeWindows. -func (mr *MockStateMockRecorder) GetFeeWindows() *gomock.Call { +// GetFeeRates indicates an expected call of GetFeeRates. +func (mr *MockStateMockRecorder) GetFeeRates() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFeeWindows", reflect.TypeOf((*MockState)(nil).GetFeeWindows)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFeeRates", reflect.TypeOf((*MockState)(nil).GetFeeRates)) } // GetLastAccepted mocks base method. @@ -1442,6 +1442,21 @@ func (mr *MockStateMockRecorder) GetLastAccepted() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLastAccepted", reflect.TypeOf((*MockState)(nil).GetLastAccepted)) } +// GetLastBlockComplexity mocks base method. +func (m *MockState) GetLastBlockComplexity() (fees.Dimensions, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetLastBlockComplexity") + ret0, _ := ret[0].(fees.Dimensions) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetLastBlockComplexity indicates an expected call of GetLastBlockComplexity. +func (mr *MockStateMockRecorder) GetLastBlockComplexity() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLastBlockComplexity", reflect.TypeOf((*MockState)(nil).GetLastBlockComplexity)) +} + // GetPendingDelegatorIterator mocks base method. func (m *MockState) GetPendingDelegatorIterator(arg0 ids.ID, arg1 ids.NodeID) (StakerIterator, error) { m.ctrl.T.Helper() @@ -1622,21 +1637,6 @@ func (mr *MockStateMockRecorder) GetUTXO(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUTXO", reflect.TypeOf((*MockState)(nil).GetUTXO), arg0) } -// GetUnitFees mocks base method. -func (m *MockState) GetUnitFees() (fees.Dimensions, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetUnitFees") - ret0, _ := ret[0].(fees.Dimensions) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetUnitFees indicates an expected call of GetUnitFees. -func (mr *MockStateMockRecorder) GetUnitFees() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUnitFees", reflect.TypeOf((*MockState)(nil).GetUnitFees)) -} - // GetUptime mocks base method. func (m *MockState) GetUptime(arg0 ids.NodeID, arg1 ids.ID) (time.Duration, time.Time, error) { m.ctrl.T.Helper() @@ -1727,18 +1727,6 @@ func (mr *MockStateMockRecorder) SetDelegateeReward(arg0, arg1, arg2 any) *gomoc return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetDelegateeReward", reflect.TypeOf((*MockState)(nil).SetDelegateeReward), arg0, arg1, arg2) } -// SetFeeWindows mocks base method. -func (m *MockState) SetFeeWindows(arg0 fees.Windows) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "SetFeeWindows", arg0) -} - -// SetFeeWindows indicates an expected call of SetFeeWindows. -func (mr *MockStateMockRecorder) SetFeeWindows(arg0 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetFeeWindows", reflect.TypeOf((*MockState)(nil).SetFeeWindows), arg0) -} - // SetHeight mocks base method. func (m *MockState) SetHeight(arg0 uint64) { m.ctrl.T.Helper() @@ -1763,6 +1751,18 @@ func (mr *MockStateMockRecorder) SetLastAccepted(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetLastAccepted", reflect.TypeOf((*MockState)(nil).SetLastAccepted), arg0) } +// SetLastBlockComplexity mocks base method. +func (m *MockState) SetLastBlockComplexity(arg0 fees.Dimensions) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetLastBlockComplexity", arg0) +} + +// SetLastBlockComplexity indicates an expected call of SetLastBlockComplexity. +func (mr *MockStateMockRecorder) SetLastBlockComplexity(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetLastBlockComplexity", reflect.TypeOf((*MockState)(nil).SetLastBlockComplexity), arg0) +} + // SetSubnetOwner mocks base method. func (m *MockState) SetSubnetOwner(arg0 ids.ID, arg1 fx.Owner) { m.ctrl.T.Helper() diff --git a/vms/platformvm/state/state.go b/vms/platformvm/state/state.go index 105a62cb9a80..f533821517cf 100644 --- a/vms/platformvm/state/state.go +++ b/vms/platformvm/state/state.go @@ -69,13 +69,13 @@ var ( ChainPrefix = []byte("chain") SingletonPrefix = []byte("singleton") - TimestampKey = []byte("timestamp") - CurrentSupplyKey = []byte("current supply") - LastAcceptedKey = []byte("last accepted") - HeightsIndexedKey = []byte("heights indexed") - UnitFeesKey = []byte("unit fees") - FeesWindowsKey = []byte("fees windows") - InitializedKey = []byte("initialized") + TimestampKey = []byte("timestamp") + CurrentSupplyKey = []byte("current supply") + LastAcceptedKey = []byte("last accepted") + HeightsIndexedKey = []byte("heights indexed") + UnitFeesKey = []byte("unit fees") + LastBlkComplexityKey = []byte("last complexity") + InitializedKey = []byte("initialized") ) // Chain collects all methods to manage the state of the chain for block @@ -86,11 +86,11 @@ type Chain interface { avax.UTXOGetter avax.UTXODeleter - GetUnitFees() (commonfees.Dimensions, error) + GetFeeRates() (commonfees.Dimensions, error) SetUnitFees(uf commonfees.Dimensions) - GetFeeWindows() (commonfees.Windows, error) - SetFeeWindows(windows commonfees.Windows) + GetLastBlockComplexity() (commonfees.Dimensions, error) + SetLastBlockComplexity(windows commonfees.Dimensions) GetTimestamp() time.Time SetTimestamp(tm time.Time) @@ -332,8 +332,8 @@ type state struct { // The persisted fields represent the current database value timestamp, persistedTimestamp time.Time - unitFees *commonfees.Dimensions // pointer, to allow customization for test networks - feesWindows commonfees.Windows + feeRate *commonfees.Dimensions // pointer, to allow customization for test networks + lastBlkComplexity commonfees.Dimensions currentSupply, persistedCurrentSupply uint64 // [lastAccepted] is the most recently accepted block. lastAccepted, persistedLastAccepted ids.ID @@ -982,21 +982,21 @@ func (s *state) GetStartTime(nodeID ids.NodeID, subnetID ids.ID) (time.Time, err return staker.StartTime, nil } -func (s *state) GetUnitFees() (commonfees.Dimensions, error) { - return *s.unitFees, nil +func (s *state) GetFeeRates() (commonfees.Dimensions, error) { + return *s.feeRate, nil } func (s *state) SetUnitFees(uf commonfees.Dimensions) { unitFees := uf - s.unitFees = &unitFees + s.feeRate = &unitFees } -func (s *state) GetFeeWindows() (commonfees.Windows, error) { - return s.feesWindows, nil +func (s *state) GetLastBlockComplexity() (commonfees.Dimensions, error) { + return s.lastBlkComplexity, nil } -func (s *state) SetFeeWindows(windows commonfees.Windows) { - s.feesWindows = windows +func (s *state) SetLastBlockComplexity(complexity commonfees.Dimensions) { + s.lastBlkComplexity = complexity } func (s *state) GetTimestamp() time.Time { @@ -1289,10 +1289,10 @@ func (s *state) loadMetadata() error { s.persistedTimestamp = timestamp s.SetTimestamp(timestamp) - s.unitFees = new(commonfees.Dimensions) + s.feeRate = new(commonfees.Dimensions) switch unitFeesBytes, err := s.singletonDB.Get(UnitFeesKey); err { case nil: - if err := s.unitFees.FromBytes(unitFeesBytes); err != nil { + if err := s.feeRate.FromBytes(unitFeesBytes); err != nil { return err } @@ -1301,15 +1301,15 @@ func (s *state) loadMetadata() error { // hence we may have never stored unit fees. Load from config // TODO: remove once fork is active isEActive := s.cfg.IsEActivated(timestamp) - *s.unitFees = config.GetDynamicFeesConfig(isEActive).InitialUnitFees + *s.feeRate = config.GetDynamicFeesConfig(isEActive).InitialFeeRate default: return err } - switch feesWindowsBytes, err := s.singletonDB.Get(FeesWindowsKey); err { + switch lastBlkComplexityBytes, err := s.singletonDB.Get(LastBlkComplexityKey); err { case nil: - if err := s.feesWindows.FromBytes(feesWindowsBytes); err != nil { + if err := s.lastBlkComplexity.FromBytes(lastBlkComplexityBytes); err != nil { return err } @@ -1317,7 +1317,7 @@ func (s *state) loadMetadata() error { // 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 - s.feesWindows = commonfees.EmptyWindows + s.lastBlkComplexity = commonfees.Empty default: return err @@ -2300,12 +2300,12 @@ func (s *state) writeMetadata() error { s.persistedTimestamp = s.timestamp } - if s.unitFees != nil { - if err := s.singletonDB.Put(UnitFeesKey, s.unitFees.Bytes()); err != nil { + if s.feeRate != nil { + if err := s.singletonDB.Put(UnitFeesKey, s.feeRate.Bytes()); err != nil { return fmt.Errorf("failed to write unit fees: %w", err) } } - if err := s.singletonDB.Put(FeesWindowsKey, s.feesWindows.Bytes()); err != nil { + if err := s.singletonDB.Put(LastBlkComplexityKey, s.lastBlkComplexity.Bytes()); err != nil { return fmt.Errorf("failed to write unit fees: %w", err) } if s.persistedCurrentSupply != s.currentSupply { diff --git a/vms/platformvm/txs/builder/builder.go b/vms/platformvm/txs/builder/builder.go index 4285bb746d90..06133ce4a765 100644 --- a/vms/platformvm/txs/builder/builder.go +++ b/vms/platformvm/txs/builder/builder.go @@ -282,7 +282,7 @@ func (b *builder) NewImportTx( changeAddr ids.ShortID, memo []byte, ) (*txs.Tx, error) { - unitFees, err := b.state.GetUnitFees() + feeRates, err := b.state.GetFeeRates() if err != nil { return nil, err } @@ -297,8 +297,8 @@ func (b *builder) NewImportTx( IsEUpgradeActive: isEUpgradeActive, Config: b.cfg, ChainTime: chainTime, - FeeManager: commonfees.NewManager(unitFees), - ConsumedUnitsCap: feeCfg.BlockUnitsCap, + FeeManager: commonfees.NewManager(feeRates), + ConsumedUnitsCap: feeCfg.BlockMaxComplexity, } ) @@ -334,7 +334,7 @@ func (b *builder) NewExportTx( changeAddr ids.ShortID, memo []byte, ) (*txs.Tx, error) { - unitFees, err := b.state.GetUnitFees() + feeRates, err := b.state.GetFeeRates() if err != nil { return nil, err } @@ -349,8 +349,8 @@ func (b *builder) NewExportTx( IsEUpgradeActive: isEUpgradeActive, Config: b.cfg, ChainTime: chainTime, - FeeManager: commonfees.NewManager(unitFees), - ConsumedUnitsCap: feeCfg.BlockUnitsCap, + FeeManager: commonfees.NewManager(feeRates), + ConsumedUnitsCap: feeCfg.BlockMaxComplexity, } ) @@ -393,7 +393,7 @@ func (b *builder) NewCreateChainTx( changeAddr ids.ShortID, memo []byte, ) (*txs.Tx, error) { - unitFees, err := b.state.GetUnitFees() + feeRates, err := b.state.GetFeeRates() if err != nil { return nil, err } @@ -408,8 +408,8 @@ func (b *builder) NewCreateChainTx( IsEUpgradeActive: isEUpgradeActive, Config: b.cfg, ChainTime: chainTime, - FeeManager: commonfees.NewManager(unitFees), - ConsumedUnitsCap: feeCfg.BlockUnitsCap, + FeeManager: commonfees.NewManager(feeRates), + ConsumedUnitsCap: feeCfg.BlockMaxComplexity, } ) @@ -440,7 +440,7 @@ func (b *builder) NewCreateSubnetTx( changeAddr ids.ShortID, memo []byte, ) (*txs.Tx, error) { - unitFees, err := b.state.GetUnitFees() + feeRates, err := b.state.GetFeeRates() if err != nil { return nil, err } @@ -455,8 +455,8 @@ func (b *builder) NewCreateSubnetTx( IsEUpgradeActive: isEUpgradeActive, Config: b.cfg, ChainTime: chainTime, - FeeManager: commonfees.NewManager(unitFees), - ConsumedUnitsCap: feeCfg.BlockUnitsCap, + FeeManager: commonfees.NewManager(feeRates), + ConsumedUnitsCap: feeCfg.BlockMaxComplexity, } ) @@ -501,7 +501,7 @@ func (b *builder) NewTransformSubnetTx( changeAddr ids.ShortID, memo []byte, ) (*txs.Tx, error) { - unitFees, err := b.state.GetUnitFees() + feeRates, err := b.state.GetFeeRates() if err != nil { return nil, err } @@ -516,8 +516,8 @@ func (b *builder) NewTransformSubnetTx( IsEUpgradeActive: isEUpgradeActive, Config: b.cfg, ChainTime: chainTime, - FeeManager: commonfees.NewManager(unitFees), - ConsumedUnitsCap: feeCfg.BlockUnitsCap, + FeeManager: commonfees.NewManager(feeRates), + ConsumedUnitsCap: feeCfg.BlockMaxComplexity, } ) @@ -561,7 +561,7 @@ func (b *builder) NewAddValidatorTx( changeAddr ids.ShortID, memo []byte, ) (*txs.Tx, error) { - unitFees, err := b.state.GetUnitFees() + feeRates, err := b.state.GetFeeRates() if err != nil { return nil, err } @@ -576,8 +576,8 @@ func (b *builder) NewAddValidatorTx( IsEUpgradeActive: isEUpgradeActive, Config: b.cfg, ChainTime: chainTime, - FeeManager: commonfees.NewManager(unitFees), - ConsumedUnitsCap: feeCfg.BlockUnitsCap, + FeeManager: commonfees.NewManager(feeRates), + ConsumedUnitsCap: feeCfg.BlockMaxComplexity, } ) @@ -623,7 +623,7 @@ func (b *builder) NewAddPermissionlessValidatorTx( changeAddr ids.ShortID, memo []byte, ) (*txs.Tx, error) { - unitFees, err := b.state.GetUnitFees() + feeRates, err := b.state.GetFeeRates() if err != nil { return nil, err } @@ -638,8 +638,8 @@ func (b *builder) NewAddPermissionlessValidatorTx( IsEUpgradeActive: isEUpgradeActive, Config: b.cfg, ChainTime: chainTime, - FeeManager: commonfees.NewManager(unitFees), - ConsumedUnitsCap: feeCfg.BlockUnitsCap, + FeeManager: commonfees.NewManager(feeRates), + ConsumedUnitsCap: feeCfg.BlockMaxComplexity, } ) @@ -689,7 +689,7 @@ func (b *builder) NewAddDelegatorTx( changeAddr ids.ShortID, memo []byte, ) (*txs.Tx, error) { - unitFees, err := b.state.GetUnitFees() + feeRates, err := b.state.GetFeeRates() if err != nil { return nil, err } @@ -704,8 +704,8 @@ func (b *builder) NewAddDelegatorTx( IsEUpgradeActive: isEUpgradeActive, Config: b.cfg, ChainTime: chainTime, - FeeManager: commonfees.NewManager(unitFees), - ConsumedUnitsCap: feeCfg.BlockUnitsCap, + FeeManager: commonfees.NewManager(feeRates), + ConsumedUnitsCap: feeCfg.BlockMaxComplexity, } ) @@ -748,7 +748,7 @@ func (b *builder) NewAddPermissionlessDelegatorTx( changeAddr ids.ShortID, memo []byte, ) (*txs.Tx, error) { - unitFees, err := b.state.GetUnitFees() + feeRates, err := b.state.GetFeeRates() if err != nil { return nil, err } @@ -763,8 +763,8 @@ func (b *builder) NewAddPermissionlessDelegatorTx( IsEUpgradeActive: isEUpgradeActive, Config: b.cfg, ChainTime: chainTime, - FeeManager: commonfees.NewManager(unitFees), - ConsumedUnitsCap: feeCfg.BlockUnitsCap, + FeeManager: commonfees.NewManager(feeRates), + ConsumedUnitsCap: feeCfg.BlockMaxComplexity, } ) @@ -811,7 +811,7 @@ func (b *builder) NewAddSubnetValidatorTx( changeAddr ids.ShortID, memo []byte, ) (*txs.Tx, error) { - unitFees, err := b.state.GetUnitFees() + feeRates, err := b.state.GetFeeRates() if err != nil { return nil, err } @@ -826,8 +826,8 @@ func (b *builder) NewAddSubnetValidatorTx( IsEUpgradeActive: isEUpgradeActive, Config: b.cfg, ChainTime: chainTime, - FeeManager: commonfees.NewManager(unitFees), - ConsumedUnitsCap: feeCfg.BlockUnitsCap, + FeeManager: commonfees.NewManager(feeRates), + ConsumedUnitsCap: feeCfg.BlockMaxComplexity, } ) @@ -864,7 +864,7 @@ func (b *builder) NewRemoveSubnetValidatorTx( changeAddr ids.ShortID, memo []byte, ) (*txs.Tx, error) { - unitFees, err := b.state.GetUnitFees() + feeRates, err := b.state.GetFeeRates() if err != nil { return nil, err } @@ -879,8 +879,8 @@ func (b *builder) NewRemoveSubnetValidatorTx( IsEUpgradeActive: isEUpgradeActive, Config: b.cfg, ChainTime: chainTime, - FeeManager: commonfees.NewManager(unitFees), - ConsumedUnitsCap: feeCfg.BlockUnitsCap, + FeeManager: commonfees.NewManager(feeRates), + ConsumedUnitsCap: feeCfg.BlockMaxComplexity, } ) @@ -909,7 +909,7 @@ func (b *builder) NewTransferSubnetOwnershipTx( changeAddr ids.ShortID, memo []byte, ) (*txs.Tx, error) { - unitFees, err := b.state.GetUnitFees() + feeRates, err := b.state.GetFeeRates() if err != nil { return nil, err } @@ -924,8 +924,8 @@ func (b *builder) NewTransferSubnetOwnershipTx( IsEUpgradeActive: isEUpgradeActive, Config: b.cfg, ChainTime: chainTime, - FeeManager: commonfees.NewManager(unitFees), - ConsumedUnitsCap: feeCfg.BlockUnitsCap, + FeeManager: commonfees.NewManager(feeRates), + ConsumedUnitsCap: feeCfg.BlockMaxComplexity, } ) @@ -959,7 +959,7 @@ func (b *builder) NewBaseTx( changeAddr ids.ShortID, memo []byte, ) (*txs.Tx, error) { - unitFees, err := b.state.GetUnitFees() + feeRates, err := b.state.GetFeeRates() if err != nil { return nil, err } @@ -974,8 +974,8 @@ func (b *builder) NewBaseTx( IsEUpgradeActive: isEUpgradeActive, Config: b.cfg, ChainTime: chainTime, - FeeManager: commonfees.NewManager(unitFees), - ConsumedUnitsCap: feeCfg.BlockUnitsCap, + FeeManager: commonfees.NewManager(feeRates), + ConsumedUnitsCap: feeCfg.BlockMaxComplexity, } ) diff --git a/vms/platformvm/txs/executor/atomic_tx_executor.go b/vms/platformvm/txs/executor/atomic_tx_executor.go index 791da5fe912b..baee0d076cfa 100644 --- a/vms/platformvm/txs/executor/atomic_tx_executor.go +++ b/vms/platformvm/txs/executor/atomic_tx_executor.go @@ -103,11 +103,11 @@ func (e *AtomicTxExecutor) atomicTx(tx txs.UnsignedTx) error { feesCfg := config.GetDynamicFeesConfig(false /*isEActive*/) executor := StandardTxExecutor{ - Backend: e.Backend, - BlkFeeManager: commonfees.NewManager(commonfees.Empty), - UnitCaps: feesCfg.BlockUnitsCap, - State: e.OnAccept, - Tx: e.Tx, + Backend: e.Backend, + BlkFeeManager: commonfees.NewManager(commonfees.Empty), + BlockMaxComplexity: feesCfg.BlockMaxComplexity, + State: e.OnAccept, + Tx: e.Tx, } err = tx.Visit(&executor) e.Inputs = executor.Inputs diff --git a/vms/platformvm/txs/executor/create_chain_test.go b/vms/platformvm/txs/executor/create_chain_test.go index 3e290bf0b672..9e5fcd36aaa2 100644 --- a/vms/platformvm/txs/executor/create_chain_test.go +++ b/vms/platformvm/txs/executor/create_chain_test.go @@ -58,11 +58,11 @@ func TestCreateChainTxInsufficientControlSigs(t *testing.T) { chainTime := env.state.GetTimestamp() feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ - Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(feeCfg.InitialUnitFees), - UnitCaps: feeCfg.BlockUnitsCap, - State: stateDiff, - Tx: tx, + Backend: &env.backend, + BlkFeeManager: commonfees.NewManager(feeCfg.InitialFeeRate), + BlockMaxComplexity: feeCfg.BlockMaxComplexity, + State: stateDiff, + Tx: tx, } err = tx.Unsigned.Visit(&executor) require.ErrorIs(err, errUnauthorizedSubnetModification) @@ -102,11 +102,11 @@ func TestCreateChainTxWrongControlSig(t *testing.T) { chainTime := stateDiff.GetTimestamp() feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ - Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(feeCfg.InitialUnitFees), - UnitCaps: feeCfg.BlockUnitsCap, - State: stateDiff, - Tx: tx, + Backend: &env.backend, + BlkFeeManager: commonfees.NewManager(feeCfg.InitialFeeRate), + BlockMaxComplexity: feeCfg.BlockMaxComplexity, + State: stateDiff, + Tx: tx, } err = tx.Unsigned.Visit(&executor) require.ErrorIs(err, errUnauthorizedSubnetModification) @@ -137,17 +137,17 @@ func TestCreateChainTxNoSuchSubnet(t *testing.T) { stateDiff, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - unitFees, err := env.state.GetUnitFees() + feeRates, err := env.state.GetFeeRates() require.NoError(err) currentTime := stateDiff.GetTimestamp() feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(currentTime)) executor := StandardTxExecutor{ - Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(unitFees), - UnitCaps: feeCfg.BlockUnitsCap, - State: stateDiff, - Tx: tx, + Backend: &env.backend, + BlkFeeManager: commonfees.NewManager(feeRates), + BlockMaxComplexity: feeCfg.BlockMaxComplexity, + State: stateDiff, + Tx: tx, } err = tx.Unsigned.Visit(&executor) require.ErrorIs(err, database.ErrNotFound) @@ -175,17 +175,17 @@ func TestCreateChainTxValid(t *testing.T) { stateDiff, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - unitFees, err := env.state.GetUnitFees() + feeRates, err := env.state.GetFeeRates() require.NoError(err) currentTime := stateDiff.GetTimestamp() feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(currentTime)) executor := StandardTxExecutor{ - Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(unitFees), - UnitCaps: feeCfg.BlockUnitsCap, - State: stateDiff, - Tx: tx, + Backend: &env.backend, + BlkFeeManager: commonfees.NewManager(feeRates), + BlockMaxComplexity: feeCfg.BlockMaxComplexity, + State: stateDiff, + Tx: tx, } require.NoError(tx.Unsigned.Visit(&executor)) } @@ -246,8 +246,8 @@ func TestCreateChainTxAP3FeeChange(t *testing.T) { IsEUpgradeActive: false, Config: &cfg, ChainTime: test.time, - FeeManager: commonfees.NewManager(feeCfg.InitialUnitFees), - ConsumedUnitsCap: feeCfg.BlockUnitsCap, + FeeManager: commonfees.NewManager(feeCfg.InitialFeeRate), + ConsumedUnitsCap: feeCfg.BlockMaxComplexity, } ) backend.ResetAddresses(addrs) @@ -275,11 +275,11 @@ func TestCreateChainTxAP3FeeChange(t *testing.T) { currentTime := stateDiff.GetTimestamp() feeCfg = config.GetDynamicFeesConfig(env.config.IsEActivated(currentTime)) executor := StandardTxExecutor{ - Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(feeCfg.InitialUnitFees), - UnitCaps: feeCfg.BlockUnitsCap, - State: stateDiff, - Tx: tx, + Backend: &env.backend, + BlkFeeManager: commonfees.NewManager(feeCfg.InitialFeeRate), + BlockMaxComplexity: feeCfg.BlockMaxComplexity, + State: stateDiff, + Tx: tx, } err = tx.Unsigned.Visit(&executor) require.ErrorIs(err, test.expectedError) diff --git a/vms/platformvm/txs/executor/create_subnet_test.go b/vms/platformvm/txs/executor/create_subnet_test.go index 1bccfbd45c1b..da1ac2e05bcc 100644 --- a/vms/platformvm/txs/executor/create_subnet_test.go +++ b/vms/platformvm/txs/executor/create_subnet_test.go @@ -83,8 +83,8 @@ func TestCreateSubnetTxAP3FeeChange(t *testing.T) { IsEUpgradeActive: false, Config: &cfg, ChainTime: test.time, - FeeManager: commonfees.NewManager(feeCfg.InitialUnitFees), - ConsumedUnitsCap: feeCfg.BlockUnitsCap, + FeeManager: commonfees.NewManager(feeCfg.InitialFeeRate), + ConsumedUnitsCap: feeCfg.BlockMaxComplexity, Fee: test.fee, } @@ -110,11 +110,11 @@ func TestCreateSubnetTxAP3FeeChange(t *testing.T) { chainTime = stateDiff.GetTimestamp() feeCfg = config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ - Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(feeCfg.InitialUnitFees), - UnitCaps: feeCfg.BlockUnitsCap, - State: stateDiff, - Tx: tx, + Backend: &env.backend, + BlkFeeManager: commonfees.NewManager(feeCfg.InitialFeeRate), + BlockMaxComplexity: feeCfg.BlockMaxComplexity, + State: stateDiff, + Tx: tx, } err = tx.Unsigned.Visit(&executor) require.ErrorIs(err, test.expectedErr) diff --git a/vms/platformvm/txs/executor/helpers_test.go b/vms/platformvm/txs/executor/helpers_test.go index 8ab087189a87..3420bc0961b7 100644 --- a/vms/platformvm/txs/executor/helpers_test.go +++ b/vms/platformvm/txs/executor/helpers_test.go @@ -235,17 +235,17 @@ func addSubnet( stateDiff, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - unitFees, err := env.state.GetUnitFees() + feeRates, err := env.state.GetFeeRates() require.NoError(err) chainTime := env.state.GetTimestamp() feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ - Backend: &env.backend, - BlkFeeManager: fees.NewManager(unitFees), - UnitCaps: feeCfg.BlockUnitsCap, - State: stateDiff, - Tx: testSubnet1, + Backend: &env.backend, + BlkFeeManager: fees.NewManager(feeRates), + BlockMaxComplexity: feeCfg.BlockMaxComplexity, + State: stateDiff, + Tx: testSubnet1, } require.NoError(testSubnet1.Unsigned.Visit(&executor)) diff --git a/vms/platformvm/txs/executor/standard_tx_executor.go b/vms/platformvm/txs/executor/standard_tx_executor.go index 96a7fcc28577..3b49da5e1e53 100644 --- a/vms/platformvm/txs/executor/standard_tx_executor.go +++ b/vms/platformvm/txs/executor/standard_tx_executor.go @@ -35,10 +35,10 @@ var ( type StandardTxExecutor struct { // inputs, to be filled before visitor methods are called *Backend - BlkFeeManager *commonFees.Manager - UnitCaps commonFees.Dimensions - State state.Diff // state is expected to be modified - Tx *txs.Tx + BlkFeeManager *commonFees.Manager + BlockMaxComplexity commonFees.Dimensions + State state.Diff // state is expected to be modified + Tx *txs.Tx // outputs of visitor execution OnAccept func() // may be nil @@ -78,7 +78,7 @@ func (e *StandardTxExecutor) CreateChainTx(tx *txs.CreateChainTx) error { Config: e.Backend.Config, ChainTime: currentTimestamp, FeeManager: e.BlkFeeManager, - ConsumedUnitsCap: e.UnitCaps, + ConsumedUnitsCap: e.BlockMaxComplexity, Credentials: e.Tx.Creds, } if err := tx.Visit(&feeCalculator); err != nil { @@ -135,7 +135,7 @@ func (e *StandardTxExecutor) CreateSubnetTx(tx *txs.CreateSubnetTx) error { Config: e.Backend.Config, ChainTime: currentTimestamp, FeeManager: e.BlkFeeManager, - ConsumedUnitsCap: e.UnitCaps, + ConsumedUnitsCap: e.BlockMaxComplexity, Credentials: e.Tx.Creds, } if err := tx.Visit(&feeCalculator); err != nil { @@ -231,7 +231,7 @@ func (e *StandardTxExecutor) ImportTx(tx *txs.ImportTx) error { Config: cfg, ChainTime: currentTimestamp, FeeManager: e.BlkFeeManager, - ConsumedUnitsCap: e.UnitCaps, + ConsumedUnitsCap: e.BlockMaxComplexity, Credentials: e.Tx.Creds, } if err := tx.Visit(&feeCalculator); err != nil { @@ -295,7 +295,7 @@ func (e *StandardTxExecutor) ExportTx(tx *txs.ExportTx) error { Config: e.Backend.Config, ChainTime: currentTimestamp, FeeManager: e.BlkFeeManager, - ConsumedUnitsCap: e.UnitCaps, + ConsumedUnitsCap: e.BlockMaxComplexity, Credentials: e.Tx.Creds, } if err := tx.Visit(&feeCalculator); err != nil { @@ -399,7 +399,7 @@ func (e *StandardTxExecutor) AddSubnetValidatorTx(tx *txs.AddSubnetValidatorTx) if err := verifyAddSubnetValidatorTx( e.Backend, e.BlkFeeManager, - e.UnitCaps, + e.BlockMaxComplexity, e.State, e.Tx, tx, @@ -446,7 +446,7 @@ func (e *StandardTxExecutor) RemoveSubnetValidatorTx(tx *txs.RemoveSubnetValidat staker, isCurrentValidator, err := verifyRemoveSubnetValidatorTx( e.Backend, e.BlkFeeManager, - e.UnitCaps, + e.BlockMaxComplexity, e.State, e.Tx, tx, @@ -498,7 +498,7 @@ func (e *StandardTxExecutor) TransformSubnetTx(tx *txs.TransformSubnetTx) error Config: e.Backend.Config, ChainTime: currentTimestamp, FeeManager: e.BlkFeeManager, - ConsumedUnitsCap: e.UnitCaps, + ConsumedUnitsCap: e.BlockMaxComplexity, Credentials: e.Tx.Creds, } if err := tx.Visit(&feeCalculator); err != nil { @@ -539,7 +539,7 @@ func (e *StandardTxExecutor) AddPermissionlessValidatorTx(tx *txs.AddPermissionl if err := verifyAddPermissionlessValidatorTx( e.Backend, e.BlkFeeManager, - e.UnitCaps, + e.BlockMaxComplexity, e.State, e.Tx, tx, @@ -573,7 +573,7 @@ func (e *StandardTxExecutor) AddPermissionlessDelegatorTx(tx *txs.AddPermissionl if err := verifyAddPermissionlessDelegatorTx( e.Backend, e.BlkFeeManager, - e.UnitCaps, + e.BlockMaxComplexity, e.State, e.Tx, tx, @@ -599,7 +599,7 @@ func (e *StandardTxExecutor) TransferSubnetOwnershipTx(tx *txs.TransferSubnetOwn err := verifyTransferSubnetOwnershipTx( e.Backend, e.BlkFeeManager, - e.UnitCaps, + e.BlockMaxComplexity, e.State, e.Tx, tx, @@ -640,7 +640,7 @@ func (e *StandardTxExecutor) BaseTx(tx *txs.BaseTx) error { Config: cfg, ChainTime: currentTimestamp, FeeManager: e.BlkFeeManager, - ConsumedUnitsCap: e.UnitCaps, + ConsumedUnitsCap: e.BlockMaxComplexity, Credentials: e.Tx.Creds, } if err := tx.Visit(&feeCalculator); err != nil { diff --git a/vms/platformvm/txs/executor/standard_tx_executor_test.go b/vms/platformvm/txs/executor/standard_tx_executor_test.go index d92dbef7004f..7813a21faaee 100644 --- a/vms/platformvm/txs/executor/standard_tx_executor_test.go +++ b/vms/platformvm/txs/executor/standard_tx_executor_test.go @@ -91,11 +91,11 @@ func TestStandardTxExecutorAddValidatorTxEmptyID(t *testing.T) { chainTime := env.state.GetTimestamp() feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ - Backend: &env.backend, - BlkFeeManager: fees.NewManager(feeCfg.InitialUnitFees), - UnitCaps: feeCfg.BlockUnitsCap, - State: stateDiff, - Tx: tx, + Backend: &env.backend, + BlkFeeManager: fees.NewManager(feeCfg.InitialFeeRate), + BlockMaxComplexity: feeCfg.BlockMaxComplexity, + State: stateDiff, + Tx: tx, } err = tx.Unsigned.Visit(&executor) require.ErrorIs(err, test.expectedError) @@ -342,11 +342,11 @@ func TestStandardTxExecutorAddDelegator(t *testing.T) { chainTime := freshTH.state.GetTimestamp() feeCfg := config.GetDynamicFeesConfig(freshTH.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ - Backend: &freshTH.backend, - BlkFeeManager: fees.NewManager(fees.Empty), - UnitCaps: feeCfg.BlockUnitsCap, - State: onAcceptState, - Tx: tx, + Backend: &freshTH.backend, + BlkFeeManager: fees.NewManager(fees.Empty), + BlockMaxComplexity: feeCfg.BlockMaxComplexity, + State: onAcceptState, + Tx: tx, } err = tx.Unsigned.Visit(&executor) require.ErrorIs(err, tt.expectedExecutionErr) @@ -385,11 +385,11 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { chainTime := env.state.GetTimestamp() feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ - Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.Empty), - UnitCaps: feeCfg.BlockUnitsCap, - State: onAcceptState, - Tx: tx, + Backend: &env.backend, + BlkFeeManager: fees.NewManager(fees.Empty), + BlockMaxComplexity: feeCfg.BlockMaxComplexity, + State: onAcceptState, + Tx: tx, } err = tx.Unsigned.Visit(&executor) require.ErrorIs(err, ErrPeriodMismatch) @@ -418,11 +418,11 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { chainTime := env.state.GetTimestamp() feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ - Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.Empty), - UnitCaps: feeCfg.BlockUnitsCap, - State: onAcceptState, - Tx: tx, + Backend: &env.backend, + BlkFeeManager: fees.NewManager(fees.Empty), + BlockMaxComplexity: feeCfg.BlockMaxComplexity, + State: onAcceptState, + Tx: tx, } require.NoError(tx.Unsigned.Visit(&executor)) } @@ -466,11 +466,11 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { chainTime := env.state.GetTimestamp() feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ - Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.Empty), - UnitCaps: feeCfg.BlockUnitsCap, - State: onAcceptState, - Tx: tx, + Backend: &env.backend, + BlkFeeManager: fees.NewManager(fees.Empty), + BlockMaxComplexity: feeCfg.BlockMaxComplexity, + State: onAcceptState, + Tx: tx, } err = tx.Unsigned.Visit(&executor) require.ErrorIs(err, ErrNotValidator) @@ -514,11 +514,11 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { chainTime := env.state.GetTimestamp() feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ - Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.Empty), - UnitCaps: feeCfg.BlockUnitsCap, - State: onAcceptState, - Tx: tx, + Backend: &env.backend, + BlkFeeManager: fees.NewManager(fees.Empty), + BlockMaxComplexity: feeCfg.BlockMaxComplexity, + State: onAcceptState, + Tx: tx, } err = tx.Unsigned.Visit(&executor) require.ErrorIs(err, ErrPeriodMismatch) @@ -545,11 +545,11 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { chainTime := env.state.GetTimestamp() feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ - Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.Empty), - UnitCaps: feeCfg.BlockUnitsCap, - State: onAcceptState, - Tx: tx, + Backend: &env.backend, + BlkFeeManager: fees.NewManager(fees.Empty), + BlockMaxComplexity: feeCfg.BlockMaxComplexity, + State: onAcceptState, + Tx: tx, } err = tx.Unsigned.Visit(&executor) require.ErrorIs(err, ErrPeriodMismatch) @@ -576,11 +576,11 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { chainTime := env.state.GetTimestamp() feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ - Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.Empty), - UnitCaps: feeCfg.BlockUnitsCap, - State: onAcceptState, - Tx: tx, + Backend: &env.backend, + BlkFeeManager: fees.NewManager(fees.Empty), + BlockMaxComplexity: feeCfg.BlockMaxComplexity, + State: onAcceptState, + Tx: tx, } require.NoError(tx.Unsigned.Visit(&executor)) } @@ -609,11 +609,11 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { chainTime := env.state.GetTimestamp() feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ - Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.Empty), - UnitCaps: feeCfg.BlockUnitsCap, - State: onAcceptState, - Tx: tx, + Backend: &env.backend, + BlkFeeManager: fees.NewManager(fees.Empty), + BlockMaxComplexity: feeCfg.BlockMaxComplexity, + State: onAcceptState, + Tx: tx, } err = tx.Unsigned.Visit(&executor) require.ErrorIs(err, ErrTimestampNotBeforeStartTime) @@ -671,11 +671,11 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { chainTime := env.state.GetTimestamp() feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ - Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.Empty), - UnitCaps: feeCfg.BlockUnitsCap, - State: onAcceptState, - Tx: duplicateSubnetTx, + Backend: &env.backend, + BlkFeeManager: fees.NewManager(fees.Empty), + BlockMaxComplexity: feeCfg.BlockMaxComplexity, + State: onAcceptState, + Tx: duplicateSubnetTx, } err = duplicateSubnetTx.Unsigned.Visit(&executor) require.ErrorIs(err, ErrDuplicateValidator) @@ -713,11 +713,11 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { chainTime := env.state.GetTimestamp() feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ - Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.Empty), - UnitCaps: feeCfg.BlockUnitsCap, - State: onAcceptState, - Tx: tx, + Backend: &env.backend, + BlkFeeManager: fees.NewManager(fees.Empty), + BlockMaxComplexity: feeCfg.BlockMaxComplexity, + State: onAcceptState, + Tx: tx, } err = tx.Unsigned.Visit(&executor) require.ErrorIs(err, secp256k1fx.ErrInputIndicesNotSortedUnique) @@ -751,11 +751,11 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { chainTime := env.state.GetTimestamp() feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ - Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.Empty), - UnitCaps: feeCfg.BlockUnitsCap, - State: onAcceptState, - Tx: tx, + Backend: &env.backend, + BlkFeeManager: fees.NewManager(fees.Empty), + BlockMaxComplexity: feeCfg.BlockMaxComplexity, + State: onAcceptState, + Tx: tx, } err = tx.Unsigned.Visit(&executor) require.ErrorIs(err, errUnauthorizedSubnetModification) @@ -787,11 +787,11 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { chainTime := env.state.GetTimestamp() feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ - Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.Empty), - UnitCaps: feeCfg.BlockUnitsCap, - State: onAcceptState, - Tx: tx, + Backend: &env.backend, + BlkFeeManager: fees.NewManager(fees.Empty), + BlockMaxComplexity: feeCfg.BlockMaxComplexity, + State: onAcceptState, + Tx: tx, } err = tx.Unsigned.Visit(&executor) require.ErrorIs(err, errUnauthorizedSubnetModification) @@ -833,11 +833,11 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { chainTime := env.state.GetTimestamp() feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ - Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.Empty), - UnitCaps: feeCfg.BlockUnitsCap, - State: onAcceptState, - Tx: tx, + Backend: &env.backend, + BlkFeeManager: fees.NewManager(fees.Empty), + BlockMaxComplexity: feeCfg.BlockMaxComplexity, + State: onAcceptState, + Tx: tx, } err = tx.Unsigned.Visit(&executor) require.ErrorIs(err, ErrDuplicateValidator) @@ -873,11 +873,11 @@ func TestBanffStandardTxExecutorAddValidator(t *testing.T) { chainTime := env.state.GetTimestamp() feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ - Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.Empty), - UnitCaps: feeCfg.BlockUnitsCap, - State: onAcceptState, - Tx: tx, + Backend: &env.backend, + BlkFeeManager: fees.NewManager(fees.Empty), + BlockMaxComplexity: feeCfg.BlockMaxComplexity, + State: onAcceptState, + Tx: tx, } err = tx.Unsigned.Visit(&executor) require.ErrorIs(err, ErrTimestampNotBeforeStartTime) @@ -917,11 +917,11 @@ func TestBanffStandardTxExecutorAddValidator(t *testing.T) { chainTime := env.state.GetTimestamp() feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ - Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.Empty), - UnitCaps: feeCfg.BlockUnitsCap, - State: onAcceptState, - Tx: tx, + Backend: &env.backend, + BlkFeeManager: fees.NewManager(fees.Empty), + BlockMaxComplexity: feeCfg.BlockMaxComplexity, + State: onAcceptState, + Tx: tx, } err = tx.Unsigned.Visit(&executor) require.ErrorIs(err, ErrAlreadyValidator) @@ -958,11 +958,11 @@ func TestBanffStandardTxExecutorAddValidator(t *testing.T) { chainTime := env.state.GetTimestamp() feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ - Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.Empty), - UnitCaps: feeCfg.BlockUnitsCap, - State: onAcceptState, - Tx: tx, + Backend: &env.backend, + BlkFeeManager: fees.NewManager(fees.Empty), + BlockMaxComplexity: feeCfg.BlockMaxComplexity, + State: onAcceptState, + Tx: tx, } err = tx.Unsigned.Visit(&executor) require.ErrorIs(err, ErrAlreadyValidator) @@ -998,11 +998,11 @@ func TestBanffStandardTxExecutorAddValidator(t *testing.T) { chainTime := env.state.GetTimestamp() feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) executor := StandardTxExecutor{ - Backend: &env.backend, - BlkFeeManager: fees.NewManager(fees.Empty), - UnitCaps: feeCfg.BlockUnitsCap, - State: onAcceptState, - Tx: tx, + Backend: &env.backend, + BlkFeeManager: fees.NewManager(fees.Empty), + BlockMaxComplexity: feeCfg.BlockMaxComplexity, + State: onAcceptState, + Tx: tx, } err = tx.Unsigned.Visit(&executor) require.ErrorIs(err, ErrFlowCheckFailed) @@ -1586,10 +1586,10 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(fees.Empty), - UnitCaps: feeCfg.BlockUnitsCap, - Tx: env.tx, - State: env.state, + BlkFeeManager: fees.NewManager(fees.Empty), + BlockMaxComplexity: feeCfg.BlockMaxComplexity, + Tx: env.tx, + State: env.state, } e.Bootstrapped.Set(true) return env.unsignedTx, e @@ -1613,10 +1613,10 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(fees.Empty), - UnitCaps: feeCfg.BlockUnitsCap, - Tx: env.tx, - State: env.state, + BlkFeeManager: fees.NewManager(fees.Empty), + BlockMaxComplexity: feeCfg.BlockMaxComplexity, + Tx: env.tx, + State: env.state, } e.Bootstrapped.Set(true) return env.unsignedTx, e @@ -1643,10 +1643,10 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(fees.Empty), - UnitCaps: feeCfg.BlockUnitsCap, - Tx: env.tx, - State: env.state, + BlkFeeManager: fees.NewManager(fees.Empty), + BlockMaxComplexity: feeCfg.BlockMaxComplexity, + Tx: env.tx, + State: env.state, } e.Bootstrapped.Set(true) return env.unsignedTx, e @@ -1676,10 +1676,10 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(fees.Empty), - UnitCaps: feeCfg.BlockUnitsCap, - Tx: env.tx, - State: env.state, + BlkFeeManager: fees.NewManager(fees.Empty), + BlockMaxComplexity: feeCfg.BlockMaxComplexity, + Tx: env.tx, + State: env.state, } e.Bootstrapped.Set(true) return env.unsignedTx, e @@ -1707,10 +1707,10 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(fees.Empty), - UnitCaps: feeCfg.BlockUnitsCap, - Tx: env.tx, - State: env.state, + BlkFeeManager: fees.NewManager(fees.Empty), + BlockMaxComplexity: feeCfg.BlockMaxComplexity, + Tx: env.tx, + State: env.state, } e.Bootstrapped.Set(true) return env.unsignedTx, e @@ -1737,10 +1737,10 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(fees.Empty), - UnitCaps: feeCfg.BlockUnitsCap, - Tx: env.tx, - State: env.state, + BlkFeeManager: fees.NewManager(fees.Empty), + BlockMaxComplexity: feeCfg.BlockMaxComplexity, + Tx: env.tx, + State: env.state, } e.Bootstrapped.Set(true) return env.unsignedTx, e @@ -1769,10 +1769,10 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(fees.Empty), - UnitCaps: feeCfg.BlockUnitsCap, - Tx: env.tx, - State: env.state, + BlkFeeManager: fees.NewManager(fees.Empty), + BlockMaxComplexity: feeCfg.BlockMaxComplexity, + Tx: env.tx, + State: env.state, } e.Bootstrapped.Set(true) return env.unsignedTx, e @@ -1804,10 +1804,10 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(fees.Empty), - UnitCaps: feeCfg.BlockUnitsCap, - Tx: env.tx, - State: env.state, + BlkFeeManager: fees.NewManager(fees.Empty), + BlockMaxComplexity: feeCfg.BlockMaxComplexity, + Tx: env.tx, + State: env.state, } e.Bootstrapped.Set(true) return env.unsignedTx, e @@ -1961,10 +1961,10 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(fees.Empty), - UnitCaps: feeCfg.BlockUnitsCap, - Tx: env.tx, - State: env.state, + BlkFeeManager: fees.NewManager(fees.Empty), + BlockMaxComplexity: feeCfg.BlockMaxComplexity, + Tx: env.tx, + State: env.state, } e.Bootstrapped.Set(true) return env.unsignedTx, e @@ -1990,10 +1990,10 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(fees.Empty), - UnitCaps: feeCfg.BlockUnitsCap, - Tx: env.tx, - State: env.state, + BlkFeeManager: fees.NewManager(fees.Empty), + BlockMaxComplexity: feeCfg.BlockMaxComplexity, + Tx: env.tx, + State: env.state, } e.Bootstrapped.Set(true) return env.unsignedTx, e @@ -2021,10 +2021,10 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(fees.Empty), - UnitCaps: feeCfg.BlockUnitsCap, - Tx: env.tx, - State: env.state, + BlkFeeManager: fees.NewManager(fees.Empty), + BlockMaxComplexity: feeCfg.BlockMaxComplexity, + Tx: env.tx, + State: env.state, } e.Bootstrapped.Set(true) return env.unsignedTx, e @@ -2057,10 +2057,10 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(fees.Empty), - UnitCaps: feeCfg.BlockUnitsCap, - Tx: env.tx, - State: env.state, + BlkFeeManager: fees.NewManager(fees.Empty), + BlockMaxComplexity: feeCfg.BlockMaxComplexity, + Tx: env.tx, + State: env.state, } e.Bootstrapped.Set(true) return env.unsignedTx, e @@ -2098,10 +2098,10 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: fees.NewManager(fees.Empty), - UnitCaps: feeCfg.BlockUnitsCap, - Tx: env.tx, - State: env.state, + BlkFeeManager: fees.NewManager(fees.Empty), + BlockMaxComplexity: feeCfg.BlockMaxComplexity, + Tx: env.tx, + State: env.state, } e.Bootstrapped.Set(true) return env.unsignedTx, e diff --git a/vms/platformvm/txs/fees/calculator.go b/vms/platformvm/txs/fees/calculator.go index 3005f84f4b73..0a8a722a9558 100644 --- a/vms/platformvm/txs/fees/calculator.go +++ b/vms/platformvm/txs/fees/calculator.go @@ -316,7 +316,7 @@ func (fc *Calculator) meterTx( } func (fc *Calculator) AddFeesFor(consumedUnits fees.Dimensions) (uint64, error) { - boundBreached, dimension := fc.FeeManager.CumulateUnits(consumedUnits, fc.ConsumedUnitsCap) + boundBreached, dimension := fc.FeeManager.CumulateComplexity(consumedUnits, fc.ConsumedUnitsCap) if boundBreached { return 0, fmt.Errorf("%w: breached dimension %d", errFailedConsumedUnitsCumulation, dimension) } @@ -331,7 +331,7 @@ func (fc *Calculator) AddFeesFor(consumedUnits fees.Dimensions) (uint64, error) } func (fc *Calculator) RemoveFeesFor(unitsToRm fees.Dimensions) (uint64, error) { - if err := fc.FeeManager.RemoveUnits(unitsToRm); err != nil { + if err := fc.FeeManager.RemoveComplexity(unitsToRm); err != nil { return 0, fmt.Errorf("failed removing units: %w", err) } diff --git a/vms/platformvm/txs/fees/calculator_test.go b/vms/platformvm/txs/fees/calculator_test.go index aa418b2eebe6..046c14be02c8 100644 --- a/vms/platformvm/txs/fees/calculator_test.go +++ b/vms/platformvm/txs/fees/calculator_test.go @@ -82,25 +82,25 @@ func TestAddAndRemoveFees(t *testing.T) { feeDelta, err := fc.AddFeesFor(units) r.NoError(err) - r.Equal(units, fc.FeeManager.GetCumulatedUnits()) + r.Equal(units, fc.FeeManager.GetCumulatedComplexity()) r.NotZero(feeDelta) r.Equal(feeDelta, fc.Fee) feeDelta2, err := fc.AddFeesFor(units) r.NoError(err) - r.Equal(doubleUnits, fc.FeeManager.GetCumulatedUnits()) + r.Equal(doubleUnits, fc.FeeManager.GetCumulatedComplexity()) r.Equal(feeDelta, feeDelta2) r.Equal(feeDelta+feeDelta2, fc.Fee) feeDelta3, err := fc.RemoveFeesFor(units) r.NoError(err) - r.Equal(units, fc.FeeManager.GetCumulatedUnits()) + r.Equal(units, fc.FeeManager.GetCumulatedComplexity()) r.Equal(feeDelta, feeDelta3) r.Equal(feeDelta, fc.Fee) feeDelta4, err := fc.RemoveFeesFor(units) r.NoError(err) - r.Zero(fc.FeeManager.GetCumulatedUnits()) + r.Zero(fc.FeeManager.GetCumulatedComplexity()) r.Equal(feeDelta, feeDelta4) r.Zero(fc.Fee) } @@ -186,7 +186,7 @@ func TestTxFees(t *testing.T) { 172, 1000, }, - fc.FeeManager.GetCumulatedUnits(), + fc.FeeManager.GetCumulatedComplexity(), ) }, }, @@ -288,7 +288,7 @@ func TestTxFees(t *testing.T) { 172, 1000, }, - fc.FeeManager.GetCumulatedUnits(), + fc.FeeManager.GetCumulatedComplexity(), ) }, }, @@ -354,7 +354,7 @@ func TestTxFees(t *testing.T) { 172, 1000, }, - fc.FeeManager.GetCumulatedUnits(), + fc.FeeManager.GetCumulatedComplexity(), ) }, }, @@ -420,7 +420,7 @@ func TestTxFees(t *testing.T) { 172, 1000, }, - fc.FeeManager.GetCumulatedUnits(), + fc.FeeManager.GetCumulatedComplexity(), ) }, }, @@ -486,7 +486,7 @@ func TestTxFees(t *testing.T) { 172, 1000, }, - fc.FeeManager.GetCumulatedUnits(), + fc.FeeManager.GetCumulatedComplexity(), ) }, }, @@ -552,7 +552,7 @@ func TestTxFees(t *testing.T) { 172, 1000, }, - fc.FeeManager.GetCumulatedUnits(), + fc.FeeManager.GetCumulatedComplexity(), ) }, }, @@ -618,7 +618,7 @@ func TestTxFees(t *testing.T) { 266, 1000, }, - fc.FeeManager.GetCumulatedUnits(), + fc.FeeManager.GetCumulatedComplexity(), ) }, }, @@ -684,7 +684,7 @@ func TestTxFees(t *testing.T) { 266, 1000, }, - fc.FeeManager.GetCumulatedUnits(), + fc.FeeManager.GetCumulatedComplexity(), ) }, }, @@ -750,7 +750,7 @@ func TestTxFees(t *testing.T) { 172, 1000, }, - fc.FeeManager.GetCumulatedUnits(), + fc.FeeManager.GetCumulatedComplexity(), ) }, }, @@ -816,7 +816,7 @@ func TestTxFees(t *testing.T) { 262, 2000, }, - fc.FeeManager.GetCumulatedUnits(), + fc.FeeManager.GetCumulatedComplexity(), ) }, }, @@ -882,7 +882,7 @@ func TestTxFees(t *testing.T) { 266, 1000, }, - fc.FeeManager.GetCumulatedUnits(), + fc.FeeManager.GetCumulatedComplexity(), ) }, }, diff --git a/vms/platformvm/vm_test.go b/vms/platformvm/vm_test.go index 6658c7ca6679..f03a0d97239d 100644 --- a/vms/platformvm/vm_test.go +++ b/vms/platformvm/vm_test.go @@ -372,7 +372,7 @@ func TestGenesis(t *testing.T) { require.Equal(utxo.Address, addr) - unitFees, err := vm.state.GetUnitFees() + unitFees, err := vm.state.GetFeeRates() require.NoError(err) // we use the first key to fund a subnet creation in [defaultGenesis]. @@ -386,7 +386,7 @@ func TestGenesis(t *testing.T) { Config: &vm.Config, ChainTime: chainTime, FeeManager: feeMan, - ConsumedUnitsCap: feeCfg.BlockUnitsCap, + ConsumedUnitsCap: feeCfg.BlockMaxComplexity, Credentials: testSubnet1.Creds, } ) @@ -2268,19 +2268,19 @@ func TestBaseTx(t *testing.T) { } require.Equal(totalOutputAmt, key0OutputAmt+key1OutputAmt+changeAddrOutputAmt) - unitFees, err := vm.state.GetUnitFees() + feeRates, err := vm.state.GetFeeRates() require.NoError(err) var ( chainTime = vm.state.GetTimestamp() feeCfg = config.GetDynamicFeesConfig(vm.Config.IsEActivated(chainTime)) - feeMan = commonfees.NewManager(unitFees) + feeMan = commonfees.NewManager(feeRates) feeCalc = &fees.Calculator{ IsEUpgradeActive: vm.IsEActivated(chainTime), Config: &vm.Config, ChainTime: chainTime, FeeManager: feeMan, - ConsumedUnitsCap: feeCfg.BlockUnitsCap, + ConsumedUnitsCap: feeCfg.BlockMaxComplexity, Credentials: baseTx.Creds, } ) diff --git a/wallet/chain/p/wallet.go b/wallet/chain/p/wallet.go index a95d28976363..9fa29ed8e95e 100644 --- a/wallet/chain/p/wallet.go +++ b/wallet/chain/p/wallet.go @@ -280,8 +280,8 @@ type wallet struct { signer walletsigner.Signer client platformvm.Client - isEForkActive bool - unitFees, unitCaps commonfees.Dimensions + isEForkActive bool + feeRates, blockMaxComplexity commonfees.Dimensions } func (w *wallet) Builder() builder.Builder { @@ -309,8 +309,8 @@ func (w *wallet) IssueBaseTx( Config: &config.Config{ CreateSubnetTxFee: w.builder.Context().CreateSubnetTxFee, }, - FeeManager: commonfees.NewManager(w.unitFees), - ConsumedUnitsCap: w.unitCaps, + FeeManager: commonfees.NewManager(w.feeRates), + ConsumedUnitsCap: w.blockMaxComplexity, } ) @@ -337,8 +337,8 @@ func (w *wallet) IssueAddValidatorTx( Config: &config.Config{ AddPrimaryNetworkValidatorFee: w.builder.Context().AddPrimaryNetworkValidatorFee, }, - FeeManager: commonfees.NewManager(w.unitFees), - ConsumedUnitsCap: w.unitCaps, + FeeManager: commonfees.NewManager(w.feeRates), + ConsumedUnitsCap: w.blockMaxComplexity, } utx, err := w.builder.NewAddValidatorTx(vdr, rewardsOwner, shares, feeCalc, options...) @@ -361,8 +361,8 @@ func (w *wallet) IssueAddSubnetValidatorTx( Config: &config.Config{ TxFee: w.builder.Context().BaseTxFee, }, - FeeManager: commonfees.NewManager(w.unitFees), - ConsumedUnitsCap: w.unitCaps, + FeeManager: commonfees.NewManager(w.feeRates), + ConsumedUnitsCap: w.blockMaxComplexity, } utx, err := w.builder.NewAddSubnetValidatorTx(vdr, feeCalc, options...) @@ -387,8 +387,8 @@ func (w *wallet) IssueRemoveSubnetValidatorTx( Config: &config.Config{ TxFee: w.builder.Context().BaseTxFee, }, - FeeManager: commonfees.NewManager(w.unitFees), - ConsumedUnitsCap: w.unitCaps, + FeeManager: commonfees.NewManager(w.feeRates), + ConsumedUnitsCap: w.blockMaxComplexity, } utx, err := w.builder.NewRemoveSubnetValidatorTx(nodeID, subnetID, feeCalc, options...) @@ -413,8 +413,8 @@ func (w *wallet) IssueAddDelegatorTx( Config: &config.Config{ AddPrimaryNetworkDelegatorFee: w.builder.Context().AddPrimaryNetworkDelegatorFee, }, - FeeManager: commonfees.NewManager(w.unitFees), - ConsumedUnitsCap: w.unitCaps, + FeeManager: commonfees.NewManager(w.feeRates), + ConsumedUnitsCap: w.blockMaxComplexity, } utx, err := w.builder.NewAddDelegatorTx(vdr, rewardsOwner, feeCalc, options...) @@ -441,8 +441,8 @@ func (w *wallet) IssueCreateChainTx( Config: &config.Config{ CreateBlockchainTxFee: w.builder.Context().CreateBlockchainTxFee, }, - FeeManager: commonfees.NewManager(w.unitFees), - ConsumedUnitsCap: w.unitCaps, + FeeManager: commonfees.NewManager(w.feeRates), + ConsumedUnitsCap: w.blockMaxComplexity, } utx, err := w.builder.NewCreateChainTx(subnetID, genesis, vmID, fxIDs, chainName, feeCalc, options...) @@ -466,8 +466,8 @@ func (w *wallet) IssueCreateSubnetTx( Config: &config.Config{ CreateSubnetTxFee: w.builder.Context().CreateSubnetTxFee, }, - FeeManager: commonfees.NewManager(w.unitFees), - ConsumedUnitsCap: w.unitCaps, + FeeManager: commonfees.NewManager(w.feeRates), + ConsumedUnitsCap: w.blockMaxComplexity, } utx, err := w.builder.NewCreateSubnetTx(owner, feeCalc, options...) if err != nil { @@ -490,8 +490,8 @@ func (w *wallet) IssueTransferSubnetOwnershipTx( Config: &config.Config{ TxFee: w.builder.Context().BaseTxFee, }, - FeeManager: commonfees.NewManager(w.unitFees), - ConsumedUnitsCap: w.unitCaps, + FeeManager: commonfees.NewManager(w.feeRates), + ConsumedUnitsCap: w.blockMaxComplexity, } utx, err := w.builder.NewTransferSubnetOwnershipTx(subnetID, owner, feeCalc, options...) @@ -515,8 +515,8 @@ func (w *wallet) IssueImportTx( Config: &config.Config{ TxFee: w.builder.Context().BaseTxFee, }, - FeeManager: commonfees.NewManager(w.unitFees), - ConsumedUnitsCap: w.unitCaps, + FeeManager: commonfees.NewManager(w.feeRates), + ConsumedUnitsCap: w.blockMaxComplexity, } utx, err := w.builder.NewImportTx(sourceChainID, to, feeCalc, options...) @@ -541,8 +541,8 @@ func (w *wallet) IssueExportTx( Config: &config.Config{ TxFee: w.builder.Context().BaseTxFee, }, - FeeManager: commonfees.NewManager(w.unitFees), - ConsumedUnitsCap: w.unitCaps, + FeeManager: commonfees.NewManager(w.feeRates), + ConsumedUnitsCap: w.blockMaxComplexity, } utx, err := w.builder.NewExportTx(chainID, outputs, feeCalc, options...) @@ -579,8 +579,8 @@ func (w *wallet) IssueTransformSubnetTx( Config: &config.Config{ TransformSubnetTxFee: w.builder.Context().TransformSubnetTxFee, }, - FeeManager: commonfees.NewManager(w.unitFees), - ConsumedUnitsCap: w.unitCaps, + FeeManager: commonfees.NewManager(w.feeRates), + ConsumedUnitsCap: w.blockMaxComplexity, } utx, err := w.builder.NewTransformSubnetTx( subnetID, @@ -626,8 +626,8 @@ func (w *wallet) IssueAddPermissionlessValidatorTx( AddPrimaryNetworkValidatorFee: w.builder.Context().AddPrimaryNetworkValidatorFee, AddSubnetValidatorFee: w.builder.Context().AddSubnetValidatorFee, }, - FeeManager: commonfees.NewManager(w.unitFees), - ConsumedUnitsCap: w.unitCaps, + FeeManager: commonfees.NewManager(w.feeRates), + ConsumedUnitsCap: w.blockMaxComplexity, } utx, err := w.builder.NewAddPermissionlessValidatorTx( @@ -663,8 +663,8 @@ func (w *wallet) IssueAddPermissionlessDelegatorTx( AddPrimaryNetworkDelegatorFee: w.builder.Context().AddPrimaryNetworkDelegatorFee, AddSubnetDelegatorFee: w.builder.Context().AddSubnetDelegatorFee, }, - FeeManager: commonfees.NewManager(w.unitFees), - ConsumedUnitsCap: w.unitCaps, + FeeManager: commonfees.NewManager(w.feeRates), + ConsumedUnitsCap: w.blockMaxComplexity, } utx, err := w.builder.NewAddPermissionlessDelegatorTx( @@ -744,12 +744,12 @@ func (w *wallet) refreshFeesData(options ...common.Option) error { eUpgradeTime := version.GetEUpgradeTime(w.builder.Context().NetworkID) w.isEForkActive = !chainTime.Before(eUpgradeTime) - _, w.unitFees, err = w.client.GetUnitFees(ctx) + _, w.feeRates, err = w.client.GetFeeRates(ctx) if err != nil { return err } feeCfg := config.GetDynamicFeesConfig(w.isEForkActive) - w.unitCaps = feeCfg.BlockUnitsCap + w.blockMaxComplexity = feeCfg.BlockMaxComplexity return nil } From 442f745eb8d1f25b04e9578c63bf7f658ac9c9ea Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 21 Mar 2024 15:58:46 +0100 Subject: [PATCH 133/190] dropped fee windows --- vms/components/fees/window.go | 106 ----------------------------- vms/components/fees/window_test.go | 70 ------------------- 2 files changed, 176 deletions(-) delete mode 100644 vms/components/fees/window.go delete mode 100644 vms/components/fees/window_test.go diff --git a/vms/components/fees/window.go b/vms/components/fees/window.go deleted file mode 100644 index f050f46caa06..000000000000 --- a/vms/components/fees/window.go +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. -// See the file LICENSE for licensing terms. - -package fees - -import ( - "encoding/binary" - "fmt" - "math" - - safemath "github.com/ava-labs/avalanchego/utils/math" -) - -const WindowSize = 10 - -type ( - Window [WindowSize]uint64 - Windows [FeeDimensions]Window -) - -var EmptyWindows = [FeeDimensions]Window{} - -func (w *Windows) Bytes() []byte { - res := make([]byte, FeeDimensions*WindowSize*uint64Len) - for i := Dimension(0); i < FeeDimensions; i++ { - for j, u := range w[i] { - start := (WindowSize*int(i) + j) * uint64Len - binary.BigEndian.PutUint64(res[start:], u) - } - } - return res -} - -func (w *Windows) FromBytes(b []byte) error { - if len(b) != FeeDimensions*WindowSize*uint64Len { - return fmt.Errorf("unexpected bytes length: expected %d, actual %d", - FeeDimensions*WindowSize*uint64Len, - len(b), - ) - } - for i := Dimension(0); i < FeeDimensions; i++ { - for j := 0; j < WindowSize; j++ { - start := (WindowSize*int(i) + j) * uint64Len - w[i][j] = binary.BigEndian.Uint64(b[start:]) - } - } - return nil -} - -// Roll rolls the uint64s consumed units within [consumptionWindow] over by [roll] places. -// For example, if there are 4 uint64 encoded in a 32 byte slice, rollWindow would -// have the following effect: -// Original: -// [1, 2, 3, 4] -// Roll = 0 -// [1, 2, 3, 4] -// Roll = 1 -// [2, 3, 4, 0] -// Roll = 2 -// [3, 4, 0, 0] -// Roll = 3 -// [4, 0, 0, 0] -// Roll >= 4 -// [0, 0, 0, 0] -// Assumes that [roll] is greater than or equal to 0 -func Roll(w Window, roll int) Window { - // Note: make allocates a zeroed array, so we are guaranteed - // that what we do not copy into, will be set to 0 - var res [WindowSize]uint64 - if roll > WindowSize { - return res - } - copy(res[:], w[roll:]) - return res -} - -// Sum sums the consumed units recorded in [window]. If an overflow occurs, -// while summing the contents, the maximum uint64 value is returned. -func Sum(w Window) uint64 { - var ( - sum uint64 - overflow error - ) - for i := 0; i < WindowSize; i++ { - // If an overflow occurs while summing the elements of the window, return the maximum - // uint64 value immediately. - sum, overflow = safemath.Add64(sum, w[i]) - if overflow != nil { - return math.MaxUint64 - } - } - return sum -} - -// Update adds [unitsConsumed] in at index within [window]. -// Assumes that [index] has already been validated. -// If an overflow occurs, the maximum uint64 value is used. -func Update(w *Window, idx int, unitsConsumed uint64) { - prevUnitsConsumed := w[idx] - - totalUnitsConsumed, overflow := safemath.Add64(prevUnitsConsumed, unitsConsumed) - if overflow != nil { - totalUnitsConsumed = math.MaxUint64 - } - w[idx] = totalUnitsConsumed -} diff --git a/vms/components/fees/window_test.go b/vms/components/fees/window_test.go deleted file mode 100644 index 9dc13bb1bf11..000000000000 --- a/vms/components/fees/window_test.go +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. -// See the file LICENSE for licensing terms. - -package fees - -import ( - "math" - "testing" - - "github.com/stretchr/testify/require" -) - -func TestMarshalUnmarshalWindows(t *testing.T) { - require := require.New(t) - - input := Windows{ - Window{}, - Window{1, 2, 3, 4, 5, 4, 3, 2, 1, 0}, - Window{math.MaxUint64, math.MaxUint64, math.MaxUint64, math.MaxUint64, 0, 0, 0, 0, 0, math.MaxUint64}, - Window{math.MaxUint64, 0, math.MaxUint64, 0, math.MaxUint64, 0, math.MaxUint64, 0, math.MaxUint64, 0}, - } - - bytes := input.Bytes() - var output Windows - require.NoError(output.FromBytes(bytes)) - require.Equal(input, output) -} - -func TestWindowRoll(t *testing.T) { - require := require.New(t) - - var win Window - for i := 0; i < WindowSize; i++ { - win[i] = uint64(i + 2024) - } - - for i := 0; i < WindowSize; i++ { - rolledWin := Roll(win, i) - - // check that first i elements in window are shited out and - // ovewritted by remaining WindowSize - i elements - require.Equal(rolledWin[0:WindowSize-i], win[i:WindowSize]) - - // check that trailing i elemnts of the rolled window are zero - require.Equal(rolledWin[WindowSize-i:], make([]uint64, i)) - } - - // check that overolling wipes all window out - overRolledWin := Roll(win, WindowSize+1) - require.Equal(Window{}, overRolledWin) -} - -func TestSum(t *testing.T) { - require := require.New(t) - - // no overflow case - var win Window - for i := 0; i < WindowSize; i++ { - win[i] = uint64(i + 1) - } - require.Equal(Sum(win), uint64(WindowSize*(WindowSize+1)/2)) - - // overflow case - Update(&win, 0, math.MaxUint64-1) - require.Equal(Sum(win), uint64(math.MaxUint64)) - - // another overflow case - Update(&win, 0, math.MaxUint64) - require.Equal(Sum(win), uint64(math.MaxUint64)) -} From 9c1d8df1e4b0ac7c04e4a0c6b56591f170335dbf Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 21 Mar 2024 16:09:40 +0100 Subject: [PATCH 134/190] some more renaming to improve clarity --- tests/e2e/p/dynamic_fees.go | 4 +- vms/components/fees/manager.go | 6 +- vms/platformvm/block/executor/verifier.go | 2 +- vms/platformvm/client.go | 4 +- vms/platformvm/service.go | 18 +++--- vms/platformvm/service_test.go | 14 ++--- vms/platformvm/state/diff.go | 8 +-- vms/platformvm/state/mock_state.go | 72 +++++++++++----------- vms/platformvm/state/state.go | 22 +++---- vms/platformvm/txs/fees/calculator_test.go | 6 +- vms/platformvm/vm_test.go | 4 +- wallet/chain/p/builder_test.go | 46 +++++++------- 12 files changed, 103 insertions(+), 103 deletions(-) diff --git a/tests/e2e/p/dynamic_fees.go b/tests/e2e/p/dynamic_fees.go index bc10b700839a..25aa5423af20 100644 --- a/tests/e2e/p/dynamic_fees.go +++ b/tests/e2e/p/dynamic_fees.go @@ -122,13 +122,13 @@ var _ = ginkgo.Describe("[Dynamic Fees]", func() { }) ginkgo.By("wait for the fee rates to decrease", func() { - initialUnitFees := currFeeRates + initialFeeRates := currFeeRates e2e.Eventually(func() bool { var err error _, currFeeRates, err = pChainClient.GetFeeRates(e2e.DefaultContext()) require.NoError(err) tests.Outf("{{blue}} next fee rates: %v {{/}}\n", currFeeRates) - return commonfees.Compare(initialUnitFees, currFeeRates) + return commonfees.Compare(initialFeeRates, currFeeRates) }, e2e.DefaultTimeout, e2e.DefaultPollingInterval, "failed to see gas price decrease before timeout") tests.Outf("\n{{blue}}fee rates have decreased to %v{{/}}\n", currFeeRates) }) diff --git a/vms/components/fees/manager.go b/vms/components/fees/manager.go index 4bf9b7c43297..269503ddabac 100644 --- a/vms/components/fees/manager.go +++ b/vms/components/fees/manager.go @@ -103,15 +103,15 @@ func (m *Manager) UpdateFeeRates( elapsedTime := uint64(childBlkTime - parentBlkTime) for i := Dimension(0); i < FeeDimensions; i++ { - nextUnitFee := nextFeeRate( + nextFeeRates := nextFeeRate( m.feeRates[i], feesConfig.UpdateCoefficient[i], parentBlkComplexity[i], feesConfig.BlockTargetComplexityRate[i], elapsedTime, ) - nextUnitFee = max(nextUnitFee, feesConfig.MinFeeRate[i]) - m.feeRates[i] = nextUnitFee + nextFeeRates = max(nextFeeRates, feesConfig.MinFeeRate[i]) + m.feeRates[i] = nextFeeRates } return nil } diff --git a/vms/platformvm/block/executor/verifier.go b/vms/platformvm/block/executor/verifier.go index ed5ef76615f2..342d553b5392 100644 --- a/vms/platformvm/block/executor/verifier.go +++ b/vms/platformvm/block/executor/verifier.go @@ -546,7 +546,7 @@ func (v *verifier) processStandardTxs( } if isEActivated { - state.SetUnitFees(feeManager.GetFeeRates()) + state.SetFeeRates(feeManager.GetFeeRates()) state.SetLastBlockComplexity(feeManager.GetCumulatedComplexity()) } diff --git a/vms/platformvm/client.go b/vms/platformvm/client.go index e7b5af6fcbfa..374ad52bc096 100644 --- a/vms/platformvm/client.go +++ b/vms/platformvm/client.go @@ -552,7 +552,7 @@ func (c *client) GetBlockByHeight(ctx context.Context, height uint64, options .. } func (c *client) GetFeeRates(ctx context.Context, options ...rpc.Option) (commonfees.Dimensions, commonfees.Dimensions, error) { - res := &GetUnitFeesReply{} + res := &GetFeeRatesReply{} err := c.requester.SendRequest(ctx, "platform.getFeeRates", struct{}{}, res, options...) - return res.CurrentUnitFees, res.NextUnitFees, err + return res.CurrentFeeRates, res.NextFeeRates, err } diff --git a/vms/platformvm/service.go b/vms/platformvm/service.go index d79e45261514..560990c309e6 100644 --- a/vms/platformvm/service.go +++ b/vms/platformvm/service.go @@ -1821,17 +1821,17 @@ func (s *Service) GetBlockByHeight(_ *http.Request, args *api.GetBlockByHeightAr return err } -// GetUnitFeesReply is the response from GetFeeRates -type GetUnitFeesReply struct { - CurrentUnitFees commonfees.Dimensions `json:"currentUnitFees"` - NextUnitFees commonfees.Dimensions `json:"nextUnitFees"` +// GetFeeRatesReply is the response from GetFeeRates +type GetFeeRatesReply struct { + CurrentFeeRates commonfees.Dimensions `json:"currentFeeRates"` + NextFeeRates commonfees.Dimensions `json:"nextFeeRates"` } // GetTimestamp returns the current timestamp on chain. -func (s *Service) GetFeeRates(_ *http.Request, _ *struct{}, reply *GetUnitFeesReply) error { +func (s *Service) GetFeeRates(_ *http.Request, _ *struct{}, reply *GetFeeRatesReply) error { s.vm.ctx.Log.Debug("API called", zap.String("service", "platform"), - zap.String("method", "getUnitFees"), + zap.String("method", "getFeeRates"), ) s.vm.ctx.Lock.Lock() @@ -1847,7 +1847,7 @@ func (s *Service) GetFeeRates(_ *http.Request, _ *struct{}, reply *GetUnitFeesRe if err != nil { return err } - reply.CurrentUnitFees = currentFeeRate + reply.CurrentFeeRates = currentFeeRate nextTimestamp, _, err := executor.NextBlockTime(onAccept, &s.vm.clock) if err != nil { @@ -1856,7 +1856,7 @@ func (s *Service) GetFeeRates(_ *http.Request, _ *struct{}, reply *GetUnitFeesRe isEActivated := s.vm.Config.IsEActivated(nextTimestamp) if !isEActivated { - reply.NextUnitFees = reply.CurrentUnitFees + reply.NextFeeRates = reply.CurrentFeeRates return nil } @@ -1881,7 +1881,7 @@ func (s *Service) GetFeeRates(_ *http.Request, _ *struct{}, reply *GetUnitFeesRe return fmt.Errorf("failed updating fee rates, %w", err) } } - reply.NextUnitFees = feeManager.GetFeeRates() + reply.NextFeeRates = feeManager.GetFeeRates() return nil } diff --git a/vms/platformvm/service_test.go b/vms/platformvm/service_test.go index c9da8dc20162..0965930d559f 100644 --- a/vms/platformvm/service_test.go +++ b/vms/platformvm/service_test.go @@ -353,13 +353,13 @@ 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 - unitFees, err := service.vm.state.GetFeeRates() + feeRates, err := service.vm.state.GetFeeRates() require.NoError(err) var ( chainTime = service.vm.state.GetTimestamp() feeCfg = config.GetDynamicFeesConfig(service.vm.Config.IsEActivated(chainTime)) - feeMan = commonfees.NewManager(unitFees) + feeMan = commonfees.NewManager(feeRates) feeCalc = &fees.Calculator{ IsEUpgradeActive: service.vm.IsEActivated(chainTime), Config: &service.vm.Config, @@ -1004,18 +1004,18 @@ func TestServiceGetBlockByHeight(t *testing.T) { } } -func TestGetUnitFees(t *testing.T) { +func TestGetFeeRates(t *testing.T) { require := require.New(t) service, _ := defaultService(t) - reply := GetUnitFeesReply{} + reply := GetFeeRatesReply{} require.NoError(service.GetFeeRates(nil, nil, &reply)) service.vm.ctx.Lock.Lock() feeRates, err := service.vm.state.GetFeeRates() require.NoError(err) - require.Equal(feeRates, reply.CurrentUnitFees) + require.Equal(feeRates, reply.CurrentFeeRates) updatedFeeRates := commonfees.Dimensions{ 123, @@ -1023,10 +1023,10 @@ func TestGetUnitFees(t *testing.T) { 789, 1011, } - service.vm.state.SetUnitFees(updatedFeeRates) + service.vm.state.SetFeeRates(updatedFeeRates) service.vm.ctx.Lock.Unlock() require.NoError(service.GetFeeRates(nil, nil, &reply)) - require.Equal(updatedFeeRates, reply.CurrentUnitFees) + require.Equal(updatedFeeRates, reply.CurrentFeeRates) } diff --git a/vms/platformvm/state/diff.go b/vms/platformvm/state/diff.go index 2328d597c36f..256ede8f9d1a 100644 --- a/vms/platformvm/state/diff.go +++ b/vms/platformvm/state/diff.go @@ -100,19 +100,19 @@ func (d *diff) GetFeeRates() (commonfees.Dimensions, error) { if !ok { return commonfees.Empty, fmt.Errorf("%w: %s", ErrMissingParentState, d.parentID) } - parentUnitFees, err := parentState.GetFeeRates() + parentFeeRates, err := parentState.GetFeeRates() if err != nil { return commonfees.Empty, err } d.feeRates = new(commonfees.Dimensions) - *d.feeRates = parentUnitFees + *d.feeRates = parentFeeRates } return *d.feeRates, nil } -func (d *diff) SetUnitFees(uf commonfees.Dimensions) { +func (d *diff) SetFeeRates(uf commonfees.Dimensions) { if d.feeRates == nil { d.feeRates = new(commonfees.Dimensions) } @@ -457,7 +457,7 @@ func (d *diff) DeleteUTXO(utxoID ids.ID) { func (d *diff) Apply(baseState Chain) error { baseState.SetTimestamp(d.timestamp) if d.feeRates != nil { - baseState.SetUnitFees(*d.feeRates) + baseState.SetFeeRates(*d.feeRates) } if d.lastBlkComplexity != nil { baseState.SetLastBlockComplexity(*d.lastBlkComplexity) diff --git a/vms/platformvm/state/mock_state.go b/vms/platformvm/state/mock_state.go index 720c804a700e..f54f56d533e0 100644 --- a/vms/platformvm/state/mock_state.go +++ b/vms/platformvm/state/mock_state.go @@ -480,6 +480,18 @@ func (mr *MockChainMockRecorder) SetDelegateeReward(arg0, arg1, arg2 any) *gomoc return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetDelegateeReward", reflect.TypeOf((*MockChain)(nil).SetDelegateeReward), arg0, arg1, arg2) } +// SetFeeRates mocks base method. +func (m *MockChain) SetFeeRates(arg0 fees.Dimensions) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetFeeRates", arg0) +} + +// SetFeeRates indicates an expected call of SetFeeRates. +func (mr *MockChainMockRecorder) SetFeeRates(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetFeeRates", reflect.TypeOf((*MockChain)(nil).SetFeeRates), arg0) +} + // SetLastBlockComplexity mocks base method. func (m *MockChain) SetLastBlockComplexity(arg0 fees.Dimensions) { m.ctrl.T.Helper() @@ -516,18 +528,6 @@ func (mr *MockChainMockRecorder) SetTimestamp(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetTimestamp", reflect.TypeOf((*MockChain)(nil).SetTimestamp), arg0) } -// SetUnitFees mocks base method. -func (m *MockChain) SetUnitFees(arg0 fees.Dimensions) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "SetUnitFees", arg0) -} - -// SetUnitFees indicates an expected call of SetUnitFees. -func (mr *MockChainMockRecorder) SetUnitFees(arg0 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetUnitFees", reflect.TypeOf((*MockChain)(nil).SetUnitFees), arg0) -} - // MockDiff is a mock of Diff interface. type MockDiff struct { ctrl *gomock.Controller @@ -996,6 +996,18 @@ func (mr *MockDiffMockRecorder) SetDelegateeReward(arg0, arg1, arg2 any) *gomock return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetDelegateeReward", reflect.TypeOf((*MockDiff)(nil).SetDelegateeReward), arg0, arg1, arg2) } +// SetFeeRates mocks base method. +func (m *MockDiff) SetFeeRates(arg0 fees.Dimensions) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetFeeRates", arg0) +} + +// SetFeeRates indicates an expected call of SetFeeRates. +func (mr *MockDiffMockRecorder) SetFeeRates(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetFeeRates", reflect.TypeOf((*MockDiff)(nil).SetFeeRates), arg0) +} + // SetLastBlockComplexity mocks base method. func (m *MockDiff) SetLastBlockComplexity(arg0 fees.Dimensions) { m.ctrl.T.Helper() @@ -1032,18 +1044,6 @@ func (mr *MockDiffMockRecorder) SetTimestamp(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetTimestamp", reflect.TypeOf((*MockDiff)(nil).SetTimestamp), arg0) } -// SetUnitFees mocks base method. -func (m *MockDiff) SetUnitFees(arg0 fees.Dimensions) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "SetUnitFees", arg0) -} - -// SetUnitFees indicates an expected call of SetUnitFees. -func (mr *MockDiffMockRecorder) SetUnitFees(arg0 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetUnitFees", reflect.TypeOf((*MockDiff)(nil).SetUnitFees), arg0) -} - // MockState is a mock of State interface. type MockState struct { ctrl *gomock.Controller @@ -1727,6 +1727,18 @@ func (mr *MockStateMockRecorder) SetDelegateeReward(arg0, arg1, arg2 any) *gomoc return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetDelegateeReward", reflect.TypeOf((*MockState)(nil).SetDelegateeReward), arg0, arg1, arg2) } +// SetFeeRates mocks base method. +func (m *MockState) SetFeeRates(arg0 fees.Dimensions) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetFeeRates", arg0) +} + +// SetFeeRates indicates an expected call of SetFeeRates. +func (mr *MockStateMockRecorder) SetFeeRates(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetFeeRates", reflect.TypeOf((*MockState)(nil).SetFeeRates), arg0) +} + // SetHeight mocks base method. func (m *MockState) SetHeight(arg0 uint64) { m.ctrl.T.Helper() @@ -1787,18 +1799,6 @@ func (mr *MockStateMockRecorder) SetTimestamp(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetTimestamp", reflect.TypeOf((*MockState)(nil).SetTimestamp), arg0) } -// SetUnitFees mocks base method. -func (m *MockState) SetUnitFees(arg0 fees.Dimensions) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "SetUnitFees", arg0) -} - -// SetUnitFees indicates an expected call of SetUnitFees. -func (mr *MockStateMockRecorder) SetUnitFees(arg0 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetUnitFees", reflect.TypeOf((*MockState)(nil).SetUnitFees), arg0) -} - // SetUptime mocks base method. func (m *MockState) SetUptime(arg0 ids.NodeID, arg1 ids.ID, arg2 time.Duration, arg3 time.Time) error { m.ctrl.T.Helper() diff --git a/vms/platformvm/state/state.go b/vms/platformvm/state/state.go index f533821517cf..c9045d5f950a 100644 --- a/vms/platformvm/state/state.go +++ b/vms/platformvm/state/state.go @@ -73,7 +73,7 @@ var ( CurrentSupplyKey = []byte("current supply") LastAcceptedKey = []byte("last accepted") HeightsIndexedKey = []byte("heights indexed") - UnitFeesKey = []byte("unit fees") + FeeRatesKey = []byte("fee rates") LastBlkComplexityKey = []byte("last complexity") InitializedKey = []byte("initialized") ) @@ -87,7 +87,7 @@ type Chain interface { avax.UTXODeleter GetFeeRates() (commonfees.Dimensions, error) - SetUnitFees(uf commonfees.Dimensions) + SetFeeRates(uf commonfees.Dimensions) GetLastBlockComplexity() (commonfees.Dimensions, error) SetLastBlockComplexity(windows commonfees.Dimensions) @@ -986,9 +986,9 @@ func (s *state) GetFeeRates() (commonfees.Dimensions, error) { return *s.feeRate, nil } -func (s *state) SetUnitFees(uf commonfees.Dimensions) { - unitFees := uf - s.feeRate = &unitFees +func (s *state) SetFeeRates(uf commonfees.Dimensions) { + feeRates := uf + s.feeRate = &feeRates } func (s *state) GetLastBlockComplexity() (commonfees.Dimensions, error) { @@ -1290,15 +1290,15 @@ func (s *state) loadMetadata() error { s.SetTimestamp(timestamp) s.feeRate = new(commonfees.Dimensions) - switch unitFeesBytes, err := s.singletonDB.Get(UnitFeesKey); err { + switch feeRatesBytes, err := s.singletonDB.Get(FeeRatesKey); err { case nil: - if err := s.feeRate.FromBytes(unitFeesBytes); err != nil { + if err := s.feeRate.FromBytes(feeRatesBytes); err != nil { return err } case database.ErrNotFound: // fork introducing dynamic fees may not be active yet, - // hence we may have never stored unit fees. Load from config + // hence we may have never stored fee rates. Load from config // TODO: remove once fork is active isEActive := s.cfg.IsEActivated(timestamp) *s.feeRate = config.GetDynamicFeesConfig(isEActive).InitialFeeRate @@ -2301,12 +2301,12 @@ func (s *state) writeMetadata() error { } if s.feeRate != nil { - if err := s.singletonDB.Put(UnitFeesKey, s.feeRate.Bytes()); err != nil { - return fmt.Errorf("failed to write unit fees: %w", err) + if err := s.singletonDB.Put(FeeRatesKey, s.feeRate.Bytes()); err != nil { + return fmt.Errorf("failed to write fee rates: %w", err) } } if err := s.singletonDB.Put(LastBlkComplexityKey, s.lastBlkComplexity.Bytes()); err != nil { - return fmt.Errorf("failed to write unit fees: %w", err) + return fmt.Errorf("failed to write fee rates: %w", err) } if s.persistedCurrentSupply != s.currentSupply { if err := database.PutUInt64(s.singletonDB, CurrentSupplyKey, s.currentSupply); err != nil { diff --git a/vms/platformvm/txs/fees/calculator_test.go b/vms/platformvm/txs/fees/calculator_test.go index 046c14be02c8..2b1ad15dca77 100644 --- a/vms/platformvm/txs/fees/calculator_test.go +++ b/vms/platformvm/txs/fees/calculator_test.go @@ -26,7 +26,7 @@ import ( ) var ( - testUnitFees = fees.Dimensions{ + testFeeRates = fees.Dimensions{ 1 * units.MicroAvax, 2 * units.MicroAvax, 3 * units.MicroAvax, @@ -71,7 +71,7 @@ func TestAddAndRemoveFees(t *testing.T) { fc := &Calculator{ IsEUpgradeActive: true, - FeeManager: fees.NewManager(testUnitFees), + FeeManager: fees.NewManager(testFeeRates), ConsumedUnitsCap: testBlockMaxConsumedUnits, } @@ -924,7 +924,7 @@ func TestTxFees(t *testing.T) { IsEUpgradeActive: cfg.IsEActivated(chainTime), Config: cfg, ChainTime: chainTime, - FeeManager: fees.NewManager(testUnitFees), + FeeManager: fees.NewManager(testFeeRates), ConsumedUnitsCap: consumedUnitCaps, Credentials: sTx.Creds, } diff --git a/vms/platformvm/vm_test.go b/vms/platformvm/vm_test.go index f03a0d97239d..7afa14bb4819 100644 --- a/vms/platformvm/vm_test.go +++ b/vms/platformvm/vm_test.go @@ -372,7 +372,7 @@ func TestGenesis(t *testing.T) { require.Equal(utxo.Address, addr) - unitFees, err := vm.state.GetFeeRates() + feeRates, err := vm.state.GetFeeRates() require.NoError(err) // we use the first key to fund a subnet creation in [defaultGenesis]. @@ -380,7 +380,7 @@ func TestGenesis(t *testing.T) { var ( chainTime = vm.state.GetTimestamp() feeCfg = config.GetDynamicFeesConfig(vm.Config.IsEActivated(chainTime)) - feeMan = commonfees.NewManager(unitFees) + feeMan = commonfees.NewManager(feeRates) feeCalc = &fees.Calculator{ IsEUpgradeActive: vm.IsEActivated(chainTime), Config: &vm.Config, diff --git a/wallet/chain/p/builder_test.go b/wallet/chain/p/builder_test.go index c7ea5e6b8a57..f1922831e22c 100644 --- a/wallet/chain/p/builder_test.go +++ b/wallet/chain/p/builder_test.go @@ -55,7 +55,7 @@ var ( AddSubnetDelegatorFee: 9 * units.Avax, } - testUnitFees = commonfees.Dimensions{ + testFeeRates = commonfees.Dimensions{ 1 * units.MicroAvax, 2 * units.MicroAvax, 3 * units.MicroAvax, @@ -101,7 +101,7 @@ func TestBaseTx(t *testing.T) { { // Post E-Upgrade feeCalc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees), + FeeManager: commonfees.NewManager(testFeeRates), ConsumedUnitsCap: testBlockMaxConsumedUnits, } utx, err := builder.NewBaseTx( @@ -115,7 +115,7 @@ func TestBaseTx(t *testing.T) { fc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees), + FeeManager: commonfees.NewManager(testFeeRates), ConsumedUnitsCap: testBlockMaxConsumedUnits, Credentials: tx.Creds, } @@ -230,7 +230,7 @@ func TestAddSubnetValidatorTx(t *testing.T) { { // Post E-Upgrade feeCalc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees), + FeeManager: commonfees.NewManager(testFeeRates), ConsumedUnitsCap: testBlockMaxConsumedUnits, } utx, err := builder.NewAddSubnetValidatorTx(subnetValidator, feeCalc) @@ -244,7 +244,7 @@ func TestAddSubnetValidatorTx(t *testing.T) { Config: &config.Config{ AddSubnetValidatorFee: units.MilliAvax, }, - FeeManager: commonfees.NewManager(testUnitFees), + FeeManager: commonfees.NewManager(testFeeRates), ConsumedUnitsCap: testBlockMaxConsumedUnits, Credentials: tx.Creds, } @@ -346,7 +346,7 @@ func TestRemoveSubnetValidatorTx(t *testing.T) { { // Post E-Upgrade feeCalc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees), + FeeManager: commonfees.NewManager(testFeeRates), ConsumedUnitsCap: testBlockMaxConsumedUnits, } utx, err := builder.NewRemoveSubnetValidatorTx( @@ -361,7 +361,7 @@ func TestRemoveSubnetValidatorTx(t *testing.T) { fc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees), + FeeManager: commonfees.NewManager(testFeeRates), ConsumedUnitsCap: testBlockMaxConsumedUnits, Credentials: tx.Creds, } @@ -474,7 +474,7 @@ func TestCreateChainTx(t *testing.T) { { // Post E-Upgrade feeCalc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees), + FeeManager: commonfees.NewManager(testFeeRates), ConsumedUnitsCap: testBlockMaxConsumedUnits, } utx, err := builder.NewCreateChainTx( @@ -492,7 +492,7 @@ func TestCreateChainTx(t *testing.T) { fc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees), + FeeManager: commonfees.NewManager(testFeeRates), ConsumedUnitsCap: testBlockMaxConsumedUnits, Credentials: tx.Creds, } @@ -600,7 +600,7 @@ func TestCreateSubnetTx(t *testing.T) { { // Post E-Upgrade feeCalc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees), + FeeManager: commonfees.NewManager(testFeeRates), ConsumedUnitsCap: testBlockMaxConsumedUnits, } utx, err := builder.NewCreateSubnetTx( @@ -614,7 +614,7 @@ func TestCreateSubnetTx(t *testing.T) { fc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees), + FeeManager: commonfees.NewManager(testFeeRates), ConsumedUnitsCap: testBlockMaxConsumedUnits, Credentials: tx.Creds, } @@ -719,7 +719,7 @@ func TestTransferSubnetOwnershipTx(t *testing.T) { { // Post E-Upgrade feeCalc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees), + FeeManager: commonfees.NewManager(testFeeRates), ConsumedUnitsCap: testBlockMaxConsumedUnits, } utx, err := builder.NewTransferSubnetOwnershipTx( @@ -734,7 +734,7 @@ func TestTransferSubnetOwnershipTx(t *testing.T) { fc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees), + FeeManager: commonfees.NewManager(testFeeRates), ConsumedUnitsCap: testBlockMaxConsumedUnits, Credentials: tx.Creds, } @@ -834,7 +834,7 @@ func TestImportTx(t *testing.T) { { // Post E-Upgrade feeCalc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees), + FeeManager: commonfees.NewManager(testFeeRates), ConsumedUnitsCap: testBlockMaxConsumedUnits, } utx, err := builder.NewImportTx( @@ -849,7 +849,7 @@ func TestImportTx(t *testing.T) { fc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees), + FeeManager: commonfees.NewManager(testFeeRates), ConsumedUnitsCap: testBlockMaxConsumedUnits, Credentials: tx.Creds, } @@ -949,7 +949,7 @@ func TestExportTx(t *testing.T) { { // Post E-Upgrade feeCalc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees), + FeeManager: commonfees.NewManager(testFeeRates), ConsumedUnitsCap: testBlockMaxConsumedUnits, } utx, err := builder.NewExportTx( @@ -964,7 +964,7 @@ func TestExportTx(t *testing.T) { fc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees), + FeeManager: commonfees.NewManager(testFeeRates), ConsumedUnitsCap: testBlockMaxConsumedUnits, Credentials: tx.Creds, } @@ -1076,7 +1076,7 @@ func TestTransformSubnetTx(t *testing.T) { { // Post E-Upgrade feeCalc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees), + FeeManager: commonfees.NewManager(testFeeRates), ConsumedUnitsCap: testBlockMaxConsumedUnits, } utx, err := builder.NewTransformSubnetTx( @@ -1103,7 +1103,7 @@ func TestTransformSubnetTx(t *testing.T) { fc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees), + FeeManager: commonfees.NewManager(testFeeRates), ConsumedUnitsCap: testBlockMaxConsumedUnits, Credentials: tx.Creds, } @@ -1223,7 +1223,7 @@ func TestAddPermissionlessValidatorTx(t *testing.T) { { // Post E-Upgrade feeCalc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees), + FeeManager: commonfees.NewManager(testFeeRates), ConsumedUnitsCap: testBlockMaxConsumedUnits, } utx, err := builder.NewAddPermissionlessValidatorTx( @@ -1249,7 +1249,7 @@ func TestAddPermissionlessValidatorTx(t *testing.T) { fc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees), + FeeManager: commonfees.NewManager(testFeeRates), ConsumedUnitsCap: testBlockMaxConsumedUnits, Credentials: tx.Creds, } @@ -1363,7 +1363,7 @@ func TestAddPermissionlessDelegatorTx(t *testing.T) { { // Post E-Upgrade feeCalc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees), + FeeManager: commonfees.NewManager(testFeeRates), ConsumedUnitsCap: testBlockMaxConsumedUnits, } utx, err := builder.NewAddPermissionlessDelegatorTx( @@ -1386,7 +1386,7 @@ func TestAddPermissionlessDelegatorTx(t *testing.T) { fc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees), + FeeManager: commonfees.NewManager(testFeeRates), ConsumedUnitsCap: testBlockMaxConsumedUnits, Credentials: tx.Creds, } From 432c17b97d478d31e221301b6ff455396aef62af Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 21 Mar 2024 17:19:03 +0100 Subject: [PATCH 135/190] minor refactoring --- vms/platformvm/txs/builder/builder.go | 255 +++++--------------------- 1 file changed, 47 insertions(+), 208 deletions(-) diff --git a/vms/platformvm/txs/builder/builder.go b/vms/platformvm/txs/builder/builder.go index 4e1f095ba9a6..1cf69430ccf3 100644 --- a/vms/platformvm/txs/builder/builder.go +++ b/vms/platformvm/txs/builder/builder.go @@ -282,26 +282,12 @@ func (b *builder) NewImportTx( changeAddr ids.ShortID, memo []byte, ) (*txs.Tx, error) { - feeRates, err := b.state.GetFeeRates() + pBuilder, pSigner := b.builders(keys) + feeCalc, err := b.feeCalculator() if err != nil { return nil, err } - var ( - pBuilder, pSigner = b.builders(keys) - chainTime = b.state.GetTimestamp() - feeCfg = config.GetDynamicFeesConfig(b.cfg.IsEActivated(chainTime)) - isEUpgradeActive = b.cfg.IsEActivated(chainTime) - - feeCalc = &fees.Calculator{ - IsEUpgradeActive: isEUpgradeActive, - Config: b.cfg, - ChainTime: chainTime, - FeeManager: commonfees.NewManager(feeRates), - BlockMaxComplexity: feeCfg.BlockMaxComplexity, - } - ) - outOwner := &secp256k1fx.OutputOwners{ Locktime: 0, Threshold: 1, @@ -334,26 +320,12 @@ func (b *builder) NewExportTx( changeAddr ids.ShortID, memo []byte, ) (*txs.Tx, error) { - feeRates, err := b.state.GetFeeRates() + pBuilder, pSigner := b.builders(keys) + feeCalc, err := b.feeCalculator() if err != nil { return nil, err } - var ( - pBuilder, pSigner = b.builders(keys) - chainTime = b.state.GetTimestamp() - feeCfg = config.GetDynamicFeesConfig(b.cfg.IsEActivated(chainTime)) - isEUpgradeActive = b.cfg.IsEActivated(chainTime) - - feeCalc = &fees.Calculator{ - IsEUpgradeActive: isEUpgradeActive, - Config: b.cfg, - ChainTime: chainTime, - FeeManager: commonfees.NewManager(feeRates), - BlockMaxComplexity: feeCfg.BlockMaxComplexity, - } - ) - outputs := []*avax.TransferableOutput{{ Asset: avax.Asset{ID: b.ctx.AVAXAssetID}, Out: &secp256k1fx.TransferOutput{ @@ -393,26 +365,12 @@ func (b *builder) NewCreateChainTx( changeAddr ids.ShortID, memo []byte, ) (*txs.Tx, error) { - feeRates, err := b.state.GetFeeRates() + pBuilder, pSigner := b.builders(keys) + feeCalc, err := b.feeCalculator() if err != nil { return nil, err } - var ( - pBuilder, pSigner = b.builders(keys) - chainTime = b.state.GetTimestamp() - feeCfg = config.GetDynamicFeesConfig(b.cfg.IsEActivated(chainTime)) - isEUpgradeActive = b.cfg.IsEActivated(chainTime) - - feeCalc = &fees.Calculator{ - IsEUpgradeActive: isEUpgradeActive, - Config: b.cfg, - ChainTime: chainTime, - FeeManager: commonfees.NewManager(feeRates), - BlockMaxComplexity: feeCfg.BlockMaxComplexity, - } - ) - utx, err := pBuilder.NewCreateChainTx( subnetID, genesisData, @@ -440,26 +398,12 @@ func (b *builder) NewCreateSubnetTx( changeAddr ids.ShortID, memo []byte, ) (*txs.Tx, error) { - feeRates, err := b.state.GetFeeRates() + pBuilder, pSigner := b.builders(keys) + feeCalc, err := b.feeCalculator() if err != nil { return nil, err } - var ( - pBuilder, pSigner = b.builders(keys) - chainTime = b.state.GetTimestamp() - feeCfg = config.GetDynamicFeesConfig(b.cfg.IsEActivated(chainTime)) - isEUpgradeActive = b.cfg.IsEActivated(chainTime) - - feeCalc = &fees.Calculator{ - IsEUpgradeActive: isEUpgradeActive, - Config: b.cfg, - ChainTime: chainTime, - FeeManager: commonfees.NewManager(feeRates), - BlockMaxComplexity: feeCfg.BlockMaxComplexity, - } - ) - utils.Sort(ownerAddrs) // sort control addresses subnetOwner := &secp256k1fx.OutputOwners{ Threshold: threshold, @@ -501,26 +445,12 @@ func (b *builder) NewTransformSubnetTx( changeAddr ids.ShortID, memo []byte, ) (*txs.Tx, error) { - feeRates, err := b.state.GetFeeRates() + pBuilder, pSigner := b.builders(keys) + feeCalc, err := b.feeCalculator() if err != nil { return nil, err } - var ( - pBuilder, pSigner = b.builders(keys) - chainTime = b.state.GetTimestamp() - feeCfg = config.GetDynamicFeesConfig(b.cfg.IsEActivated(chainTime)) - isEUpgradeActive = b.cfg.IsEActivated(chainTime) - - feeCalc = &fees.Calculator{ - IsEUpgradeActive: isEUpgradeActive, - Config: b.cfg, - ChainTime: chainTime, - FeeManager: commonfees.NewManager(feeRates), - BlockMaxComplexity: feeCfg.BlockMaxComplexity, - } - ) - utx, err := pBuilder.NewTransformSubnetTx( subnetID, assetID, @@ -561,26 +491,12 @@ func (b *builder) NewAddValidatorTx( changeAddr ids.ShortID, memo []byte, ) (*txs.Tx, error) { - feeRates, err := b.state.GetFeeRates() + pBuilder, pSigner := b.builders(keys) + feeCalc, err := b.feeCalculator() if err != nil { return nil, err } - var ( - pBuilder, pSigner = b.builders(keys) - chainTime = b.state.GetTimestamp() - feeCfg = config.GetDynamicFeesConfig(b.cfg.IsEActivated(chainTime)) - isEUpgradeActive = b.cfg.IsEActivated(chainTime) - - feeCalc = &fees.Calculator{ - IsEUpgradeActive: isEUpgradeActive, - Config: b.cfg, - ChainTime: chainTime, - FeeManager: commonfees.NewManager(feeRates), - BlockMaxComplexity: feeCfg.BlockMaxComplexity, - } - ) - vdr := &txs.Validator{ NodeID: nodeID, Start: startTime, @@ -623,26 +539,12 @@ func (b *builder) NewAddPermissionlessValidatorTx( changeAddr ids.ShortID, memo []byte, ) (*txs.Tx, error) { - feeRates, err := b.state.GetFeeRates() + pBuilder, pSigner := b.builders(keys) + feeCalc, err := b.feeCalculator() if err != nil { return nil, err } - var ( - pBuilder, pSigner = b.builders(keys) - chainTime = b.state.GetTimestamp() - feeCfg = config.GetDynamicFeesConfig(b.cfg.IsEActivated(chainTime)) - isEUpgradeActive = b.cfg.IsEActivated(chainTime) - - feeCalc = &fees.Calculator{ - IsEUpgradeActive: isEUpgradeActive, - Config: b.cfg, - ChainTime: chainTime, - FeeManager: commonfees.NewManager(feeRates), - BlockMaxComplexity: feeCfg.BlockMaxComplexity, - } - ) - vdr := &txs.SubnetValidator{ Validator: txs.Validator{ NodeID: nodeID, @@ -689,26 +591,12 @@ func (b *builder) NewAddDelegatorTx( changeAddr ids.ShortID, memo []byte, ) (*txs.Tx, error) { - feeRates, err := b.state.GetFeeRates() + pBuilder, pSigner := b.builders(keys) + feeCalc, err := b.feeCalculator() if err != nil { return nil, err } - var ( - pBuilder, pSigner = b.builders(keys) - chainTime = b.state.GetTimestamp() - feeCfg = config.GetDynamicFeesConfig(b.cfg.IsEActivated(chainTime)) - isEUpgradeActive = b.cfg.IsEActivated(chainTime) - - feeCalc = &fees.Calculator{ - IsEUpgradeActive: isEUpgradeActive, - Config: b.cfg, - ChainTime: chainTime, - FeeManager: commonfees.NewManager(feeRates), - BlockMaxComplexity: feeCfg.BlockMaxComplexity, - } - ) - vdr := &txs.Validator{ NodeID: nodeID, Start: startTime, @@ -748,26 +636,12 @@ func (b *builder) NewAddPermissionlessDelegatorTx( changeAddr ids.ShortID, memo []byte, ) (*txs.Tx, error) { - feeRates, err := b.state.GetFeeRates() + pBuilder, pSigner := b.builders(keys) + feeCalc, err := b.feeCalculator() if err != nil { return nil, err } - var ( - pBuilder, pSigner = b.builders(keys) - chainTime = b.state.GetTimestamp() - feeCfg = config.GetDynamicFeesConfig(b.cfg.IsEActivated(chainTime)) - isEUpgradeActive = b.cfg.IsEActivated(chainTime) - - feeCalc = &fees.Calculator{ - IsEUpgradeActive: isEUpgradeActive, - Config: b.cfg, - ChainTime: chainTime, - FeeManager: commonfees.NewManager(feeRates), - BlockMaxComplexity: feeCfg.BlockMaxComplexity, - } - ) - vdr := &txs.SubnetValidator{ Validator: txs.Validator{ NodeID: nodeID, @@ -811,26 +685,12 @@ func (b *builder) NewAddSubnetValidatorTx( changeAddr ids.ShortID, memo []byte, ) (*txs.Tx, error) { - feeRates, err := b.state.GetFeeRates() + pBuilder, pSigner := b.builders(keys) + feeCalc, err := b.feeCalculator() if err != nil { return nil, err } - var ( - pBuilder, pSigner = b.builders(keys) - chainTime = b.state.GetTimestamp() - feeCfg = config.GetDynamicFeesConfig(b.cfg.IsEActivated(chainTime)) - isEUpgradeActive = b.cfg.IsEActivated(chainTime) - - feeCalc = &fees.Calculator{ - IsEUpgradeActive: isEUpgradeActive, - Config: b.cfg, - ChainTime: chainTime, - FeeManager: commonfees.NewManager(feeRates), - BlockMaxComplexity: feeCfg.BlockMaxComplexity, - } - ) - vdr := &txs.SubnetValidator{ Validator: txs.Validator{ NodeID: nodeID, @@ -864,26 +724,12 @@ func (b *builder) NewRemoveSubnetValidatorTx( changeAddr ids.ShortID, memo []byte, ) (*txs.Tx, error) { - feeRates, err := b.state.GetFeeRates() + pBuilder, pSigner := b.builders(keys) + feeCalc, err := b.feeCalculator() if err != nil { return nil, err } - var ( - pBuilder, pSigner = b.builders(keys) - chainTime = b.state.GetTimestamp() - feeCfg = config.GetDynamicFeesConfig(b.cfg.IsEActivated(chainTime)) - isEUpgradeActive = b.cfg.IsEActivated(chainTime) - - feeCalc = &fees.Calculator{ - IsEUpgradeActive: isEUpgradeActive, - Config: b.cfg, - ChainTime: chainTime, - FeeManager: commonfees.NewManager(feeRates), - BlockMaxComplexity: feeCfg.BlockMaxComplexity, - } - ) - utx, err := pBuilder.NewRemoveSubnetValidatorTx( nodeID, subnetID, @@ -909,26 +755,12 @@ func (b *builder) NewTransferSubnetOwnershipTx( changeAddr ids.ShortID, memo []byte, ) (*txs.Tx, error) { - feeRates, err := b.state.GetFeeRates() + pBuilder, pSigner := b.builders(keys) + feeCalc, err := b.feeCalculator() if err != nil { return nil, err } - var ( - pBuilder, pSigner = b.builders(keys) - chainTime = b.state.GetTimestamp() - feeCfg = config.GetDynamicFeesConfig(b.cfg.IsEActivated(chainTime)) - isEUpgradeActive = b.cfg.IsEActivated(chainTime) - - feeCalc = &fees.Calculator{ - IsEUpgradeActive: isEUpgradeActive, - Config: b.cfg, - ChainTime: chainTime, - FeeManager: commonfees.NewManager(feeRates), - BlockMaxComplexity: feeCfg.BlockMaxComplexity, - } - ) - utils.Sort(ownerAddrs) // sort control addresses newOwner := &secp256k1fx.OutputOwners{ Threshold: threshold, @@ -959,26 +791,12 @@ func (b *builder) NewBaseTx( changeAddr ids.ShortID, memo []byte, ) (*txs.Tx, error) { - feeRates, err := b.state.GetFeeRates() + pBuilder, pSigner := b.builders(keys) + feeCalc, err := b.feeCalculator() if err != nil { return nil, err } - var ( - pBuilder, pSigner = b.builders(keys) - chainTime = b.state.GetTimestamp() - feeCfg = config.GetDynamicFeesConfig(b.cfg.IsEActivated(chainTime)) - isEUpgradeActive = b.cfg.IsEActivated(chainTime) - - feeCalc = &fees.Calculator{ - IsEUpgradeActive: isEUpgradeActive, - Config: b.cfg, - ChainTime: chainTime, - FeeManager: commonfees.NewManager(feeRates), - BlockMaxComplexity: feeCfg.BlockMaxComplexity, - } - ) - out := &avax.TransferableOutput{ Asset: avax.Asset{ID: b.ctx.AVAXAssetID}, Out: &secp256k1fx.TransferOutput{ @@ -1016,6 +834,27 @@ func (b *builder) builders(keys []*secp256k1.PrivateKey) (walletbuilder.Builder, return builder, signer } +func (b *builder) feeCalculator() (*fees.Calculator, error) { + feeRates, err := b.state.GetFeeRates() + if err != nil { + return nil, err + } + + var ( + chainTime = b.state.GetTimestamp() + feeCfg = config.GetDynamicFeesConfig(b.cfg.IsEActivated(chainTime)) + isEUpgradeActive = b.cfg.IsEActivated(chainTime) + ) + + return &fees.Calculator{ + IsEUpgradeActive: isEUpgradeActive, + Config: b.cfg, + ChainTime: chainTime, + FeeManager: commonfees.NewManager(feeRates), + BlockMaxComplexity: feeCfg.BlockMaxComplexity, + }, nil +} + func options(changeAddr ids.ShortID, memo []byte) []common.Option { return common.UnionOptions( []common.Option{common.WithChangeOwner(&secp256k1fx.OutputOwners{ From faaa96ef262712372c42584f8909ce5fa525f862 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Wed, 27 Mar 2024 10:55:11 +0100 Subject: [PATCH 136/190] fixed merge --- vms/platformvm/state/state.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vms/platformvm/state/state.go b/vms/platformvm/state/state.go index 8358fee4039b..f1ce086715dd 100644 --- a/vms/platformvm/state/state.go +++ b/vms/platformvm/state/state.go @@ -88,7 +88,7 @@ var ( FeeRatesKey = []byte("fee rates") LastBlkComplexityKey = []byte("last complexity") InitializedKey = []byte("initialized") - BlocksReindexedKey = []byte("blocks reindexed") + BlocksReindexedKey = []byte("blocks reindexed") ) // Chain collects all methods to manage the state of the chain for block From 6a0806df52be5cf4159db0fab12c7435d5cee1c4 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Fri, 29 Mar 2024 16:30:36 +0100 Subject: [PATCH 137/190] fixed txBuilder dynamic fees time --- vms/platformvm/block/builder/builder.go | 19 ++--- vms/platformvm/block/builder/helpers_test.go | 1 + vms/platformvm/block/executor/helpers_test.go | 2 + vms/platformvm/block/executor/manager.go | 23 +++--- .../block/executor/proposal_block_test.go | 3 +- vms/platformvm/block/executor/verifier.go | 30 ++++---- .../block/executor/verifier_test.go | 2 - vms/platformvm/service.go | 23 ++---- vms/platformvm/state/stakers_helpers.go | 70 +++++++++++++++++++ .../txs/executor/create_chain_test.go | 10 ++- vms/platformvm/txs/executor/helpers_test.go | 14 ++-- .../txs/executor/proposal_tx_executor.go | 2 +- .../staker_tx_verification_helpers.go | 34 --------- vms/platformvm/txs/executor/state_changes.go | 25 ------- vms/platformvm/txs/fees/helpers.go | 33 +++++++++ vms/platformvm/txs/txstest/builder.go | 28 +++++--- vms/platformvm/validator_set_property_test.go | 3 + vms/platformvm/vm_regression_test.go | 1 + vms/platformvm/vm_test.go | 1 + wallet/chain/p/wallet.go | 32 ++++----- 20 files changed, 195 insertions(+), 161 deletions(-) create mode 100644 vms/platformvm/state/stakers_helpers.go diff --git a/vms/platformvm/block/builder/builder.go b/vms/platformvm/block/builder/builder.go index fe2534a5f1a9..4df119de8539 100644 --- a/vms/platformvm/block/builder/builder.go +++ b/vms/platformvm/block/builder/builder.go @@ -23,6 +23,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/fees" "github.com/ava-labs/avalanchego/vms/platformvm/txs/mempool" commonfees "github.com/ava-labs/avalanchego/vms/components/fees" @@ -173,7 +174,7 @@ func (b *builder) durationToSleep() (time.Duration, error) { return 0, fmt.Errorf("%w: %s", errMissingPreferredState, preferredID) } - nextStakerChangeTime, err := txexecutor.GetNextStakerChangeTime(preferredState) + nextStakerChangeTime, err := state.GetNextStakerChangeTime(preferredState) if err != nil { return 0, fmt.Errorf("%w of %s: %w", errCalculatingNextStakerTime, preferredID, err) } @@ -218,7 +219,7 @@ func (b *builder) BuildBlock(context.Context) (snowman.Block, error) { return nil, fmt.Errorf("%w: %s", state.ErrMissingParentState, preferredID) } - timestamp, timeWasCapped, err := txexecutor.NextBlockTime(preferredState, b.txExecutorBackend.Clk) + timestamp, timeWasCapped, err := state.NextBlockTime(preferredState, b.txExecutorBackend.Clk) if err != nil { return nil, fmt.Errorf("could not calculate next staker change time: %w", err) } @@ -340,10 +341,6 @@ func packBlockTxs( if err != nil { return nil, err } - parentBlkComplexity, err := stateDiff.GetLastBlockComplexity() - if err != nil { - return nil, err - } var ( isEActivated = backend.Config.IsEActivated(timestamp) @@ -355,13 +352,9 @@ func packBlockTxs( feeMan := commonfees.NewManager(feeRates) if isEActivated { - if err := feeMan.UpdateFeeRates( - feeCfg, - parentBlkComplexity, - parentBlkTime.Unix(), - timestamp.Unix(), - ); err != nil { - return nil, fmt.Errorf("failed updating fee rates, %w", err) + feeMan, err = fees.UpdatedFeeManager(stateDiff, backend.Config, parentBlkTime, timestamp) + 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 7b3d929be1f7..8398c3121be0 100644 --- a/vms/platformvm/block/builder/helpers_test.go +++ b/vms/platformvm/block/builder/helpers_test.go @@ -155,6 +155,7 @@ func newEnvironment(t *testing.T, f fork) *environment { //nolint:unparam res.txBuilder = txstest.NewBuilder( res.ctx, res.config, + res.clk, res.state, ) diff --git a/vms/platformvm/block/executor/helpers_test.go b/vms/platformvm/block/executor/helpers_test.go index c7872b052429..3f53711ca650 100644 --- a/vms/platformvm/block/executor/helpers_test.go +++ b/vms/platformvm/block/executor/helpers_test.go @@ -160,6 +160,7 @@ func newEnvironment(t *testing.T, ctrl *gomock.Controller, f fork) *environment res.txBuilder = txstest.NewBuilder( res.ctx, res.config, + res.clk, res.state, ) } else { @@ -171,6 +172,7 @@ func newEnvironment(t *testing.T, ctrl *gomock.Controller, f fork) *environment res.txBuilder = txstest.NewBuilder( res.ctx, res.config, + res.clk, res.mockedState, ) diff --git a/vms/platformvm/block/executor/manager.go b/vms/platformvm/block/executor/manager.go index e6a76e001672..ae841d0e5e1e 100644 --- a/vms/platformvm/block/executor/manager.go +++ b/vms/platformvm/block/executor/manager.go @@ -5,20 +5,21 @@ package executor import ( "errors" - "fmt" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/snow/consensus/snowman" "github.com/ava-labs/avalanchego/utils/set" - "github.com/ava-labs/avalanchego/vms/components/fees" "github.com/ava-labs/avalanchego/vms/platformvm/block" "github.com/ava-labs/avalanchego/vms/platformvm/config" "github.com/ava-labs/avalanchego/vms/platformvm/metrics" "github.com/ava-labs/avalanchego/vms/platformvm/state" "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/fees" "github.com/ava-labs/avalanchego/vms/platformvm/txs/mempool" "github.com/ava-labs/avalanchego/vms/platformvm/validators" + + commonfees "github.com/ava-labs/avalanchego/vms/components/fees" ) var ( @@ -138,7 +139,7 @@ func (m *manager) VerifyTx(tx *txs.Tx) error { // retrieve parent block time before moving time forward parentBlkTime := stateDiff.GetTimestamp() - nextBlkTime, _, err := executor.NextBlockTime(stateDiff, m.txExecutorBackend.Clk) + nextBlkTime, _, err := state.NextBlockTime(stateDiff, m.txExecutorBackend.Clk) if err != nil { return err } @@ -152,25 +153,17 @@ func (m *manager) VerifyTx(tx *txs.Tx) error { if err != nil { return err } - parentBlkComplexitty, err := stateDiff.GetLastBlockComplexity() - if err != nil { - return err - } var ( isEActive = m.txExecutorBackend.Config.IsEActivated(nextBlkTime) feesCfg = config.GetDynamicFeesConfig(isEActive) ) - feeManager := fees.NewManager(feeRates) + feeManager := commonfees.NewManager(feeRates) if isEActive { - if err := feeManager.UpdateFeeRates( - feesCfg, - parentBlkComplexitty, - parentBlkTime.Unix(), - nextBlkTime.Unix(), - ); err != nil { - return fmt.Errorf("failed updating fee rates, %w", err) + feeManager, err = fees.UpdatedFeeManager(stateDiff, m.txExecutorBackend.Config, parentBlkTime, nextBlkTime) + 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 427a0b83b685..241342f9d11d 100644 --- a/vms/platformvm/block/executor/proposal_block_test.go +++ b/vms/platformvm/block/executor/proposal_block_test.go @@ -161,7 +161,6 @@ func TestBanffProposalBlockTimeVerification(t *testing.T) { onParentAccept := state.NewMockDiff(ctrl) onParentAccept.EXPECT().GetTimestamp().Return(parentTime).AnyTimes() onParentAccept.EXPECT().GetFeeRates().Return(commonfees.Empty, nil).Times(2) - onParentAccept.EXPECT().GetLastBlockComplexity().Return(commonfees.Empty, nil).Times(2) onParentAccept.EXPECT().GetCurrentSupply(constants.PrimaryNetworkID).Return(uint64(1000), nil).AnyTimes() env.blkManager.(*manager).blkIDToState[parentID] = &blockState{ @@ -1421,7 +1420,7 @@ func TestAddValidatorProposalBlock(t *testing.T) { // Advance time until next staker change time is [validatorEndTime] for { - nextStakerChangeTime, err := executor.GetNextStakerChangeTime(env.state) + nextStakerChangeTime, err := state.GetNextStakerChangeTime(env.state) require.NoError(err) if nextStakerChangeTime.Equal(validatorEndTime) { break diff --git a/vms/platformvm/block/executor/verifier.go b/vms/platformvm/block/executor/verifier.go index 539703e7d689..152ce04b9e3f 100644 --- a/vms/platformvm/block/executor/verifier.go +++ b/vms/platformvm/block/executor/verifier.go @@ -11,13 +11,15 @@ import ( "github.com/ava-labs/avalanchego/chains/atomic" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils/set" - "github.com/ava-labs/avalanchego/vms/components/fees" "github.com/ava-labs/avalanchego/vms/platformvm/block" "github.com/ava-labs/avalanchego/vms/platformvm/config" "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/fees" + + commonfees "github.com/ava-labs/avalanchego/vms/components/fees" ) var ( @@ -167,7 +169,7 @@ func (v *verifier) ApricotProposalBlock(b *block.ApricotProposalBlock) error { return err } - return v.proposalBlock(b, nil, onCommitState, onAbortState, fees.Empty, nil, nil, nil) + return v.proposalBlock(b, nil, onCommitState, onAbortState, commonfees.Empty, nil, nil, nil) } func (v *verifier) ApricotStandardBlock(b *block.ApricotStandardBlock) error { @@ -232,7 +234,7 @@ func (v *verifier) ApricotAtomicBlock(b *block.ApricotAtomicBlock) error { inputs: atomicExecutor.Inputs, timestamp: atomicExecutor.OnAccept.GetTimestamp(), - blockComplexity: fees.Empty, + blockComplexity: commonfees.Empty, atomicRequests: atomicExecutor.AtomicRequests, } return nil @@ -283,7 +285,7 @@ func (v *verifier) banffNonOptionBlock(b block.BanffBlock) error { ) } - nextStakerChangeTime, err := executor.GetNextStakerChangeTime(parentState) + nextStakerChangeTime, err := state.GetNextStakerChangeTime(parentState) if err != nil { return fmt.Errorf("could not verify block timestamp: %w", err) } @@ -379,7 +381,7 @@ func (v *verifier) proposalBlock( onDecisionState state.Diff, onCommitState state.Diff, onAbortState state.Diff, - blockComplexity fees.Dimensions, + blockComplexity commonfees.Dimensions, inputs set.Set[ids.ID], atomicRequests map[ids.ID]*atomic.Requests, onAcceptFunc func(), @@ -467,7 +469,7 @@ func (v *verifier) processStandardTxs( parentBlkTime, blkTimestamp time.Time, ) ( set.Set[ids.ID], - *fees.Manager, + *commonfees.Manager, map[ids.ID]*atomic.Requests, func(), error, @@ -476,10 +478,6 @@ func (v *verifier) processStandardTxs( if err != nil { return nil, nil, nil, nil, err } - parentBlkComplexity, err := state.GetLastBlockComplexity() - if err != nil { - return nil, nil, nil, nil, err - } var ( isEActive = v.txExecutorBackend.Config.IsEActivated(parentBlkTime) @@ -491,15 +489,11 @@ func (v *verifier) processStandardTxs( atomicRequests = make(map[ids.ID]*atomic.Requests) ) - feeMan := fees.NewManager(feeRates) + feeMan := commonfees.NewManager(feeRates) if isEActive { - if err := feeMan.UpdateFeeRates( - feesCfg, - parentBlkComplexity, - parentBlkTime.Unix(), - blkTimestamp.Unix(), - ); err != nil { - return nil, nil, nil, nil, fmt.Errorf("failed updating fee rates, %w", err) + feeMan, err = fees.UpdatedFeeManager(state, v.txExecutorBackend.Config, parentBlkTime, blkTimestamp) + if err != nil { + return nil, nil, nil, nil, err } } diff --git a/vms/platformvm/block/executor/verifier_test.go b/vms/platformvm/block/executor/verifier_test.go index 9878d009f7d5..2aa884c831cd 100644 --- a/vms/platformvm/block/executor/verifier_test.go +++ b/vms/platformvm/block/executor/verifier_test.go @@ -290,7 +290,6 @@ func TestVerifierVisitStandardBlock(t *testing.T) { timestamp := time.Now() parentState.EXPECT().GetTimestamp().Return(timestamp).Times(1) parentState.EXPECT().GetFeeRates().Return(commonfees.Empty, nil) - parentState.EXPECT().GetLastBlockComplexity().Return(commonfees.Empty, nil) parentStatelessBlk.EXPECT().Height().Return(uint64(1)).Times(1) mempool.EXPECT().Remove(apricotBlk.Txs()).Times(1) @@ -774,7 +773,6 @@ func TestVerifierVisitStandardBlockWithDuplicateInputs(t *testing.T) { parentStatelessBlk.EXPECT().Height().Return(uint64(1)).Times(1) parentState.EXPECT().GetTimestamp().Return(timestamp).Times(1) parentState.EXPECT().GetFeeRates().Return(commonfees.Empty, nil) - parentState.EXPECT().GetLastBlockComplexity().Return(commonfees.Empty, nil) parentStatelessBlk.EXPECT().Parent().Return(grandParentID).Times(1) diff --git a/vms/platformvm/service.go b/vms/platformvm/service.go index 0dfa8dc6ed5b..8c64664c89d8 100644 --- a/vms/platformvm/service.go +++ b/vms/platformvm/service.go @@ -29,7 +29,6 @@ import ( "github.com/ava-labs/avalanchego/utils/set" "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/components/keystore" - "github.com/ava-labs/avalanchego/vms/platformvm/config" "github.com/ava-labs/avalanchego/vms/platformvm/fx" "github.com/ava-labs/avalanchego/vms/platformvm/reward" "github.com/ava-labs/avalanchego/vms/platformvm/signer" @@ -37,7 +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/executor" + "github.com/ava-labs/avalanchego/vms/platformvm/txs/fees" "github.com/ava-labs/avalanchego/vms/secp256k1fx" avajson "github.com/ava-labs/avalanchego/utils/json" @@ -1853,7 +1852,7 @@ func (s *Service) GetFeeRates(_ *http.Request, _ *struct{}, reply *GetFeeRatesRe } reply.CurrentFeeRates = currentFeeRate - nextTimestamp, _, err := executor.NextBlockTime(onAccept, &s.vm.clock) + nextTimestamp, _, err := state.NextBlockTime(onAccept, &s.vm.clock) if err != nil { return fmt.Errorf("could not calculate next staker change time: %w", err) } @@ -1866,23 +1865,13 @@ func (s *Service) GetFeeRates(_ *http.Request, _ *struct{}, reply *GetFeeRatesRe var ( currentTimestamp = onAccept.GetTimestamp() - feesCfg = config.GetDynamicFeesConfig(isEActivated) + feeManager = commonfees.NewManager(currentFeeRate) ) - parentBlkComplexity, err := onAccept.GetLastBlockComplexity() - if err != nil { - return err - } - - feeManager := commonfees.NewManager(currentFeeRate) if isEActivated { - if err := feeManager.UpdateFeeRates( - feesCfg, - parentBlkComplexity, - currentTimestamp.Unix(), - nextTimestamp.Unix(), - ); err != nil { - return fmt.Errorf("failed updating fee rates, %w", err) + feeManager, err = fees.UpdatedFeeManager(onAccept, &s.vm.Config, currentTimestamp, nextTimestamp) + if err != nil { + return err } } reply.NextFeeRates = feeManager.GetFeeRates() diff --git a/vms/platformvm/state/stakers_helpers.go b/vms/platformvm/state/stakers_helpers.go new file mode 100644 index 000000000000..036eb168d73d --- /dev/null +++ b/vms/platformvm/state/stakers_helpers.go @@ -0,0 +1,70 @@ +// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package state + +import ( + "fmt" + "time" + + "github.com/ava-labs/avalanchego/database" + "github.com/ava-labs/avalanchego/utils/timer/mockable" +) + +func NextBlockTime(state Chain, clk *mockable.Clock) (time.Time, bool, error) { + var ( + timestamp = clk.Time() + parentTime = state.GetTimestamp() + ) + if parentTime.After(timestamp) { + timestamp = parentTime + } + // [timestamp] = max(now, parentTime) + + nextStakerChangeTime, err := GetNextStakerChangeTime(state) + if err != nil { + return time.Time{}, false, fmt.Errorf("failed getting next staker change time: %w", err) + } + + // timeWasCapped means that [timestamp] was reduced to [nextStakerChangeTime] + timeWasCapped := !timestamp.Before(nextStakerChangeTime) + if timeWasCapped { + timestamp = nextStakerChangeTime + } + // [timestamp] = min(max(now, parentTime), nextStakerChangeTime) + return timestamp, timeWasCapped, nil +} + +// GetNextStakerChangeTime returns the next time a staker will be either added +// or removed to/from the current validator set. +func GetNextStakerChangeTime(state Chain) (time.Time, error) { + currentStakerIterator, err := state.GetCurrentStakerIterator() + if err != nil { + return time.Time{}, err + } + defer currentStakerIterator.Release() + + pendingStakerIterator, err := state.GetPendingStakerIterator() + if err != nil { + return time.Time{}, err + } + defer pendingStakerIterator.Release() + + hasCurrentStaker := currentStakerIterator.Next() + hasPendingStaker := pendingStakerIterator.Next() + switch { + case hasCurrentStaker && hasPendingStaker: + nextCurrentTime := currentStakerIterator.Value().NextTime + nextPendingTime := pendingStakerIterator.Value().NextTime + if nextCurrentTime.Before(nextPendingTime) { + return nextCurrentTime, nil + } + return nextPendingTime, nil + case hasCurrentStaker: + return currentStakerIterator.Value().NextTime, nil + case hasPendingStaker: + return pendingStakerIterator.Value().NextTime, nil + default: + return time.Time{}, database.ErrNotFound + } +} diff --git a/vms/platformvm/txs/executor/create_chain_test.go b/vms/platformvm/txs/executor/create_chain_test.go index fc97f0cc6850..5e4337b7a45d 100644 --- a/vms/platformvm/txs/executor/create_chain_test.go +++ b/vms/platformvm/txs/executor/create_chain_test.go @@ -167,14 +167,18 @@ func TestCreateChainTxValid(t *testing.T) { stateDiff, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeRates, err := env.state.GetFeeRates() + currentTime := stateDiff.GetTimestamp() + nextBlkTime, _, err := state.NextBlockTime(stateDiff, env.clk) require.NoError(err) - currentTime := stateDiff.GetTimestamp() feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(currentTime)) + + feeMan, err := fees.UpdatedFeeManager(stateDiff, env.config, currentTime, nextBlkTime) + require.NoError(err) + executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(feeRates), + BlkFeeManager: feeMan, BlockMaxComplexity: feeCfg.BlockMaxComplexity, State: stateDiff, Tx: tx, diff --git a/vms/platformvm/txs/executor/helpers_test.go b/vms/platformvm/txs/executor/helpers_test.go index 756fd0362217..8c0a72efb492 100644 --- a/vms/platformvm/txs/executor/helpers_test.go +++ b/vms/platformvm/txs/executor/helpers_test.go @@ -33,7 +33,6 @@ 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/fees" "github.com/ava-labs/avalanchego/vms/platformvm/api" "github.com/ava-labs/avalanchego/vms/platformvm/config" "github.com/ava-labs/avalanchego/vms/platformvm/fx" @@ -42,6 +41,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/fees" "github.com/ava-labs/avalanchego/vms/platformvm/txs/txstest" "github.com/ava-labs/avalanchego/vms/platformvm/utxo" "github.com/ava-labs/avalanchego/vms/secp256k1fx" @@ -146,6 +146,7 @@ func newEnvironment(t *testing.T, f fork) *environment { txBuilder := txstest.NewBuilder( ctx, config, + clk, baseState, ) @@ -235,14 +236,17 @@ func addSubnet( stateDiff, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeRates, err := env.state.GetFeeRates() + currentChainTime := env.state.GetTimestamp() + nextChainTime, _, err := state.NextBlockTime(stateDiff, env.clk) require.NoError(err) - chainTime := env.state.GetTimestamp() - feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) + feeManager, err := fees.UpdatedFeeManager(stateDiff, env.config, currentChainTime, nextChainTime) + require.NoError(err) + + feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(currentChainTime)) executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(feeRates), + BlkFeeManager: feeManager, BlockMaxComplexity: feeCfg.BlockMaxComplexity, State: stateDiff, Tx: testSubnet1, diff --git a/vms/platformvm/txs/executor/proposal_tx_executor.go b/vms/platformvm/txs/executor/proposal_tx_executor.go index 0e3faf539013..5bfed49b8b26 100644 --- a/vms/platformvm/txs/executor/proposal_tx_executor.go +++ b/vms/platformvm/txs/executor/proposal_tx_executor.go @@ -274,7 +274,7 @@ func (e *ProposalTxExecutor) AdvanceTimeTx(tx *txs.AdvanceTimeTx) error { // Only allow timestamp to move forward as far as the time of next staker // set change time - nextStakerChangeTime, err := GetNextStakerChangeTime(e.OnCommitState) + nextStakerChangeTime, err := state.GetNextStakerChangeTime(e.OnCommitState) if err != nil { return err } diff --git a/vms/platformvm/txs/executor/staker_tx_verification_helpers.go b/vms/platformvm/txs/executor/staker_tx_verification_helpers.go index 3a74cea28696..eb18c6609299 100644 --- a/vms/platformvm/txs/executor/staker_tx_verification_helpers.go +++ b/vms/platformvm/txs/executor/staker_tx_verification_helpers.go @@ -94,40 +94,6 @@ func getDelegatorRules( }, nil } -// GetNextStakerChangeTime returns the next time a staker will be either added -// or removed to/from the current validator set. -func GetNextStakerChangeTime(state state.Chain) (time.Time, error) { - currentStakerIterator, err := state.GetCurrentStakerIterator() - if err != nil { - return time.Time{}, err - } - defer currentStakerIterator.Release() - - pendingStakerIterator, err := state.GetPendingStakerIterator() - if err != nil { - return time.Time{}, err - } - defer pendingStakerIterator.Release() - - hasCurrentStaker := currentStakerIterator.Next() - hasPendingStaker := pendingStakerIterator.Next() - switch { - case hasCurrentStaker && hasPendingStaker: - nextCurrentTime := currentStakerIterator.Value().NextTime - nextPendingTime := pendingStakerIterator.Value().NextTime - if nextCurrentTime.Before(nextPendingTime) { - return nextCurrentTime, nil - } - return nextPendingTime, nil - case hasCurrentStaker: - return currentStakerIterator.Value().NextTime, nil - case hasPendingStaker: - return pendingStakerIterator.Value().NextTime, nil - default: - return time.Time{}, database.ErrNotFound - } -} - // GetValidator returns information about the given validator, which may be a // current validator or pending validator. func GetValidator(state state.Chain, subnetID ids.ID, nodeID ids.NodeID) (*state.Staker, error) { diff --git a/vms/platformvm/txs/executor/state_changes.go b/vms/platformvm/txs/executor/state_changes.go index 36981b095e8c..3086358304a3 100644 --- a/vms/platformvm/txs/executor/state_changes.go +++ b/vms/platformvm/txs/executor/state_changes.go @@ -10,7 +10,6 @@ import ( "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils/constants" - "github.com/ava-labs/avalanchego/utils/timer/mockable" "github.com/ava-labs/avalanchego/vms/platformvm/reward" "github.com/ava-labs/avalanchego/vms/platformvm/state" "github.com/ava-labs/avalanchego/vms/platformvm/txs" @@ -58,30 +57,6 @@ func VerifyNewChainTime( return nil } -func NextBlockTime(state state.Chain, clk *mockable.Clock) (time.Time, bool, error) { - var ( - timestamp = clk.Time() - parentTime = state.GetTimestamp() - ) - if parentTime.After(timestamp) { - timestamp = parentTime - } - // [timestamp] = max(now, parentTime) - - nextStakerChangeTime, err := GetNextStakerChangeTime(state) - if err != nil { - return time.Time{}, false, fmt.Errorf("failed getting next staker change time: %w", err) - } - - // timeWasCapped means that [timestamp] was reduced to [nextStakerChangeTime] - timeWasCapped := !timestamp.Before(nextStakerChangeTime) - if timeWasCapped { - timestamp = nextStakerChangeTime - } - // [timestamp] = min(max(now, parentTime), nextStakerChangeTime) - return timestamp, timeWasCapped, nil -} - // AdvanceTimeTo applies all state changes to [parentState] resulting from // advancing the chain time to [newChainTime]. // Returns true iff the validator set changed. diff --git a/vms/platformvm/txs/fees/helpers.go b/vms/platformvm/txs/fees/helpers.go index 9c9f6817dabe..356212009896 100644 --- a/vms/platformvm/txs/fees/helpers.go +++ b/vms/platformvm/txs/fees/helpers.go @@ -5,9 +5,12 @@ package fees import ( "fmt" + "time" "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/components/fees" + "github.com/ava-labs/avalanchego/vms/platformvm/config" + "github.com/ava-labs/avalanchego/vms/platformvm/state" "github.com/ava-labs/avalanchego/vms/platformvm/txs" ) @@ -46,3 +49,33 @@ func FinanceCredential(feeCalc *Calculator, keysCount int) (uint64, error) { } return addedFees, nil } + +func UpdatedFeeManager(state state.Chain, cfg *config.Config, parentBlkTime, nextBlkTime time.Time) (*fees.Manager, error) { + var ( + isEActive = cfg.IsEActivated(parentBlkTime) + feeCfg = config.GetDynamicFeesConfig(isEActive) + ) + + feeRates, err := state.GetFeeRates() + if err != nil { + return nil, fmt.Errorf("failed retrieving fee rates: %w", err) + } + parentBlkComplexity, err := state.GetLastBlockComplexity() + if err != nil { + return nil, fmt.Errorf("failed retrieving last block complexity: %w", err) + } + + feeManager := fees.NewManager(feeRates) + if isEActive { + if err := feeManager.UpdateFeeRates( + feeCfg, + parentBlkComplexity, + parentBlkTime.Unix(), + nextBlkTime.Unix(), + ); err != nil { + return nil, fmt.Errorf("failed updating fee rates, %w", err) + } + } + + return feeManager, nil +} diff --git a/vms/platformvm/txs/txstest/builder.go b/vms/platformvm/txs/txstest/builder.go index acbfad722ecf..5dddcffe4f82 100644 --- a/vms/platformvm/txs/txstest/builder.go +++ b/vms/platformvm/txs/txstest/builder.go @@ -11,6 +11,7 @@ import ( "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/snow" "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" + "github.com/ava-labs/avalanchego/utils/timer/mockable" "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/platformvm/config" "github.com/ava-labs/avalanchego/vms/platformvm/state" @@ -20,7 +21,6 @@ import ( "github.com/ava-labs/avalanchego/wallet/chain/p/builder" "github.com/ava-labs/avalanchego/wallet/subnet/primary/common" - commonfees "github.com/ava-labs/avalanchego/vms/components/fees" vmsigner "github.com/ava-labs/avalanchego/vms/platformvm/signer" walletsigner "github.com/ava-labs/avalanchego/wallet/chain/p/signer" ) @@ -28,11 +28,13 @@ import ( func NewBuilder( ctx *snow.Context, cfg *config.Config, + clk *mockable.Clock, state state.State, ) *Builder { return &Builder{ ctx: ctx, cfg: cfg, + clk: clk, state: state, } } @@ -40,6 +42,7 @@ func NewBuilder( type Builder struct { ctx *snow.Context cfg *config.Config + clk *mockable.Clock state state.State } @@ -418,22 +421,27 @@ func (b *Builder) builders(keys []*secp256k1.PrivateKey) (builder.Builder, walle } func (b *Builder) feeCalculator() (*fees.Calculator, error) { - feeRates, err := b.state.GetFeeRates() + var ( + currentChainTime = b.state.GetTimestamp() + isEActive = b.cfg.IsEActivated(currentChainTime) + feeCfg = config.GetDynamicFeesConfig(isEActive) + ) + + nextChainTime, _, err := state.NextBlockTime(b.state, b.clk) if err != nil { - return nil, err + return nil, fmt.Errorf("failed calculating next block time: %w", err) } - var ( - chainTime = b.state.GetTimestamp() - feeCfg = config.GetDynamicFeesConfig(b.cfg.IsEActivated(chainTime)) - isEActive = b.cfg.IsEActivated(chainTime) - ) + feeManager, err := fees.UpdatedFeeManager(b.state, b.cfg, currentChainTime, nextChainTime) + if err != nil { + return nil, err + } return &fees.Calculator{ IsEActive: isEActive, Config: b.cfg, - ChainTime: chainTime, - FeeManager: commonfees.NewManager(feeRates), + ChainTime: nextChainTime, + FeeManager: feeManager, BlockMaxComplexity: feeCfg.BlockMaxComplexity, }, nil } diff --git a/vms/platformvm/validator_set_property_test.go b/vms/platformvm/validator_set_property_test.go index a6c353211cc6..15b09548b0d2 100644 --- a/vms/platformvm/validator_set_property_test.go +++ b/vms/platformvm/validator_set_property_test.go @@ -259,6 +259,7 @@ func addSubnetValidator(vm *VM, data *validatorInputData, subnetID ids.ID) (*sta txBuilder := txstest.NewBuilder( vm.ctx, &vm.Config, + &vm.clock, vm.state, ) @@ -296,6 +297,7 @@ func addPrimaryValidatorWithBLSKey(vm *VM, data *validatorInputData) (*state.Sta txBuilder := txstest.NewBuilder( vm.ctx, &vm.Config, + &vm.clock, vm.state, ) @@ -716,6 +718,7 @@ func buildVM(t *testing.T) (*VM, ids.ID, error) { txBuilder := txstest.NewBuilder( vm.ctx, &vm.Config, + &vm.clock, vm.state, ) diff --git a/vms/platformvm/vm_regression_test.go b/vms/platformvm/vm_regression_test.go index 0218e115521d..aa4bf0aa3c33 100644 --- a/vms/platformvm/vm_regression_test.go +++ b/vms/platformvm/vm_regression_test.go @@ -485,6 +485,7 @@ func TestUnverifiedParentPanicRegression(t *testing.T) { txBuilder := txstest.NewBuilder( vm.ctx, &vm.Config, + &vm.clock, vm.state, ) diff --git a/vms/platformvm/vm_test.go b/vms/platformvm/vm_test.go index 58f577e2057f..18d6586684f6 100644 --- a/vms/platformvm/vm_test.go +++ b/vms/platformvm/vm_test.go @@ -308,6 +308,7 @@ func defaultVM(t *testing.T, f fork) (*VM, *txstest.Builder, database.Database, builder := txstest.NewBuilder( ctx, &vm.Config, + &vm.clock, vm.state, ) diff --git a/wallet/chain/p/wallet.go b/wallet/chain/p/wallet.go index 8b1b9acb706c..badc0a3bb4c8 100644 --- a/wallet/chain/p/wallet.go +++ b/wallet/chain/p/wallet.go @@ -280,8 +280,8 @@ type wallet struct { signer walletsigner.Signer client platformvm.Client - isEForkActive bool - feeRates, blockMaxComplexity commonfees.Dimensions + isEForkActive bool + nextFeeRates, blockMaxComplexity commonfees.Dimensions } func (w *wallet) Builder() builder.Builder { @@ -309,7 +309,7 @@ func (w *wallet) IssueBaseTx( Config: &config.Config{ CreateSubnetTxFee: w.builder.Context().CreateSubnetTxFee, }, - FeeManager: commonfees.NewManager(w.feeRates), + FeeManager: commonfees.NewManager(w.nextFeeRates), BlockMaxComplexity: w.blockMaxComplexity, } ) @@ -337,7 +337,7 @@ func (w *wallet) IssueAddValidatorTx( Config: &config.Config{ AddPrimaryNetworkValidatorFee: w.builder.Context().AddPrimaryNetworkValidatorFee, }, - FeeManager: commonfees.NewManager(w.feeRates), + FeeManager: commonfees.NewManager(w.nextFeeRates), BlockMaxComplexity: w.blockMaxComplexity, } @@ -361,7 +361,7 @@ func (w *wallet) IssueAddSubnetValidatorTx( Config: &config.Config{ TxFee: w.builder.Context().BaseTxFee, }, - FeeManager: commonfees.NewManager(w.feeRates), + FeeManager: commonfees.NewManager(w.nextFeeRates), BlockMaxComplexity: w.blockMaxComplexity, } @@ -387,7 +387,7 @@ func (w *wallet) IssueRemoveSubnetValidatorTx( Config: &config.Config{ TxFee: w.builder.Context().BaseTxFee, }, - FeeManager: commonfees.NewManager(w.feeRates), + FeeManager: commonfees.NewManager(w.nextFeeRates), BlockMaxComplexity: w.blockMaxComplexity, } @@ -413,7 +413,7 @@ func (w *wallet) IssueAddDelegatorTx( Config: &config.Config{ AddPrimaryNetworkDelegatorFee: w.builder.Context().AddPrimaryNetworkDelegatorFee, }, - FeeManager: commonfees.NewManager(w.feeRates), + FeeManager: commonfees.NewManager(w.nextFeeRates), BlockMaxComplexity: w.blockMaxComplexity, } @@ -441,7 +441,7 @@ func (w *wallet) IssueCreateChainTx( Config: &config.Config{ CreateBlockchainTxFee: w.builder.Context().CreateBlockchainTxFee, }, - FeeManager: commonfees.NewManager(w.feeRates), + FeeManager: commonfees.NewManager(w.nextFeeRates), BlockMaxComplexity: w.blockMaxComplexity, } @@ -466,7 +466,7 @@ func (w *wallet) IssueCreateSubnetTx( Config: &config.Config{ CreateSubnetTxFee: w.builder.Context().CreateSubnetTxFee, }, - FeeManager: commonfees.NewManager(w.feeRates), + FeeManager: commonfees.NewManager(w.nextFeeRates), BlockMaxComplexity: w.blockMaxComplexity, } utx, err := w.builder.NewCreateSubnetTx(owner, feeCalc, options...) @@ -490,7 +490,7 @@ func (w *wallet) IssueTransferSubnetOwnershipTx( Config: &config.Config{ TxFee: w.builder.Context().BaseTxFee, }, - FeeManager: commonfees.NewManager(w.feeRates), + FeeManager: commonfees.NewManager(w.nextFeeRates), BlockMaxComplexity: w.blockMaxComplexity, } @@ -515,7 +515,7 @@ func (w *wallet) IssueImportTx( Config: &config.Config{ TxFee: w.builder.Context().BaseTxFee, }, - FeeManager: commonfees.NewManager(w.feeRates), + FeeManager: commonfees.NewManager(w.nextFeeRates), BlockMaxComplexity: w.blockMaxComplexity, } @@ -541,7 +541,7 @@ func (w *wallet) IssueExportTx( Config: &config.Config{ TxFee: w.builder.Context().BaseTxFee, }, - FeeManager: commonfees.NewManager(w.feeRates), + FeeManager: commonfees.NewManager(w.nextFeeRates), BlockMaxComplexity: w.blockMaxComplexity, } @@ -579,7 +579,7 @@ func (w *wallet) IssueTransformSubnetTx( Config: &config.Config{ TransformSubnetTxFee: w.builder.Context().TransformSubnetTxFee, }, - FeeManager: commonfees.NewManager(w.feeRates), + FeeManager: commonfees.NewManager(w.nextFeeRates), BlockMaxComplexity: w.blockMaxComplexity, } utx, err := w.builder.NewTransformSubnetTx( @@ -626,7 +626,7 @@ func (w *wallet) IssueAddPermissionlessValidatorTx( AddPrimaryNetworkValidatorFee: w.builder.Context().AddPrimaryNetworkValidatorFee, AddSubnetValidatorFee: w.builder.Context().AddSubnetValidatorFee, }, - FeeManager: commonfees.NewManager(w.feeRates), + FeeManager: commonfees.NewManager(w.nextFeeRates), BlockMaxComplexity: w.blockMaxComplexity, } @@ -663,7 +663,7 @@ func (w *wallet) IssueAddPermissionlessDelegatorTx( AddPrimaryNetworkDelegatorFee: w.builder.Context().AddPrimaryNetworkDelegatorFee, AddSubnetDelegatorFee: w.builder.Context().AddSubnetDelegatorFee, }, - FeeManager: commonfees.NewManager(w.feeRates), + FeeManager: commonfees.NewManager(w.nextFeeRates), BlockMaxComplexity: w.blockMaxComplexity, } @@ -744,7 +744,7 @@ func (w *wallet) refreshFeesData(options ...common.Option) error { eUpgradeTime := version.GetEUpgradeTime(w.builder.Context().NetworkID) w.isEForkActive = !chainTime.Before(eUpgradeTime) - _, w.feeRates, err = w.client.GetFeeRates(ctx) + _, w.nextFeeRates, err = w.client.GetFeeRates(ctx) if err != nil { return err } From 09e3305c5f66efcc171ad9f0e827180278cf7cc5 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 8 Apr 2024 15:14:26 +0200 Subject: [PATCH 138/190] nit --- .../txs/executor/create_chain_test.go | 40 ++++++++++++++----- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/vms/platformvm/txs/executor/create_chain_test.go b/vms/platformvm/txs/executor/create_chain_test.go index 5cf3c2af8406..4e2791113c28 100644 --- a/vms/platformvm/txs/executor/create_chain_test.go +++ b/vms/platformvm/txs/executor/create_chain_test.go @@ -30,7 +30,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() @@ -50,11 +50,18 @@ func TestCreateChainTxInsufficientControlSigs(t *testing.T) { stateDiff, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - chainTime := env.state.GetTimestamp() - feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) + currentTime := stateDiff.GetTimestamp() + nextBlkTime, _, err := state.NextBlockTime(stateDiff, env.clk) + require.NoError(err) + + feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(currentTime)) + + feeMan, err := fees.UpdatedFeeManager(stateDiff, env.config, currentTime, nextBlkTime) + require.NoError(err) + executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(feeCfg.InitialFeeRate), + BlkFeeManager: feeMan, BlockMaxComplexity: feeCfg.BlockMaxComplexity, State: stateDiff, Tx: tx, @@ -66,7 +73,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,11 +99,18 @@ func TestCreateChainTxWrongControlSig(t *testing.T) { stateDiff, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - chainTime := stateDiff.GetTimestamp() - feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(chainTime)) + currentTime := stateDiff.GetTimestamp() + nextBlkTime, _, err := state.NextBlockTime(stateDiff, env.clk) + require.NoError(err) + + feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(currentTime)) + + feeMan, err := fees.UpdatedFeeManager(stateDiff, env.config, currentTime, nextBlkTime) + require.NoError(err) + executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(feeCfg.InitialFeeRate), + BlkFeeManager: feeMan, BlockMaxComplexity: feeCfg.BlockMaxComplexity, State: stateDiff, Tx: tx, @@ -128,14 +142,18 @@ func TestCreateChainTxNoSuchSubnet(t *testing.T) { stateDiff, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - feeRates, err := env.state.GetFeeRates() + currentTime := stateDiff.GetTimestamp() + nextBlkTime, _, err := state.NextBlockTime(stateDiff, env.clk) require.NoError(err) - currentTime := stateDiff.GetTimestamp() feeCfg := config.GetDynamicFeesConfig(env.config.IsEActivated(currentTime)) + + feeMan, err := fees.UpdatedFeeManager(stateDiff, env.config, currentTime, nextBlkTime) + require.NoError(err) + executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(feeRates), + BlkFeeManager: feeMan, BlockMaxComplexity: feeCfg.BlockMaxComplexity, State: stateDiff, Tx: tx, From e2c801bd4990fe01458771deb397932b11bf64df Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 18 Apr 2024 10:07:40 +0200 Subject: [PATCH 139/190] tuned update fee algo parameters --- vms/components/fees/manager.go | 4 +- vms/components/fees/manager_test.go | 6 +-- vms/platformvm/config/dynamic_fees_config.go | 41 +++++++++++-------- .../txs/executor/create_chain_test.go | 4 +- 4 files changed, 32 insertions(+), 23 deletions(-) diff --git a/vms/components/fees/manager.go b/vms/components/fees/manager.go index 269503ddabac..4517570a6a0a 100644 --- a/vms/components/fees/manager.go +++ b/vms/components/fees/manager.go @@ -134,7 +134,7 @@ func nextFeeRate(currentFeeRate, coeff, parentBlkComplexity, targetComplexityRat switch { case parentBlkComplexity > targetComplexity: - exp := 1442 * coeff * (parentBlkComplexity - targetComplexity) / targetComplexity / 1000 + exp := 1442 * coeff * (parentBlkComplexity - targetComplexity) / targetComplexity / 1000 / 10_000 exp = min(exp, 62) // we cap the exponent to avoid an overflow of uint64 type res, over := safemath.Mul64(currentFeeRate, 1< Date: Thu, 18 Apr 2024 10:46:23 +0200 Subject: [PATCH 140/190] added UTs showing update fee rate not currently working (due to integer approximation) --- vms/components/fees/manager_test.go | 95 +++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) diff --git a/vms/components/fees/manager_test.go b/vms/components/fees/manager_test.go index 4827084eca18..ae68a1be2e9c 100644 --- a/vms/components/fees/manager_test.go +++ b/vms/components/fees/manager_test.go @@ -9,8 +9,15 @@ import ( "time" "github.com/stretchr/testify/require" + + "github.com/ava-labs/avalanchego/utils/units" ) +type blkTimeAndComplexity struct { + blkTime int64 + complexity Dimensions +} + func TestUpdateFeeRates(t *testing.T) { require := require.New(t) @@ -144,3 +151,91 @@ func TestUpdateFeeRatesStability(t *testing.T) { require.Equal(initialFeeRate[UTXOWrite], m2.feeRates[UTXOWrite]) require.Equal(initialFeeRate[Compute], m2.feeRates[Compute]) } + +func TestPChainFeeRateIncreaseDueToPeak(t *testing.T) { + // Complexity values comes from the mainnet historical peak as measured + // pre E upgrade activation + + require := require.New(t) + + var ( + feesCfg = DynamicFeesConfig{ + MinFeeRate: Dimensions{ + 60 * units.NanoAvax, + 8 * units.NanoAvax, + 10 * units.NanoAvax, + 35 * units.NanoAvax, + }, + UpdateCoefficient: Dimensions{ // over 10_000 + 30, + 20, + 25, + 20, + }, + BlockTargetComplexityRate: Dimensions{ + 200, + 60, + 80, + 600, + }, + } + + // See mainnet P-chain block 298vMuyYEi8R3XX6Ewi5orsDVYn5jrNDrPEaPG89UsckcN8e8K and sequent + blockComplexities = []blkTimeAndComplexity{ + {1703455204, Dimensions{41388, 23040, 23122, 256000}}, + {1703455209, Dimensions{41388, 23040, 23122, 256000}}, + {1703455222, Dimensions{41388, 23040, 23122, 256000}}, + {1703455228, Dimensions{41388, 23040, 23122, 256000}}, + {1703455236, Dimensions{41388, 23040, 23122, 256000}}, + {1703455242, Dimensions{41388, 23040, 23122, 256000}}, + {1703455250, Dimensions{41388, 23040, 23122, 256000}}, + {1703455256, Dimensions{41388, 23040, 23122, 256000}}, + {1703455320, Dimensions{41388, 23040, 23122, 256000}}, + {1703455328, Dimensions{41388, 23040, 23122, 256000}}, + {1703455334, Dimensions{41388, 23040, 23122, 256000}}, + {1703455349, Dimensions{41388, 23040, 23122, 256000}}, + {1703455356, Dimensions{41388, 23040, 23122, 256000}}, + {1703455362, Dimensions{41388, 23040, 23122, 256000}}, + {1703455412, Dimensions{41388, 23040, 23122, 256000}}, + {1703455418, Dimensions{41388, 23040, 23122, 256000}}, + {1703455424, Dimensions{41388, 23040, 23122, 256000}}, + {1703455430, Dimensions{41388, 23040, 23122, 256000}}, + {1703455437, Dimensions{41388, 23040, 23122, 256000}}, + {1703455442, Dimensions{41388, 23040, 23122, 256000}}, + {1703455448, Dimensions{41388, 23040, 23122, 256000}}, + {1703455454, Dimensions{41388, 23040, 23122, 256000}}, + {1703455460, Dimensions{41388, 23040, 23122, 256000}}, + {1703455468, Dimensions{41388, 23040, 23122, 256000}}, + {1703455489, Dimensions{41388, 23040, 23122, 256000}}, + {1703455497, Dimensions{41388, 23040, 23122, 256000}}, + {1703455503, Dimensions{41388, 23040, 23122, 256000}}, + {1703455509, Dimensions{41388, 23040, 23122, 256000}}, + {1703455517, Dimensions{41388, 23040, 23122, 256000}}, + {1703455528, Dimensions{41388, 23040, 23122, 256000}}, + } + ) + + m := &Manager{ + feeRates: feesCfg.MinFeeRate, + } + + parentFeeRate := feesCfg.MinFeeRate + for i := 1; i < len(blockComplexities); i++ { + parentBlkData := blockComplexities[i-1] + childBlkData := blockComplexities[i] + require.NoError(m.UpdateFeeRates( + feesCfg, + parentBlkData.complexity, + parentBlkData.blkTime, + childBlkData.blkTime, + )) + + // check that fee rates are strictly increasing + require.Less(parentFeeRate[Bandwidth], m.feeRates[Bandwidth]) + require.Less(parentFeeRate[UTXORead], m.feeRates[UTXORead]) + require.Less(parentFeeRate[UTXOWrite], m.feeRates[UTXOWrite]) + require.Less(parentFeeRate[Compute], m.feeRates[Compute]) + + parentFeeRate = m.feeRates + } +} From 38d0ac0f19cb691e5425a7e97aad32993507a036 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 18 Apr 2024 16:11:56 +0200 Subject: [PATCH 141/190] wip: solving update fees numerical precision issues --- vms/components/fees/manager.go | 83 +++++++++++++++----- vms/components/fees/manager_test.go | 60 ++++++++++---- vms/platformvm/config/dynamic_fees_config.go | 2 +- 3 files changed, 109 insertions(+), 36 deletions(-) diff --git a/vms/components/fees/manager.go b/vms/components/fees/manager.go index 4517570a6a0a..ac5d99381441 100644 --- a/vms/components/fees/manager.go +++ b/vms/components/fees/manager.go @@ -10,6 +10,9 @@ import ( safemath "github.com/ava-labs/avalanchego/utils/math" ) +// the update fee algorithm has a UpdateCoefficient, normalized to [CoeffDenom] +const CoeffDenom = uint64(10_000) + type Manager struct { // Avax denominated fee rates, i.e. fees per unit of complexity. feeRates Dimensions @@ -118,12 +121,17 @@ func (m *Manager) UpdateFeeRates( func nextFeeRate(currentFeeRate, coeff, parentBlkComplexity, targetComplexityRate, elapsedTime uint64) uint64 { // We update the fee rate with the formula: - // feeRate_{t+1} = feeRate_t * exp{coeff * (parentComplexity - targetComplexity)/(targetComplexity) } - // where [targetComplexity] is the complexity expected in the elapsed time. + // feeRate_{t+1} = feeRate_t * exp(delta) + // where + // delta == K * (parentComplexity - targetComplexity)/(targetComplexity) + // and [targetComplexity] is the median complexity expected in the elapsed time. // - // We simplify the exponential for integer math. Specifically we approximate 1/ln(2) with 1_442/1_000 - // so that exp { x } == 2^{ 1/ln(2) * x } ≈≈ 2^{1_442/1_000 * x} - // Finally we round the exponent to a uint64 + // We approximate the exponential as follows: + // * For delta in the interval [0, 10], we use the following piecewise, linear function: + // x \in [a,b] --> exp(X) ≈≈ (exp(b)-exp(a))(b-a)*(X-a) + exp(a) + // * For delta > 10 we approximate the exponential via a quadratic function + // exp(X) ≈≈ (X-10)^2 + exp(10) + // The approximation is overall continuous, so it behaves well at the interval edges // parent and child block may have the same timestamp. In this case targetComplexity will match targetComplexityRate elapsedTime = max(1, elapsedTime) @@ -132,22 +140,59 @@ func nextFeeRate(currentFeeRate, coeff, parentBlkComplexity, targetComplexityRat targetComplexity = math.MaxUint64 } - switch { - case parentBlkComplexity > targetComplexity: - exp := 1442 * coeff * (parentBlkComplexity - targetComplexity) / targetComplexity / 1000 / 10_000 - exp = min(exp, 62) // we cap the exponent to avoid an overflow of uint64 type - res, over := safemath.Mul64(currentFeeRate, 1< targetComplexity { + delta = coeff * (parentBlkComplexity - targetComplexity) / targetComplexity + increase = true + } else { + delta = coeff * (targetComplexity - parentBlkComplexity) / targetComplexity + increase = false + } + switch { + case delta < 1*CoeffDenom: + weight = 2*delta + 1*CoeffDenom + case delta < 2*CoeffDenom: + weight = 5*delta - 2*CoeffDenom + case delta < 3*CoeffDenom: + weight = 13*delta - 18*CoeffDenom + case delta < 4*CoeffDenom: + weight = 35*delta - 84*CoeffDenom + case delta < 5*CoeffDenom: + weight = 94*delta - 321*CoeffDenom + case delta < 6*CoeffDenom: + weight = 256*delta - 1131*CoeffDenom + case delta < 7*CoeffDenom: + weight = 694*delta - 3760*CoeffDenom + case delta < 8*CoeffDenom: + weight = 1885*delta - 12098*CoeffDenom + case delta < 9*CoeffDenom: + weight = 5123*delta - 38003*CoeffDenom + case delta < 10*CoeffDenom: + weight = 13924*delta - 117212*CoeffDenom default: - return currentFeeRate // unitsConsumed == target + weight = (delta/CoeffDenom - 10) ^ 2 + 22028 + } + + if increase { + return currentFeeRate * weight / CoeffDenom } + return currentFeeRate * CoeffDenom / weight } diff --git a/vms/components/fees/manager_test.go b/vms/components/fees/manager_test.go index ae68a1be2e9c..c14a27bee054 100644 --- a/vms/components/fees/manager_test.go +++ b/vms/components/fees/manager_test.go @@ -47,13 +47,13 @@ func TestUpdateFeeRates(t *testing.T) { )) // Bandwidth complexity are above target, fee rate is pushed up - require.Equal(uint64(16), m.feeRates[Bandwidth]) + require.Equal(uint64(21), m.feeRates[Bandwidth]) // UTXORead complexity is at target, fee rate does not change require.Equal(parentFeeRate[UTXORead], m.feeRates[UTXORead]) // UTXOWrite complexity is below target, fee rate is pushed down - require.Equal(uint64(5), m.feeRates[UTXOWrite]) + require.Equal(uint64(3), m.feeRates[UTXOWrite]) // Compute complexoty is below target, fee rate is pushed down to the minimum require.Equal(feesCfg.MinFeeRate[Compute], m.feeRates[Compute]) @@ -94,7 +94,7 @@ func TestUpdateFeeRatesEdgeCases(t *testing.T) { require.Equal(parentFeeRate[UTXOWrite], m.feeRates[UTXOWrite]) // Compute complexity is way above target. Fee rate spikes - require.Equal(uint64(0x8000000000000000), m.feeRates[Compute]) + require.Equal(uint64(0x55e63b88c6), m.feeRates[Compute]) } func TestUpdateFeeRatesStability(t *testing.T) { @@ -109,14 +109,15 @@ func TestUpdateFeeRatesStability(t *testing.T) { var ( feesCfg = DynamicFeesConfig{ MinFeeRate: Dimensions{0, 0, 0, 0}, - UpdateCoefficient: Dimensions{20_000, 40_000, 50_000, 100_000}, + UpdateCoefficient: Dimensions{20, 40, 50, 100}, BlockTargetComplexityRate: Dimensions{25, 50, 100, 1000}, } - initialFeeRate = Dimensions{10, 100, 1_000, 1_000_000_000} - parentComplexity = Dimensions{24, 45, 70, 500} - childComplexity = Dimensions{26, 55, 130, 1500} + initialFeeRate = Dimensions{10, 100, 1_000, 1_000_000} elapsedTime = time.Second + parentComplexity = Dimensions{24, 45, 70, 500} // less than target complexity rate * elapsedTime + childComplexity = Dimensions{26, 55, 130, 1500} // more than target complexity rate * elapsedTime + parentBlkTime = time.Now().Truncate(time.Second) childBlkTime = parentBlkTime.Add(elapsedTime) granChildBlkTime = childBlkTime.Add(elapsedTime) @@ -166,7 +167,7 @@ func TestPChainFeeRateIncreaseDueToPeak(t *testing.T) { 10 * units.NanoAvax, 35 * units.NanoAvax, }, - UpdateCoefficient: Dimensions{ // over 10_000 + UpdateCoefficient: Dimensions{ // over CoeffDenom 30, 20, 25, @@ -180,7 +181,7 @@ func TestPChainFeeRateIncreaseDueToPeak(t *testing.T) { }, } - // See mainnet P-chain block 298vMuyYEi8R3XX6Ewi5orsDVYn5jrNDrPEaPG89UsckcN8e8K and sequent + // See mainnet P-chain block 298vMuyYEi8R3XX6Ewi5orsDVYn5jrNDrPEaPG89UsckcN8e8K its descendants blockComplexities = []blkTimeAndComplexity{ {1703455204, Dimensions{41388, 23040, 23122, 256000}}, {1703455209, Dimensions{41388, 23040, 23122, 256000}}, @@ -219,7 +220,8 @@ func TestPChainFeeRateIncreaseDueToPeak(t *testing.T) { feeRates: feesCfg.MinFeeRate, } - parentFeeRate := feesCfg.MinFeeRate + // PEAK INCOMING + peakFeeRate := feesCfg.MinFeeRate for i := 1; i < len(blockComplexities); i++ { parentBlkData := blockComplexities[i-1] childBlkData := blockComplexities[i] @@ -230,12 +232,38 @@ func TestPChainFeeRateIncreaseDueToPeak(t *testing.T) { childBlkData.blkTime, )) - // check that fee rates are strictly increasing - require.Less(parentFeeRate[Bandwidth], m.feeRates[Bandwidth]) - require.Less(parentFeeRate[UTXORead], m.feeRates[UTXORead]) - require.Less(parentFeeRate[UTXOWrite], m.feeRates[UTXOWrite]) - require.Less(parentFeeRate[Compute], m.feeRates[Compute]) + // check that at least a fee rate component has strictly increased + require.False(Compare(m.feeRates, peakFeeRate)) + + // at peak the total fee for a median complexity tx should be in tens of Avax, no more. + fee, err := m.CalculateFee(feesCfg.BlockTargetComplexityRate) + require.NoError(err) + require.Less(fee, 100*units.Avax) + + peakFeeRate = m.feeRates + } - parentFeeRate = m.feeRates + // OFF PEAK + offPeakBlkComplexity := Dimensions{ + feesCfg.BlockTargetComplexityRate[Bandwidth] - 10, + feesCfg.BlockTargetComplexityRate[UTXORead] - 3, + feesCfg.BlockTargetComplexityRate[UTXOWrite] - 6, + feesCfg.BlockTargetComplexityRate[Compute] - 30, } + elapsedTime := time.Second + parentBlkTime := time.Now().Truncate(time.Second) + childBlkTime := parentBlkTime.Add(elapsedTime) + + require.NoError(m.UpdateFeeRates( + feesCfg, + offPeakBlkComplexity, + parentBlkTime.Unix(), + childBlkTime.Unix(), + )) + + // fee rates must be strictly smaller than peak ones + require.Less(m.feeRates[Bandwidth], peakFeeRate[Bandwidth]) + require.Less(m.feeRates[UTXORead], peakFeeRate[UTXORead]) + require.Less(m.feeRates[UTXOWrite], peakFeeRate[UTXOWrite]) + require.Less(m.feeRates[Compute], peakFeeRate[Compute]) } diff --git a/vms/platformvm/config/dynamic_fees_config.go b/vms/platformvm/config/dynamic_fees_config.go index 4c37c7ede813..be55a3110718 100644 --- a/vms/platformvm/config/dynamic_fees_config.go +++ b/vms/platformvm/config/dynamic_fees_config.go @@ -39,7 +39,7 @@ var ( 10 * units.NanoAvax, 35 * units.NanoAvax, }, - UpdateCoefficient: commonfees.Dimensions{ // over 10_000 + UpdateCoefficient: commonfees.Dimensions{ // over fees.CoeffDenom 30, 20, 25, From 2de2d4abeadeead3de47b3ad1fec6d3eeed9392b Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 18 Apr 2024 20:05:57 +0200 Subject: [PATCH 142/190] wip: another approximation, still with some numerical errors --- vms/components/fees/manager.go | 78 ++++++++++++++++++----------- vms/components/fees/manager_test.go | 8 ++- 2 files changed, 57 insertions(+), 29 deletions(-) diff --git a/vms/components/fees/manager.go b/vms/components/fees/manager.go index ac5d99381441..a017182ad3ce 100644 --- a/vms/components/fees/manager.go +++ b/vms/components/fees/manager.go @@ -111,6 +111,7 @@ func (m *Manager) UpdateFeeRates( feesConfig.UpdateCoefficient[i], parentBlkComplexity[i], feesConfig.BlockTargetComplexityRate[i], + feesConfig.BlockMaxComplexity[i], elapsedTime, ) nextFeeRates = max(nextFeeRates, feesConfig.MinFeeRate[i]) @@ -119,7 +120,7 @@ func (m *Manager) UpdateFeeRates( return nil } -func nextFeeRate(currentFeeRate, coeff, parentBlkComplexity, targetComplexityRate, elapsedTime uint64) uint64 { +func nextFeeRate(currentFeeRate, coeff, parentBlkComplexity, targetComplexityRate, maxBlkComplexity, elapsedTime uint64) uint64 { // We update the fee rate with the formula: // feeRate_{t+1} = feeRate_t * exp(delta) // where @@ -127,10 +128,9 @@ func nextFeeRate(currentFeeRate, coeff, parentBlkComplexity, targetComplexityRat // and [targetComplexity] is the median complexity expected in the elapsed time. // // We approximate the exponential as follows: - // * For delta in the interval [0, 10], we use the following piecewise, linear function: + // * For delta in the interval [0, MaxDelta], we use the following piecewise, linear function: // x \in [a,b] --> exp(X) ≈≈ (exp(b)-exp(a))(b-a)*(X-a) + exp(a) - // * For delta > 10 we approximate the exponential via a quadratic function - // exp(X) ≈≈ (X-10)^2 + exp(10) + // MaxDelta is given by the max block complexity (MaxBlkComplexity - targetComplexity)/(targetComplexity) // The approximation is overall continuous, so it behaves well at the interval edges // parent and child block may have the same timestamp. In this case targetComplexity will match targetComplexityRate @@ -145,7 +145,8 @@ func nextFeeRate(currentFeeRate, coeff, parentBlkComplexity, targetComplexityRat } var ( - delta uint64 + scaledDelta uint64 + scaleCoeff uint64 // [increase] tells if // [nextFeeRate] = [currentFeeRate] * [factor] or @@ -159,36 +160,57 @@ func nextFeeRate(currentFeeRate, coeff, parentBlkComplexity, targetComplexityRat // To control for numerical errors, we defer [coeff] normalization by [CoeffDenom] // to the very end. This is possible since the approximation we use is piecewise linear. if parentBlkComplexity > targetComplexity { - delta = coeff * (parentBlkComplexity - targetComplexity) / targetComplexity + scaledDelta = 10 * (parentBlkComplexity - targetComplexity) / (maxBlkComplexity - targetComplexity) + scaleCoeff = coeff * (maxBlkComplexity - targetComplexity) / targetComplexity / CoeffDenom / 10 increase = true } else { - delta = coeff * (targetComplexity - parentBlkComplexity) / targetComplexity + scaledDelta = 10 * (targetComplexity - parentBlkComplexity) / (maxBlkComplexity - targetComplexity) + scaleCoeff = coeff * (maxBlkComplexity - targetComplexity) / targetComplexity / CoeffDenom / 10 increase = false } + var ( + m, q uint64 + qPositive bool + ) switch { - case delta < 1*CoeffDenom: - weight = 2*delta + 1*CoeffDenom - case delta < 2*CoeffDenom: - weight = 5*delta - 2*CoeffDenom - case delta < 3*CoeffDenom: - weight = 13*delta - 18*CoeffDenom - case delta < 4*CoeffDenom: - weight = 35*delta - 84*CoeffDenom - case delta < 5*CoeffDenom: - weight = 94*delta - 321*CoeffDenom - case delta < 6*CoeffDenom: - weight = 256*delta - 1131*CoeffDenom - case delta < 7*CoeffDenom: - weight = 694*delta - 3760*CoeffDenom - case delta < 8*CoeffDenom: - weight = 1885*delta - 12098*CoeffDenom - case delta < 9*CoeffDenom: - weight = 5123*delta - 38003*CoeffDenom - case delta < 10*CoeffDenom: - weight = 13924*delta - 117212*CoeffDenom + case scaledDelta < 1: + m = 2 + q = 1 + qPositive = true + case scaledDelta < 2: + m = 5 + q = 2 + case scaledDelta < 3: + m = 13 + q = 18 + case scaledDelta < 4: + m = 35 + q = 84 + case scaledDelta < 5: + m = 94 + q = 321 + case scaledDelta < 6: + m = 256 + q = 1131 + case scaledDelta < 7: + m = 694 + q = 3760 + case scaledDelta < 8: + m = 1885 + q = 12098 + case scaledDelta < 9: + m = 5123 + q = 38003 default: - weight = (delta/CoeffDenom - 10) ^ 2 + 22028 + m = 13924 + q = 117212 + } + + if !qPositive { + weight = scaleCoeff*(m*scaledDelta-q) + (scaleCoeff-1)*q + } else { + weight = scaleCoeff*(m*scaledDelta+q) - (scaleCoeff-1)*q } if increase { diff --git a/vms/components/fees/manager_test.go b/vms/components/fees/manager_test.go index c14a27bee054..84ade8a18ef6 100644 --- a/vms/components/fees/manager_test.go +++ b/vms/components/fees/manager_test.go @@ -24,7 +24,7 @@ func TestUpdateFeeRates(t *testing.T) { var ( feesCfg = DynamicFeesConfig{ MinFeeRate: Dimensions{1, 1, 1, 1}, - UpdateCoefficient: Dimensions{10_000, 20_000, 50_000, 100_000}, + UpdateCoefficient: Dimensions{1, 2, 5, 10}, BlockTargetComplexityRate: Dimensions{25, 25, 25, 25}, } parentFeeRate = Dimensions{1, 2, 10, 20} @@ -173,6 +173,12 @@ func TestPChainFeeRateIncreaseDueToPeak(t *testing.T) { 25, 20, }, + BlockMaxComplexity: Dimensions{ + 100_000, + 40_000, + 40_000, + 500_000, + }, BlockTargetComplexityRate: Dimensions{ 200, 60, From ace5379bcc23a4f37f36255eddf3eeca9c617199 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Fri, 19 Apr 2024 14:50:47 +0200 Subject: [PATCH 143/190] fixing update fees algo --- vms/components/fees/manager.go | 145 ++++++++++++++++++++-------- vms/components/fees/manager_test.go | 25 +++-- 2 files changed, 119 insertions(+), 51 deletions(-) diff --git a/vms/components/fees/manager.go b/vms/components/fees/manager.go index ac5d99381441..b83a0a692fa8 100644 --- a/vms/components/fees/manager.go +++ b/vms/components/fees/manager.go @@ -10,8 +10,8 @@ import ( safemath "github.com/ava-labs/avalanchego/utils/math" ) -// the update fee algorithm has a UpdateCoefficient, normalized to [CoeffDenom] -const CoeffDenom = uint64(10_000) +// the update fee algorithm has a UpdateCoefficient, normalized to [CoeffDenom] +const CoeffDenom = uint64(1_000) type Manager struct { // Avax denominated fee rates, i.e. fees per unit of complexity. @@ -111,6 +111,7 @@ func (m *Manager) UpdateFeeRates( feesConfig.UpdateCoefficient[i], parentBlkComplexity[i], feesConfig.BlockTargetComplexityRate[i], + feesConfig.BlockMaxComplexity[i], elapsedTime, ) nextFeeRates = max(nextFeeRates, feesConfig.MinFeeRate[i]) @@ -119,7 +120,14 @@ func (m *Manager) UpdateFeeRates( return nil } -func nextFeeRate(currentFeeRate, coeff, parentBlkComplexity, targetComplexityRate, elapsedTime uint64) uint64 { +func nextFeeRate( + currentFeeRate, + coeff, + parentBlkComplexity, + targetComplexityRate, + maxComplexity, + elapsedTime uint64, +) uint64 { // We update the fee rate with the formula: // feeRate_{t+1} = feeRate_t * exp(delta) // where @@ -144,55 +152,108 @@ func nextFeeRate(currentFeeRate, coeff, parentBlkComplexity, targetComplexityRat return currentFeeRate // complexity matches target, nothing to update } - var ( - delta uint64 - - // [increase] tells if - // [nextFeeRate] = [currentFeeRate] * [factor] or - // [nextFeeRate] = [currentFeeRate] / [factor] - increase bool - - // [weight] is how much we increase or reduce the fee rate - weight uint64 - ) + // [increase] tells if + // [nextFeeRate] = [currentFeeRate] * [factor] or + // [nextFeeRate] = [currentFeeRate] / [factor] + var increase bool - // To control for numerical errors, we defer [coeff] normalization by [CoeffDenom] - // to the very end. This is possible since the approximation we use is piecewise linear. - if parentBlkComplexity > targetComplexity { - delta = coeff * (parentBlkComplexity - targetComplexity) / targetComplexity + var num1 uint64 + if maxComplexity > targetComplexity { + num1 = coeff * (maxComplexity - targetComplexity) increase = true } else { - delta = coeff * (targetComplexity - parentBlkComplexity) / targetComplexity + num1 = coeff * (targetComplexity - maxComplexity) increase = false } + denom1 := CoeffDenom * targetComplexity switch { - case delta < 1*CoeffDenom: - weight = 2*delta + 1*CoeffDenom - case delta < 2*CoeffDenom: - weight = 5*delta - 2*CoeffDenom - case delta < 3*CoeffDenom: - weight = 13*delta - 18*CoeffDenom - case delta < 4*CoeffDenom: - weight = 35*delta - 84*CoeffDenom - case delta < 5*CoeffDenom: - weight = 94*delta - 321*CoeffDenom - case delta < 6*CoeffDenom: - weight = 256*delta - 1131*CoeffDenom - case delta < 7*CoeffDenom: - weight = 694*delta - 3760*CoeffDenom - case delta < 8*CoeffDenom: - weight = 1885*delta - 12098*CoeffDenom - case delta < 9*CoeffDenom: - weight = 5123*delta - 38003*CoeffDenom - case delta < 10*CoeffDenom: - weight = 13924*delta - 117212*CoeffDenom + case num1 < 1*denom1: + num1 = 2*num1 + denom1 + case num1 < 2*denom1: + num1 = 5*num1 - 2*denom1 + case num1 < 3*denom1: + num1 = 13*num1 - 18*denom1 + case num1 < 4*denom1: + num1 = 35*num1 - 84*denom1 + case num1 < 5*denom1: + num1 = 94*num1 - 321*denom1 + case num1 < 6*denom1: + num1 = 256*num1 - 1131*denom1 + case num1 < 7*denom1: + num1 = 694*num1 - 3760*denom1 + case num1 < 8*denom1: + num1 = 1885*num1 - 12098*denom1 + case num1 < 9*denom1: + num1 = 5123*num1 - 38003*denom1 default: - weight = (delta/CoeffDenom - 10) ^ 2 + 22028 + num1 = 13924*num1 - 117212*denom1 + } + + var ( + num2 uint64 + denom2 uint64 + ) + + if maxComplexity > targetComplexity { + num2 = parentBlkComplexity + maxComplexity - 2*targetComplexity + denom2 = maxComplexity - targetComplexity + } else { + num2 = 2*targetComplexity - parentBlkComplexity - maxComplexity + denom2 = targetComplexity - maxComplexity } if increase { - return currentFeeRate * weight / CoeffDenom + return currentFeeRate * num1 * num2 / denom1 / denom2 + } else { + return currentFeeRate * denom1 * num2 / num1 / denom2 } - return currentFeeRate * CoeffDenom / weight + + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + + // // To control for numerical errors, we defer [coeff] normalization by [CoeffDenom] + // // to the very end. This is possible since the approximation we use is piecewise linear. + // if parentBlkComplexity > targetComplexity { + // delta = coeff * (parentBlkComplexity - targetComplexity) / targetComplexity + // increase = true + // } else { + // delta = coeff * (targetComplexity - parentBlkComplexity) / targetComplexity + // increase = false + // } + + // switch { + // case delta < 1*CoeffDenom: + // weight = 2*delta + 1*CoeffDenom + // case delta < 2*CoeffDenom: + // weight = 5*delta - 2*CoeffDenom + // case delta < 3*CoeffDenom: + // weight = 13*delta - 18*CoeffDenom + // case delta < 4*CoeffDenom: + // weight = 35*delta - 84*CoeffDenom + // case delta < 5*CoeffDenom: + // weight = 94*delta - 321*CoeffDenom + // case delta < 6*CoeffDenom: + // weight = 256*delta - 1131*CoeffDenom + // case delta < 7*CoeffDenom: + // weight = 694*delta - 3760*CoeffDenom + // case delta < 8*CoeffDenom: + // weight = 1885*delta - 12098*CoeffDenom + // case delta < 9*CoeffDenom: + // weight = 5123*delta - 38003*CoeffDenom + // case delta < 10*CoeffDenom: + // weight = 13924*delta - 117212*CoeffDenom + // default: + // weight = (delta/CoeffDenom - 10) ^ 2 + 22028 + // } + + // if increase { + // return currentFeeRate * weight / CoeffDenom + // } + // return currentFeeRate * CoeffDenom / weight + + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// } diff --git a/vms/components/fees/manager_test.go b/vms/components/fees/manager_test.go index c14a27bee054..7e879b69783e 100644 --- a/vms/components/fees/manager_test.go +++ b/vms/components/fees/manager_test.go @@ -4,6 +4,7 @@ package fees import ( + "fmt" "math" "testing" "time" @@ -168,10 +169,10 @@ func TestPChainFeeRateIncreaseDueToPeak(t *testing.T) { 35 * units.NanoAvax, }, UpdateCoefficient: Dimensions{ // over CoeffDenom - 30, - 20, - 25, - 20, + 4, + 1, + 2, + 3, }, BlockTargetComplexityRate: Dimensions{ 200, @@ -179,6 +180,12 @@ func TestPChainFeeRateIncreaseDueToPeak(t *testing.T) { 80, 600, }, + BlockMaxComplexity: Dimensions{ + 100_000, + 60_000, + 60_000, + 600_000, + }, } // See mainnet P-chain block 298vMuyYEi8R3XX6Ewi5orsDVYn5jrNDrPEaPG89UsckcN8e8K its descendants @@ -238,17 +245,17 @@ func TestPChainFeeRateIncreaseDueToPeak(t *testing.T) { // at peak the total fee for a median complexity tx should be in tens of Avax, no more. fee, err := m.CalculateFee(feesCfg.BlockTargetComplexityRate) require.NoError(err) - require.Less(fee, 100*units.Avax) + require.Less(fee, 100*units.Avax, fmt.Sprintf("iteration: %d, total: %d", i, len(blockComplexities))) peakFeeRate = m.feeRates } // OFF PEAK offPeakBlkComplexity := Dimensions{ - feesCfg.BlockTargetComplexityRate[Bandwidth] - 10, - feesCfg.BlockTargetComplexityRate[UTXORead] - 3, - feesCfg.BlockTargetComplexityRate[UTXOWrite] - 6, - feesCfg.BlockTargetComplexityRate[Compute] - 30, + feesCfg.BlockTargetComplexityRate[Bandwidth] * 1 / 10, + feesCfg.BlockTargetComplexityRate[UTXORead] * 1 / 10, + feesCfg.BlockTargetComplexityRate[UTXOWrite] * 1 / 10, + feesCfg.BlockTargetComplexityRate[Compute] * 1 / 10, } elapsedTime := time.Second parentBlkTime := time.Now().Truncate(time.Second) From d64d30e6285f68748335dc28bfdd962b0573ea37 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Fri, 19 Apr 2024 15:40:35 +0200 Subject: [PATCH 144/190] some more fixes for the decrease side --- vms/components/fees/manager.go | 163 +++++++++++----------------- vms/components/fees/manager_test.go | 2 +- 2 files changed, 63 insertions(+), 102 deletions(-) diff --git a/vms/components/fees/manager.go b/vms/components/fees/manager.go index b83a0a692fa8..c029eca4e3f3 100644 --- a/vms/components/fees/manager.go +++ b/vms/components/fees/manager.go @@ -135,11 +135,7 @@ func nextFeeRate( // and [targetComplexity] is the median complexity expected in the elapsed time. // // We approximate the exponential as follows: - // * For delta in the interval [0, 10], we use the following piecewise, linear function: - // x \in [a,b] --> exp(X) ≈≈ (exp(b)-exp(a))(b-a)*(X-a) + exp(a) - // * For delta > 10 we approximate the exponential via a quadratic function - // exp(X) ≈≈ (X-10)^2 + exp(10) - // The approximation is overall continuous, so it behaves well at the interval edges + // TODO DESCRIBE IT // parent and child block may have the same timestamp. In this case targetComplexity will match targetComplexityRate elapsedTime = max(1, elapsedTime) @@ -152,108 +148,73 @@ func nextFeeRate( return currentFeeRate // complexity matches target, nothing to update } - // [increase] tells if - // [nextFeeRate] = [currentFeeRate] * [factor] or - // [nextFeeRate] = [currentFeeRate] / [factor] - var increase bool - - var num1 uint64 - if maxComplexity > targetComplexity { - num1 = coeff * (maxComplexity - targetComplexity) - increase = true - } else { - num1 = coeff * (targetComplexity - maxComplexity) - increase = false - } - denom1 := CoeffDenom * targetComplexity + var ( + increaseFee bool - switch { - case num1 < 1*denom1: - num1 = 2*num1 + denom1 - case num1 < 2*denom1: - num1 = 5*num1 - 2*denom1 - case num1 < 3*denom1: - num1 = 13*num1 - 18*denom1 - case num1 < 4*denom1: - num1 = 35*num1 - 84*denom1 - case num1 < 5*denom1: - num1 = 94*num1 - 321*denom1 - case num1 < 6*denom1: - num1 = 256*num1 - 1131*denom1 - case num1 < 7*denom1: - num1 = 694*num1 - 3760*denom1 - case num1 < 8*denom1: - num1 = 1885*num1 - 12098*denom1 - case num1 < 9*denom1: - num1 = 5123*num1 - 38003*denom1 - default: - num1 = 13924*num1 - 117212*denom1 - } + numExp uint64 + denomExp = CoeffDenom * targetComplexity - var ( - num2 uint64 - denom2 uint64 + numFactor uint64 + denomFactor uint64 ) - if maxComplexity > targetComplexity { - num2 = parentBlkComplexity + maxComplexity - 2*targetComplexity - denom2 = maxComplexity - targetComplexity - } else { - num2 = 2*targetComplexity - parentBlkComplexity - maxComplexity - denom2 = targetComplexity - maxComplexity + // Assumes parentBlkComplexity <= maxComplexity + switch { + case targetComplexity < parentBlkComplexity: + increaseFee = true + numExp = coeff * (maxComplexity - targetComplexity) + + numFactor = maxComplexity + parentBlkComplexity - 2*targetComplexity + denomFactor = maxComplexity - targetComplexity + + case parentBlkComplexity < targetComplexity && targetComplexity < maxComplexity: + increaseFee = false + numExp = coeff * (maxComplexity - targetComplexity) + + numFactor = maxComplexity - parentBlkComplexity + denomFactor = maxComplexity - targetComplexity + + case parentBlkComplexity < targetComplexity && targetComplexity == maxComplexity: + increaseFee = false + numExp = coeff * (maxComplexity - targetComplexity) + + numFactor = 1 + denomFactor = 1 + default: // parentBlkComplexity < targetComplexity && maxComplexity < targetComplexity + increaseFee = false + numExp = coeff * (targetComplexity - maxComplexity) + + numFactor = 2*targetComplexity - maxComplexity - parentBlkComplexity + denomFactor = targetComplexity - maxComplexity + } + + // Exponentiate via the piecewise linear approximation + switch { + case numExp < 1*denomExp: + numExp = 2*numExp + denomExp + case numExp < 2*denomExp: + numExp = 5*numExp - 2*denomExp + case numExp < 3*denomExp: + numExp = 13*numExp - 18*denomExp + case numExp < 4*denomExp: + numExp = 35*numExp - 84*denomExp + case numExp < 5*denomExp: + numExp = 94*numExp - 321*denomExp + case numExp < 6*denomExp: + numExp = 256*numExp - 1131*denomExp + case numExp < 7*denomExp: + numExp = 694*numExp - 3760*denomExp + case numExp < 8*denomExp: + numExp = 1885*numExp - 12098*denomExp + case numExp < 9*denomExp: + numExp = 5123*numExp - 38003*denomExp + default: + numExp = 13924*numExp - 117212*denomExp } - if increase { - return currentFeeRate * num1 * num2 / denom1 / denom2 - } else { - return currentFeeRate * denom1 * num2 / num1 / denom2 + if increaseFee { + return currentFeeRate * numExp * numFactor / denomExp / denomFactor } - //////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////// - - // // To control for numerical errors, we defer [coeff] normalization by [CoeffDenom] - // // to the very end. This is possible since the approximation we use is piecewise linear. - // if parentBlkComplexity > targetComplexity { - // delta = coeff * (parentBlkComplexity - targetComplexity) / targetComplexity - // increase = true - // } else { - // delta = coeff * (targetComplexity - parentBlkComplexity) / targetComplexity - // increase = false - // } - - // switch { - // case delta < 1*CoeffDenom: - // weight = 2*delta + 1*CoeffDenom - // case delta < 2*CoeffDenom: - // weight = 5*delta - 2*CoeffDenom - // case delta < 3*CoeffDenom: - // weight = 13*delta - 18*CoeffDenom - // case delta < 4*CoeffDenom: - // weight = 35*delta - 84*CoeffDenom - // case delta < 5*CoeffDenom: - // weight = 94*delta - 321*CoeffDenom - // case delta < 6*CoeffDenom: - // weight = 256*delta - 1131*CoeffDenom - // case delta < 7*CoeffDenom: - // weight = 694*delta - 3760*CoeffDenom - // case delta < 8*CoeffDenom: - // weight = 1885*delta - 12098*CoeffDenom - // case delta < 9*CoeffDenom: - // weight = 5123*delta - 38003*CoeffDenom - // case delta < 10*CoeffDenom: - // weight = 13924*delta - 117212*CoeffDenom - // default: - // weight = (delta/CoeffDenom - 10) ^ 2 + 22028 - // } - - // if increase { - // return currentFeeRate * weight / CoeffDenom - // } - // return currentFeeRate * CoeffDenom / weight - - //////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////// + return currentFeeRate * denomExp * numFactor / numExp / denomFactor } diff --git a/vms/components/fees/manager_test.go b/vms/components/fees/manager_test.go index 7e879b69783e..f6ddf49f2d86 100644 --- a/vms/components/fees/manager_test.go +++ b/vms/components/fees/manager_test.go @@ -240,7 +240,7 @@ func TestPChainFeeRateIncreaseDueToPeak(t *testing.T) { )) // check that at least a fee rate component has strictly increased - require.False(Compare(m.feeRates, peakFeeRate)) + require.False(Compare(m.feeRates, peakFeeRate), fmt.Sprintf("failed at %d of %d iteration", i, len(blockComplexities))) // at peak the total fee for a median complexity tx should be in tens of Avax, no more. fee, err := m.CalculateFee(feesCfg.BlockTargetComplexityRate) From 9edcabe770406aa397f54034d87f63f8b8e42bfa Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Sun, 21 Apr 2024 15:19:32 +0200 Subject: [PATCH 145/190] fix --- vms/components/fees/manager.go | 87 +++++----------- vms/components/fees/manager_test.go | 103 +++++++------------ vms/platformvm/config/dynamic_fees_config.go | 8 +- 3 files changed, 69 insertions(+), 129 deletions(-) diff --git a/vms/components/fees/manager.go b/vms/components/fees/manager.go index c029eca4e3f3..85ee1f539064 100644 --- a/vms/components/fees/manager.go +++ b/vms/components/fees/manager.go @@ -111,7 +111,6 @@ func (m *Manager) UpdateFeeRates( feesConfig.UpdateCoefficient[i], parentBlkComplexity[i], feesConfig.BlockTargetComplexityRate[i], - feesConfig.BlockMaxComplexity[i], elapsedTime, ) nextFeeRates = max(nextFeeRates, feesConfig.MinFeeRate[i]) @@ -125,7 +124,6 @@ func nextFeeRate( coeff, parentBlkComplexity, targetComplexityRate, - maxComplexity, elapsedTime uint64, ) uint64 { // We update the fee rate with the formula: @@ -135,7 +133,16 @@ func nextFeeRate( // and [targetComplexity] is the median complexity expected in the elapsed time. // // We approximate the exponential as follows: - // TODO DESCRIBE IT + // + // 1 + k * delta^2 if delta >= 0 + // feeRate_{t+1} = feeRate_t * + // 1 / (1 + k * delta^2) if delta < 0 + // + // The approximation keeps two key properties of the exponential formula: + // 1. It's strictly increasing with delta + // 2. It's stable because feeRate(delta) * feeRate(-delta) = 1, meaning that + // if complexity increase and decrease by the same amount in two consecutive blocks + // the fee rate will go back to the original value. // parent and child block may have the same timestamp. In this case targetComplexity will match targetComplexityRate elapsedTime = max(1, elapsedTime) @@ -150,71 +157,31 @@ func nextFeeRate( var ( increaseFee bool - - numExp uint64 - denomExp = CoeffDenom * targetComplexity - - numFactor uint64 - denomFactor uint64 + delta uint64 ) - // Assumes parentBlkComplexity <= maxComplexity - switch { - case targetComplexity < parentBlkComplexity: + if targetComplexity < parentBlkComplexity { increaseFee = true - numExp = coeff * (maxComplexity - targetComplexity) - - numFactor = maxComplexity + parentBlkComplexity - 2*targetComplexity - denomFactor = maxComplexity - targetComplexity - - case parentBlkComplexity < targetComplexity && targetComplexity < maxComplexity: - increaseFee = false - numExp = coeff * (maxComplexity - targetComplexity) - - numFactor = maxComplexity - parentBlkComplexity - denomFactor = maxComplexity - targetComplexity - - case parentBlkComplexity < targetComplexity && targetComplexity == maxComplexity: - increaseFee = false - numExp = coeff * (maxComplexity - targetComplexity) - - numFactor = 1 - denomFactor = 1 - default: // parentBlkComplexity < targetComplexity && maxComplexity < targetComplexity + delta = parentBlkComplexity - targetComplexity + } else { increaseFee = false - numExp = coeff * (targetComplexity - maxComplexity) - - numFactor = 2*targetComplexity - maxComplexity - parentBlkComplexity - denomFactor = targetComplexity - maxComplexity + delta = targetComplexity - parentBlkComplexity } - // Exponentiate via the piecewise linear approximation - switch { - case numExp < 1*denomExp: - numExp = 2*numExp + denomExp - case numExp < 2*denomExp: - numExp = 5*numExp - 2*denomExp - case numExp < 3*denomExp: - numExp = 13*numExp - 18*denomExp - case numExp < 4*denomExp: - numExp = 35*numExp - 84*denomExp - case numExp < 5*denomExp: - numExp = 94*numExp - 321*denomExp - case numExp < 6*denomExp: - numExp = 256*numExp - 1131*denomExp - case numExp < 7*denomExp: - numExp = 694*numExp - 3760*denomExp - case numExp < 8*denomExp: - numExp = 1885*numExp - 12098*denomExp - case numExp < 9*denomExp: - numExp = 5123*numExp - 38003*denomExp - default: - numExp = 13924*numExp - 117212*denomExp - } + num := coeff * delta * delta + denom := targetComplexity * targetComplexity * CoeffDenom if increaseFee { - return currentFeeRate * numExp * numFactor / denomExp / denomFactor + res, over := safemath.Mul64(currentFeeRate, denom+num) + if over != nil { + res = math.MaxUint64 + } + return res / denom } - return currentFeeRate * denomExp * numFactor / numExp / denomFactor + res, over := safemath.Mul64(currentFeeRate, denom) + if over != nil { + res = math.MaxUint64 + } + return res / (denom + num) } diff --git a/vms/components/fees/manager_test.go b/vms/components/fees/manager_test.go index f6ddf49f2d86..c40b49ef96f0 100644 --- a/vms/components/fees/manager_test.go +++ b/vms/components/fees/manager_test.go @@ -5,7 +5,6 @@ package fees import ( "fmt" - "math" "testing" "time" @@ -25,10 +24,10 @@ func TestUpdateFeeRates(t *testing.T) { var ( feesCfg = DynamicFeesConfig{ MinFeeRate: Dimensions{1, 1, 1, 1}, - UpdateCoefficient: Dimensions{10_000, 20_000, 50_000, 100_000}, + UpdateCoefficient: Dimensions{10, 20, 50, 100}, BlockTargetComplexityRate: Dimensions{25, 25, 25, 25}, } - parentFeeRate = Dimensions{1, 2, 10, 20} + parentFeeRate = Dimensions{10, 20, 100, 200} parentComplexity = Dimensions{100, 25, 20, 10} elapsedTime = time.Second @@ -48,54 +47,16 @@ func TestUpdateFeeRates(t *testing.T) { )) // Bandwidth complexity are above target, fee rate is pushed up - require.Equal(uint64(21), m.feeRates[Bandwidth]) + require.Equal(uint64(10), m.feeRates[Bandwidth]) // UTXORead complexity is at target, fee rate does not change require.Equal(parentFeeRate[UTXORead], m.feeRates[UTXORead]) // UTXOWrite complexity is below target, fee rate is pushed down - require.Equal(uint64(3), m.feeRates[UTXOWrite]) + require.Equal(uint64(99), m.feeRates[UTXOWrite]) // Compute complexoty is below target, fee rate is pushed down to the minimum - require.Equal(feesCfg.MinFeeRate[Compute], m.feeRates[Compute]) -} - -func TestUpdateFeeRatesEdgeCases(t *testing.T) { - require := require.New(t) - - var ( - feesCfg = DynamicFeesConfig{ - MinFeeRate: Dimensions{1, 0, 0, 0}, - UpdateCoefficient: Dimensions{10_000, 10_000, 10_000, 10_000}, - BlockTargetComplexityRate: Dimensions{math.MaxUint64, 1, 1, 1}, // a very skewed requirement for block complexity - } - parentFeeRate = Dimensions{2, 1, 2, 2} - parentComplexity = Dimensions{math.MaxUint64, 0, 1, math.MaxUint64} - - elapsedTime = time.Second - parentBlkTime = time.Now().Truncate(time.Second) - childBlkTime = parentBlkTime.Add(elapsedTime) - ) - - m := &Manager{feeRates: parentFeeRate} - require.NoError(m.UpdateFeeRates( - feesCfg, - parentComplexity, - parentBlkTime.Unix(), - childBlkTime.Unix(), - )) - - // Bandwidth complexity is huge but at target, fee rate is unchanged - require.Equal(parentFeeRate[Bandwidth], m.feeRates[Bandwidth]) - - // UTXORead complexity is below target. Fee rate is reduced - require.Equal(feesCfg.MinFeeRate[UTXORead], m.feeRates[UTXORead]) - - // UTXOWrite complexity is at target, fee rate is unchanged - require.Equal(parentFeeRate[UTXOWrite], m.feeRates[UTXOWrite]) - - // Compute complexity is way above target. Fee rate spikes - require.Equal(uint64(0x55e63b88c6), m.feeRates[Compute]) + require.Equal(uint64(193), m.feeRates[Compute]) } func TestUpdateFeeRatesStability(t *testing.T) { @@ -103,21 +64,26 @@ func TestUpdateFeeRatesStability(t *testing.T) { // (vs e.g. the EIP-1559 scheme we use in the C-chain) is that // it is more stable against dithering. // We prove here that if complexity oscillates around the target - // fee rates are unchanged. + // fee rates are unchanged (discounting for some numerical errors) require := require.New(t) var ( feesCfg = DynamicFeesConfig{ MinFeeRate: Dimensions{0, 0, 0, 0}, - UpdateCoefficient: Dimensions{20, 40, 50, 100}, - BlockTargetComplexityRate: Dimensions{25, 50, 100, 1000}, + UpdateCoefficient: Dimensions{2, 4, 5, 10}, + BlockTargetComplexityRate: Dimensions{200, 60, 80, 600}, + } + initialFeeRate = Dimensions{ + 60 * units.NanoAvax, + 8 * units.NanoAvax, + 10 * units.NanoAvax, + 35 * units.NanoAvax, } - initialFeeRate = Dimensions{10, 100, 1_000, 1_000_000} elapsedTime = time.Second - parentComplexity = Dimensions{24, 45, 70, 500} // less than target complexity rate * elapsedTime - childComplexity = Dimensions{26, 55, 130, 1500} // more than target complexity rate * elapsedTime + parentComplexity = Dimensions{50, 45, 70, 500} // less than target complexity rate * elapsedTime + childComplexity = Dimensions{350, 75, 90, 700} // more than target complexity rate * elapsedTime parentBlkTime = time.Now().Truncate(time.Second) childBlkTime = parentBlkTime.Add(elapsedTime) @@ -133,8 +99,8 @@ func TestUpdateFeeRatesStability(t *testing.T) { childBlkTime.Unix(), )) - require.LessOrEqual(m1.feeRates[Bandwidth], initialFeeRate[Bandwidth]) - require.LessOrEqual(m1.feeRates[UTXORead], initialFeeRate[UTXORead]) + require.Less(m1.feeRates[Bandwidth], initialFeeRate[Bandwidth]) + require.Less(m1.feeRates[UTXORead], initialFeeRate[UTXORead]) require.Less(m1.feeRates[UTXOWrite], initialFeeRate[UTXOWrite]) require.Less(m1.feeRates[Compute], initialFeeRate[Compute]) @@ -148,10 +114,10 @@ func TestUpdateFeeRatesStability(t *testing.T) { granChildBlkTime.Unix(), )) - require.Equal(initialFeeRate[Bandwidth], m2.feeRates[Bandwidth]) - require.Equal(initialFeeRate[UTXORead], m2.feeRates[UTXORead]) - require.Equal(initialFeeRate[UTXOWrite], m2.feeRates[UTXOWrite]) - require.Equal(initialFeeRate[Compute], m2.feeRates[Compute]) + require.LessOrEqual(initialFeeRate[Bandwidth]-m2.feeRates[Bandwidth], uint64(1)) + require.LessOrEqual(initialFeeRate[UTXORead]-m2.feeRates[UTXORead], uint64(1)) + require.LessOrEqual(initialFeeRate[UTXOWrite]-m2.feeRates[UTXOWrite], uint64(1)) + require.LessOrEqual(initialFeeRate[Compute]-m2.feeRates[Compute], uint64(1)) } func TestPChainFeeRateIncreaseDueToPeak(t *testing.T) { @@ -175,10 +141,10 @@ func TestPChainFeeRateIncreaseDueToPeak(t *testing.T) { 3, }, BlockTargetComplexityRate: Dimensions{ - 200, - 60, - 80, - 600, + 4 * 200, + 4 * 60, + 4 * 80, + 4 * 600, }, BlockMaxComplexity: Dimensions{ 100_000, @@ -240,7 +206,14 @@ func TestPChainFeeRateIncreaseDueToPeak(t *testing.T) { )) // check that at least a fee rate component has strictly increased - require.False(Compare(m.feeRates, peakFeeRate), fmt.Sprintf("failed at %d of %d iteration", i, len(blockComplexities))) + require.False( + Compare(m.feeRates, peakFeeRate), + fmt.Sprintf("failed at %d of %d iteration, \n curr fees %v \n next fees %v", + i, + len(blockComplexities), + peakFeeRate, + m.feeRates, + )) // at peak the total fee for a median complexity tx should be in tens of Avax, no more. fee, err := m.CalculateFee(feesCfg.BlockTargetComplexityRate) @@ -252,10 +225,10 @@ func TestPChainFeeRateIncreaseDueToPeak(t *testing.T) { // OFF PEAK offPeakBlkComplexity := Dimensions{ - feesCfg.BlockTargetComplexityRate[Bandwidth] * 1 / 10, - feesCfg.BlockTargetComplexityRate[UTXORead] * 1 / 10, - feesCfg.BlockTargetComplexityRate[UTXOWrite] * 1 / 10, - feesCfg.BlockTargetComplexityRate[Compute] * 1 / 10, + feesCfg.BlockTargetComplexityRate[Bandwidth] * 99 / 100, + feesCfg.BlockTargetComplexityRate[UTXORead] * 99 / 100, + feesCfg.BlockTargetComplexityRate[UTXOWrite] * 99 / 100, + feesCfg.BlockTargetComplexityRate[Compute] * 99 / 100, } elapsedTime := time.Second parentBlkTime := time.Now().Truncate(time.Second) diff --git a/vms/platformvm/config/dynamic_fees_config.go b/vms/platformvm/config/dynamic_fees_config.go index be55a3110718..1a5ad5b8c36a 100644 --- a/vms/platformvm/config/dynamic_fees_config.go +++ b/vms/platformvm/config/dynamic_fees_config.go @@ -40,10 +40,10 @@ var ( 35 * units.NanoAvax, }, UpdateCoefficient: commonfees.Dimensions{ // over fees.CoeffDenom - 30, - 20, - 25, - 20, + 3, + 2, + 2, + 3, }, BlockMaxComplexity: commonfees.Dimensions{ 10_000, From 86b3e5e704c1d416069e2089d29ea03641a68319 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 15 Apr 2024 15:18:14 +0200 Subject: [PATCH 146/190] repackaged P-chain fork times --- node/node.go | 17 ++-- vms/platformvm/block/builder/helpers_test.go | 15 ++-- vms/platformvm/block/executor/helpers_test.go | 15 ++-- .../block/executor/verifier_test.go | 67 +++++++++++---- vms/platformvm/config/config.go | 44 +--------- vms/platformvm/txs/executor/helpers_test.go | 15 ++-- .../txs/executor/standard_tx_executor_test.go | 15 ++-- vms/platformvm/upgrade/times.go | 50 +++++++++++ vms/platformvm/validator_set_property_test.go | 13 +-- vms/platformvm/vm_regression_test.go | 11 ++- vms/platformvm/vm_test.go | 85 +++++++++++-------- 11 files changed, 214 insertions(+), 133 deletions(-) create mode 100644 vms/platformvm/upgrade/times.go diff --git a/node/node.go b/node/node.go index 58e903404470..a29e275b7666 100644 --- a/node/node.go +++ b/node/node.go @@ -75,6 +75,7 @@ import ( "github.com/ava-labs/avalanchego/vms/avm" "github.com/ava-labs/avalanchego/vms/platformvm" "github.com/ava-labs/avalanchego/vms/platformvm/signer" + "github.com/ava-labs/avalanchego/vms/platformvm/upgrade" "github.com/ava-labs/avalanchego/vms/registry" "github.com/ava-labs/avalanchego/vms/rpcchainvm/runtime" @@ -1149,13 +1150,15 @@ func (n *Node) initVMs() error { MinStakeDuration: n.Config.MinStakeDuration, MaxStakeDuration: n.Config.MaxStakeDuration, RewardConfig: n.Config.RewardConfig, - ApricotPhase3Time: version.GetApricotPhase3Time(n.Config.NetworkID), - ApricotPhase5Time: version.GetApricotPhase5Time(n.Config.NetworkID), - BanffTime: version.GetBanffTime(n.Config.NetworkID), - CortinaTime: version.GetCortinaTime(n.Config.NetworkID), - DurangoTime: version.GetDurangoTime(n.Config.NetworkID), - EUpgradeTime: eUpgradeTime, - UseCurrentHeight: n.Config.UseCurrentHeight, + Times: upgrade.Times{ + ApricotPhase3Time: version.GetApricotPhase3Time(n.Config.NetworkID), + ApricotPhase5Time: version.GetApricotPhase5Time(n.Config.NetworkID), + BanffTime: version.GetBanffTime(n.Config.NetworkID), + CortinaTime: version.GetCortinaTime(n.Config.NetworkID), + DurangoTime: version.GetDurangoTime(n.Config.NetworkID), + EUpgradeTime: eUpgradeTime, + }, + UseCurrentHeight: n.Config.UseCurrentHeight, }, }), n.VMManager.RegisterFactory(context.TODO(), constants.AVMID, &avm.Factory{ diff --git a/vms/platformvm/block/builder/helpers_test.go b/vms/platformvm/block/builder/helpers_test.go index 958ef92ae5c2..c26e0542dcf2 100644 --- a/vms/platformvm/block/builder/helpers_test.go +++ b/vms/platformvm/block/builder/helpers_test.go @@ -45,6 +45,7 @@ import ( "github.com/ava-labs/avalanchego/vms/platformvm/txs" "github.com/ava-labs/avalanchego/vms/platformvm/txs/mempool" "github.com/ava-labs/avalanchego/vms/platformvm/txs/txstest" + "github.com/ava-labs/avalanchego/vms/platformvm/upgrade" "github.com/ava-labs/avalanchego/vms/platformvm/utxo" "github.com/ava-labs/avalanchego/vms/secp256k1fx" @@ -321,12 +322,14 @@ func defaultConfig(t *testing.T, f fork) *config.Config { MintingPeriod: 365 * 24 * time.Hour, SupplyCap: 720 * units.MegaAvax, }, - ApricotPhase3Time: mockable.MaxTime, - ApricotPhase5Time: mockable.MaxTime, - BanffTime: mockable.MaxTime, - CortinaTime: mockable.MaxTime, - DurangoTime: mockable.MaxTime, - EUpgradeTime: mockable.MaxTime, + Times: upgrade.Times{ + ApricotPhase3Time: mockable.MaxTime, + ApricotPhase5Time: mockable.MaxTime, + BanffTime: mockable.MaxTime, + CortinaTime: mockable.MaxTime, + DurangoTime: mockable.MaxTime, + EUpgradeTime: mockable.MaxTime, + }, } switch f { diff --git a/vms/platformvm/block/executor/helpers_test.go b/vms/platformvm/block/executor/helpers_test.go index 0849146afcf6..53949ea791e7 100644 --- a/vms/platformvm/block/executor/helpers_test.go +++ b/vms/platformvm/block/executor/helpers_test.go @@ -46,6 +46,7 @@ import ( "github.com/ava-labs/avalanchego/vms/platformvm/txs/executor" "github.com/ava-labs/avalanchego/vms/platformvm/txs/mempool" "github.com/ava-labs/avalanchego/vms/platformvm/txs/txstest" + "github.com/ava-labs/avalanchego/vms/platformvm/upgrade" "github.com/ava-labs/avalanchego/vms/platformvm/utxo" "github.com/ava-labs/avalanchego/vms/secp256k1fx" @@ -343,12 +344,14 @@ func defaultConfig(t *testing.T, f fork) *config.Config { MintingPeriod: 365 * 24 * time.Hour, SupplyCap: 720 * units.MegaAvax, }, - ApricotPhase3Time: mockable.MaxTime, - ApricotPhase5Time: mockable.MaxTime, - BanffTime: mockable.MaxTime, - CortinaTime: mockable.MaxTime, - DurangoTime: mockable.MaxTime, - EUpgradeTime: mockable.MaxTime, + Times: upgrade.Times{ + ApricotPhase3Time: mockable.MaxTime, + ApricotPhase5Time: mockable.MaxTime, + BanffTime: mockable.MaxTime, + CortinaTime: mockable.MaxTime, + DurangoTime: mockable.MaxTime, + EUpgradeTime: mockable.MaxTime, + }, } switch f { diff --git a/vms/platformvm/block/executor/verifier_test.go b/vms/platformvm/block/executor/verifier_test.go index ba24fb2f1298..c8ea158f9dfa 100644 --- a/vms/platformvm/block/executor/verifier_test.go +++ b/vms/platformvm/block/executor/verifier_test.go @@ -26,6 +26,7 @@ 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/mempool" + "github.com/ava-labs/avalanchego/vms/platformvm/upgrade" ) func TestVerifierVisitProposalBlock(t *testing.T) { @@ -58,7 +59,9 @@ func TestVerifierVisitProposalBlock(t *testing.T) { verifier := &verifier{ txExecutorBackend: &executor.Backend{ Config: &config.Config{ - BanffTime: mockable.MaxTime, // banff is not activated + Times: upgrade.Times{ + BanffTime: mockable.MaxTime, // banff is not activated + }, }, Clk: &mockable.Clock{}, }, @@ -142,8 +145,10 @@ func TestVerifierVisitAtomicBlock(t *testing.T) { verifier := &verifier{ txExecutorBackend: &executor.Backend{ Config: &config.Config{ - ApricotPhase5Time: time.Now().Add(time.Hour), - BanffTime: mockable.MaxTime, // banff is not activated + Times: upgrade.Times{ + ApricotPhase5Time: time.Now().Add(time.Hour), + BanffTime: mockable.MaxTime, // banff is not activated + }, }, Clk: &mockable.Clock{}, }, @@ -229,8 +234,10 @@ func TestVerifierVisitStandardBlock(t *testing.T) { verifier := &verifier{ txExecutorBackend: &executor.Backend{ Config: &config.Config{ - ApricotPhase5Time: time.Now().Add(time.Hour), - BanffTime: mockable.MaxTime, // banff is not activated + Times: upgrade.Times{ + ApricotPhase5Time: time.Now().Add(time.Hour), + BanffTime: mockable.MaxTime, // banff is not activated + }, }, Clk: &mockable.Clock{}, }, @@ -334,7 +341,9 @@ func TestVerifierVisitCommitBlock(t *testing.T) { verifier := &verifier{ txExecutorBackend: &executor.Backend{ Config: &config.Config{ - BanffTime: mockable.MaxTime, // banff is not activated + Times: upgrade.Times{ + BanffTime: mockable.MaxTime, // banff is not activated + }, }, Clk: &mockable.Clock{}, }, @@ -405,7 +414,9 @@ func TestVerifierVisitAbortBlock(t *testing.T) { verifier := &verifier{ txExecutorBackend: &executor.Backend{ Config: &config.Config{ - BanffTime: mockable.MaxTime, // banff is not activated + Times: upgrade.Times{ + BanffTime: mockable.MaxTime, // banff is not activated + }, }, Clk: &mockable.Clock{}, }, @@ -464,7 +475,9 @@ func TestVerifyUnverifiedParent(t *testing.T) { verifier := &verifier{ txExecutorBackend: &executor.Backend{ Config: &config.Config{ - BanffTime: mockable.MaxTime, // banff is not activated + Times: upgrade.Times{ + BanffTime: mockable.MaxTime, // banff is not activated + }, }, Clk: &mockable.Clock{}, }, @@ -536,7 +549,9 @@ func TestBanffAbortBlockTimestampChecks(t *testing.T) { verifier := &verifier{ txExecutorBackend: &executor.Backend{ Config: &config.Config{ - BanffTime: time.Time{}, // banff is activated + Times: upgrade.Times{ + BanffTime: time.Time{}, // banff is activated + }, }, Clk: &mockable.Clock{}, }, @@ -632,7 +647,9 @@ func TestBanffCommitBlockTimestampChecks(t *testing.T) { verifier := &verifier{ txExecutorBackend: &executor.Backend{ Config: &config.Config{ - BanffTime: time.Time{}, // banff is activated + Times: upgrade.Times{ + BanffTime: time.Time{}, // banff is activated + }, }, Clk: &mockable.Clock{}, }, @@ -711,8 +728,10 @@ func TestVerifierVisitStandardBlockWithDuplicateInputs(t *testing.T) { verifier := &verifier{ txExecutorBackend: &executor.Backend{ Config: &config.Config{ - ApricotPhase5Time: time.Now().Add(time.Hour), - BanffTime: mockable.MaxTime, // banff is not activated + Times: upgrade.Times{ + ApricotPhase5Time: time.Now().Add(time.Hour), + BanffTime: mockable.MaxTime, // banff is not activated + }, }, Clk: &mockable.Clock{}, }, @@ -800,7 +819,9 @@ func TestVerifierVisitApricotStandardBlockWithProposalBlockParent(t *testing.T) verifier := &verifier{ txExecutorBackend: &executor.Backend{ Config: &config.Config{ - BanffTime: mockable.MaxTime, // banff is not activated + Times: upgrade.Times{ + BanffTime: mockable.MaxTime, // banff is not activated + }, }, Clk: &mockable.Clock{}, }, @@ -857,7 +878,9 @@ func TestVerifierVisitBanffStandardBlockWithProposalBlockParent(t *testing.T) { verifier := &verifier{ txExecutorBackend: &executor.Backend{ Config: &config.Config{ - BanffTime: time.Time{}, // banff is activated + Times: upgrade.Times{ + BanffTime: time.Time{}, // banff is activated + }, }, Clk: &mockable.Clock{}, }, @@ -894,7 +917,9 @@ func TestVerifierVisitApricotCommitBlockUnexpectedParentState(t *testing.T) { verifier := &verifier{ txExecutorBackend: &executor.Backend{ Config: &config.Config{ - BanffTime: mockable.MaxTime, // banff is not activated + Times: upgrade.Times{ + BanffTime: mockable.MaxTime, // banff is not activated + }, }, Clk: &mockable.Clock{}, }, @@ -937,7 +962,9 @@ func TestVerifierVisitBanffCommitBlockUnexpectedParentState(t *testing.T) { verifier := &verifier{ txExecutorBackend: &executor.Backend{ Config: &config.Config{ - BanffTime: time.Time{}, // banff is activated + Times: upgrade.Times{ + BanffTime: time.Time{}, // banff is activated + }, }, Clk: &mockable.Clock{}, }, @@ -981,7 +1008,9 @@ func TestVerifierVisitApricotAbortBlockUnexpectedParentState(t *testing.T) { verifier := &verifier{ txExecutorBackend: &executor.Backend{ Config: &config.Config{ - BanffTime: mockable.MaxTime, // banff is not activated + Times: upgrade.Times{ + BanffTime: mockable.MaxTime, // banff is not activated + }, }, Clk: &mockable.Clock{}, }, @@ -1024,7 +1053,9 @@ func TestVerifierVisitBanffAbortBlockUnexpectedParentState(t *testing.T) { verifier := &verifier{ txExecutorBackend: &executor.Backend{ Config: &config.Config{ - BanffTime: time.Time{}, // banff is activated + Times: upgrade.Times{ + BanffTime: time.Time{}, // banff is activated + }, }, Clk: &mockable.Clock{}, }, diff --git a/vms/platformvm/config/config.go b/vms/platformvm/config/config.go index 07cb74a8fd18..db3af99154b0 100644 --- a/vms/platformvm/config/config.go +++ b/vms/platformvm/config/config.go @@ -14,6 +14,7 @@ import ( "github.com/ava-labs/avalanchego/utils/set" "github.com/ava-labs/avalanchego/vms/platformvm/reward" "github.com/ava-labs/avalanchego/vms/platformvm/txs" + "github.com/ava-labs/avalanchego/vms/platformvm/upgrade" ) // Struct collecting all foundational parameters of PlatformVM @@ -92,23 +93,8 @@ type Config struct { // Config for the minting function RewardConfig reward.Config - // Time of the AP3 network upgrade - ApricotPhase3Time time.Time - - // Time of the AP5 network upgrade - ApricotPhase5Time time.Time - - // Time of the Banff network upgrade - BanffTime time.Time - - // Time of the Cortina network upgrade - CortinaTime time.Time - - // Time of the Durango network upgrade - DurangoTime time.Time - - // Time of the E network upgrade - EUpgradeTime time.Time + // All network upgrade timestamps + upgrade.Times // UseCurrentHeight forces [GetMinimumHeight] to return the current height // of the P-Chain instead of the oldest block in the [recentlyAccepted] @@ -120,30 +106,6 @@ type Config struct { UseCurrentHeight bool } -func (c *Config) IsApricotPhase3Activated(timestamp time.Time) bool { - return !timestamp.Before(c.ApricotPhase3Time) -} - -func (c *Config) IsApricotPhase5Activated(timestamp time.Time) bool { - return !timestamp.Before(c.ApricotPhase5Time) -} - -func (c *Config) IsBanffActivated(timestamp time.Time) bool { - return !timestamp.Before(c.BanffTime) -} - -func (c *Config) IsCortinaActivated(timestamp time.Time) bool { - return !timestamp.Before(c.CortinaTime) -} - -func (c *Config) IsDurangoActivated(timestamp time.Time) bool { - return !timestamp.Before(c.DurangoTime) -} - -func (c *Config) IsEActivated(timestamp time.Time) bool { - return !timestamp.Before(c.EUpgradeTime) -} - // Create the blockchain described in [tx], but only if this node is a member of // the subnet that validates the chain func (c *Config) CreateChain(chainID ids.ID, tx *txs.CreateChainTx) { diff --git a/vms/platformvm/txs/executor/helpers_test.go b/vms/platformvm/txs/executor/helpers_test.go index 387b5d2a831d..3f738b84f6ea 100644 --- a/vms/platformvm/txs/executor/helpers_test.go +++ b/vms/platformvm/txs/executor/helpers_test.go @@ -42,6 +42,7 @@ import ( "github.com/ava-labs/avalanchego/vms/platformvm/status" "github.com/ava-labs/avalanchego/vms/platformvm/txs" "github.com/ava-labs/avalanchego/vms/platformvm/txs/txstest" + "github.com/ava-labs/avalanchego/vms/platformvm/upgrade" "github.com/ava-labs/avalanchego/vms/platformvm/utxo" "github.com/ava-labs/avalanchego/vms/secp256k1fx" "github.com/ava-labs/avalanchego/wallet/subnet/primary/common" @@ -292,12 +293,14 @@ func defaultConfig(t *testing.T, f fork) *config.Config { MintingPeriod: 365 * 24 * time.Hour, SupplyCap: 720 * units.MegaAvax, }, - ApricotPhase3Time: mockable.MaxTime, - ApricotPhase5Time: mockable.MaxTime, - BanffTime: mockable.MaxTime, - CortinaTime: mockable.MaxTime, - DurangoTime: mockable.MaxTime, - EUpgradeTime: mockable.MaxTime, + Times: upgrade.Times{ + ApricotPhase3Time: mockable.MaxTime, + ApricotPhase5Time: mockable.MaxTime, + BanffTime: mockable.MaxTime, + CortinaTime: mockable.MaxTime, + DurangoTime: mockable.MaxTime, + EUpgradeTime: mockable.MaxTime, + }, } switch f { diff --git a/vms/platformvm/txs/executor/standard_tx_executor_test.go b/vms/platformvm/txs/executor/standard_tx_executor_test.go index 0e274dd85860..0d51555aed72 100644 --- a/vms/platformvm/txs/executor/standard_tx_executor_test.go +++ b/vms/platformvm/txs/executor/standard_tx_executor_test.go @@ -31,6 +31,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/upgrade" "github.com/ava-labs/avalanchego/vms/platformvm/utxo" "github.com/ava-labs/avalanchego/vms/secp256k1fx" "github.com/ava-labs/avalanchego/wallet/subnet/primary/common" @@ -2080,12 +2081,14 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { func defaultTestConfig(t *testing.T, f fork, tm time.Time) *config.Config { c := &config.Config{ - ApricotPhase3Time: mockable.MaxTime, - ApricotPhase5Time: mockable.MaxTime, - BanffTime: mockable.MaxTime, - CortinaTime: mockable.MaxTime, - DurangoTime: mockable.MaxTime, - EUpgradeTime: mockable.MaxTime, + Times: upgrade.Times{ + ApricotPhase3Time: mockable.MaxTime, + ApricotPhase5Time: mockable.MaxTime, + BanffTime: mockable.MaxTime, + CortinaTime: mockable.MaxTime, + DurangoTime: mockable.MaxTime, + EUpgradeTime: mockable.MaxTime, + }, } switch f { diff --git a/vms/platformvm/upgrade/times.go b/vms/platformvm/upgrade/times.go new file mode 100644 index 000000000000..f4c6bacecf9c --- /dev/null +++ b/vms/platformvm/upgrade/times.go @@ -0,0 +1,50 @@ +// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package upgrade + +import "time" + +type Times struct { + // Time of the AP3 network upgrade + ApricotPhase3Time time.Time + + // Time of the AP5 network upgrade + ApricotPhase5Time time.Time + + // Time of the Banff network upgrade + BanffTime time.Time + + // Time of the Cortina network upgrade + CortinaTime time.Time + + // Time of the Durango network upgrade + DurangoTime time.Time + + // Time of the E network upgrade + EUpgradeTime time.Time +} + +func (t *Times) IsApricotPhase3Activated(timestamp time.Time) bool { + return !timestamp.Before(t.ApricotPhase3Time) +} + +func (t *Times) IsApricotPhase5Activated(timestamp time.Time) bool { + return !timestamp.Before(t.ApricotPhase5Time) +} + +func (t *Times) IsBanffActivated(timestamp time.Time) bool { + return !timestamp.Before(t.BanffTime) +} + +func (t *Times) IsCortinaActivated(timestamp time.Time) bool { + return !timestamp.Before(t.CortinaTime) +} + +func (t *Times) IsDurangoActivated(timestamp time.Time) bool { + return !timestamp.Before(t.DurangoTime) +} + +func (t *Times) IsEActivated(timestamp time.Time) bool { + return !timestamp.Before(t.EUpgradeTime) +} diff --git a/vms/platformvm/validator_set_property_test.go b/vms/platformvm/validator_set_property_test.go index 9effc6fbeeb2..162a02a70887 100644 --- a/vms/platformvm/validator_set_property_test.go +++ b/vms/platformvm/validator_set_property_test.go @@ -44,6 +44,7 @@ import ( "github.com/ava-labs/avalanchego/vms/platformvm/state" "github.com/ava-labs/avalanchego/vms/platformvm/txs" "github.com/ava-labs/avalanchego/vms/platformvm/txs/txstest" + "github.com/ava-labs/avalanchego/vms/platformvm/upgrade" "github.com/ava-labs/avalanchego/vms/secp256k1fx" blockexecutor "github.com/ava-labs/avalanchego/vms/platformvm/block/executor" @@ -661,11 +662,13 @@ func buildVM(t *testing.T) (*VM, ids.ID, error) { MinStakeDuration: defaultMinStakingDuration, MaxStakeDuration: defaultMaxStakingDuration, RewardConfig: defaultRewardConfig, - ApricotPhase3Time: forkTime, - ApricotPhase5Time: forkTime, - BanffTime: forkTime, - CortinaTime: forkTime, - EUpgradeTime: mockable.MaxTime, + Times: upgrade.Times{ + ApricotPhase3Time: forkTime, + ApricotPhase5Time: forkTime, + BanffTime: forkTime, + CortinaTime: forkTime, + EUpgradeTime: mockable.MaxTime, + }, }} vm.clock.Set(forkTime.Add(time.Second)) diff --git a/vms/platformvm/vm_regression_test.go b/vms/platformvm/vm_regression_test.go index 0218e115521d..bbab930cbe96 100644 --- a/vms/platformvm/vm_regression_test.go +++ b/vms/platformvm/vm_regression_test.go @@ -45,6 +45,7 @@ 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/txstest" + "github.com/ava-labs/avalanchego/vms/platformvm/upgrade" "github.com/ava-labs/avalanchego/vms/secp256k1fx" blockexecutor "github.com/ava-labs/avalanchego/vms/platformvm/block/executor" @@ -442,10 +443,12 @@ func TestUnverifiedParentPanicRegression(t *testing.T) { MinStakeDuration: defaultMinStakingDuration, MaxStakeDuration: defaultMaxStakingDuration, RewardConfig: defaultRewardConfig, - BanffTime: latestForkTime, - CortinaTime: mockable.MaxTime, - DurangoTime: mockable.MaxTime, - EUpgradeTime: mockable.MaxTime, + Times: upgrade.Times{ + BanffTime: latestForkTime, + CortinaTime: mockable.MaxTime, + DurangoTime: mockable.MaxTime, + EUpgradeTime: mockable.MaxTime, + }, }} ctx := snowtest.Context(t, snowtest.PChainID) diff --git a/vms/platformvm/vm_test.go b/vms/platformvm/vm_test.go index 479788b47097..e2fa50d121e8 100644 --- a/vms/platformvm/vm_test.go +++ b/vms/platformvm/vm_test.go @@ -58,6 +58,7 @@ import ( "github.com/ava-labs/avalanchego/vms/platformvm/status" "github.com/ava-labs/avalanchego/vms/platformvm/txs" "github.com/ava-labs/avalanchego/vms/platformvm/txs/txstest" + "github.com/ava-labs/avalanchego/vms/platformvm/upgrade" "github.com/ava-labs/avalanchego/vms/secp256k1fx" p2ppb "github.com/ava-labs/avalanchego/proto/pb/p2p" @@ -254,12 +255,14 @@ func defaultVM(t *testing.T, f fork) (*VM, *txstest.Builder, database.Database, MinStakeDuration: defaultMinStakingDuration, MaxStakeDuration: defaultMaxStakingDuration, RewardConfig: defaultRewardConfig, - ApricotPhase3Time: apricotPhase3Time, - ApricotPhase5Time: apricotPhase5Time, - BanffTime: banffTime, - CortinaTime: cortinaTime, - DurangoTime: durangoTime, - EUpgradeTime: eUpgradeTime, + Times: upgrade.Times{ + ApricotPhase3Time: apricotPhase3Time, + ApricotPhase5Time: apricotPhase5Time, + BanffTime: banffTime, + CortinaTime: cortinaTime, + DurangoTime: durangoTime, + EUpgradeTime: eUpgradeTime, + }, }} db := memdb.New() @@ -1178,10 +1181,12 @@ func TestRestartFullyAccepted(t *testing.T) { MinStakeDuration: defaultMinStakingDuration, MaxStakeDuration: defaultMaxStakingDuration, RewardConfig: defaultRewardConfig, - BanffTime: latestForkTime, - CortinaTime: latestForkTime, - DurangoTime: latestForkTime, - EUpgradeTime: mockable.MaxTime, + Times: upgrade.Times{ + BanffTime: latestForkTime, + CortinaTime: latestForkTime, + DurangoTime: latestForkTime, + EUpgradeTime: mockable.MaxTime, + }, }} firstCtx := snowtest.Context(t, snowtest.PChainID) @@ -1266,10 +1271,12 @@ func TestRestartFullyAccepted(t *testing.T) { MinStakeDuration: defaultMinStakingDuration, MaxStakeDuration: defaultMaxStakingDuration, RewardConfig: defaultRewardConfig, - BanffTime: latestForkTime, - CortinaTime: latestForkTime, - DurangoTime: latestForkTime, - EUpgradeTime: mockable.MaxTime, + Times: upgrade.Times{ + BanffTime: latestForkTime, + CortinaTime: latestForkTime, + DurangoTime: latestForkTime, + EUpgradeTime: mockable.MaxTime, + }, }} secondCtx := snowtest.Context(t, snowtest.PChainID) @@ -1315,10 +1322,12 @@ func TestBootstrapPartiallyAccepted(t *testing.T) { MinStakeDuration: defaultMinStakingDuration, MaxStakeDuration: defaultMaxStakingDuration, RewardConfig: defaultRewardConfig, - BanffTime: latestForkTime, - CortinaTime: latestForkTime, - DurangoTime: latestForkTime, - EUpgradeTime: mockable.MaxTime, + Times: upgrade.Times{ + BanffTime: latestForkTime, + CortinaTime: latestForkTime, + DurangoTime: latestForkTime, + EUpgradeTime: mockable.MaxTime, + }, }} initialClkTime := latestForkTime.Add(time.Second) @@ -1663,10 +1672,12 @@ func TestUnverifiedParent(t *testing.T) { MinStakeDuration: defaultMinStakingDuration, MaxStakeDuration: defaultMaxStakingDuration, RewardConfig: defaultRewardConfig, - BanffTime: latestForkTime, - CortinaTime: latestForkTime, - DurangoTime: latestForkTime, - EUpgradeTime: mockable.MaxTime, + Times: upgrade.Times{ + BanffTime: latestForkTime, + CortinaTime: latestForkTime, + DurangoTime: latestForkTime, + EUpgradeTime: mockable.MaxTime, + }, }} initialClkTime := latestForkTime.Add(time.Second) @@ -1824,10 +1835,12 @@ func TestUptimeDisallowedWithRestart(t *testing.T) { RewardConfig: defaultRewardConfig, Validators: validators.NewManager(), UptimeLockedCalculator: uptime.NewLockedCalculator(), - BanffTime: latestForkTime, - CortinaTime: latestForkTime, - DurangoTime: latestForkTime, - EUpgradeTime: mockable.MaxTime, + Times: upgrade.Times{ + BanffTime: latestForkTime, + CortinaTime: latestForkTime, + DurangoTime: latestForkTime, + EUpgradeTime: mockable.MaxTime, + }, }} firstCtx := snowtest.Context(t, snowtest.PChainID) @@ -1873,10 +1886,12 @@ func TestUptimeDisallowedWithRestart(t *testing.T) { UptimePercentage: secondUptimePercentage / 100., Validators: validators.NewManager(), UptimeLockedCalculator: uptime.NewLockedCalculator(), - BanffTime: latestForkTime, - CortinaTime: latestForkTime, - DurangoTime: latestForkTime, - EUpgradeTime: mockable.MaxTime, + Times: upgrade.Times{ + BanffTime: latestForkTime, + CortinaTime: latestForkTime, + DurangoTime: latestForkTime, + EUpgradeTime: mockable.MaxTime, + }, }} secondCtx := snowtest.Context(t, snowtest.PChainID) @@ -1973,10 +1988,12 @@ func TestUptimeDisallowedAfterNeverConnecting(t *testing.T) { RewardConfig: defaultRewardConfig, Validators: validators.NewManager(), UptimeLockedCalculator: uptime.NewLockedCalculator(), - BanffTime: latestForkTime, - CortinaTime: latestForkTime, - DurangoTime: latestForkTime, - EUpgradeTime: mockable.MaxTime, + Times: upgrade.Times{ + BanffTime: latestForkTime, + CortinaTime: latestForkTime, + DurangoTime: latestForkTime, + EUpgradeTime: mockable.MaxTime, + }, }} ctx := snowtest.Context(t, snowtest.PChainID) From 059384d7be2644c31e1b610ad1bb77f200a80bf2 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Tue, 23 Apr 2024 11:11:36 +0200 Subject: [PATCH 147/190] moved static configs to fee package Signed-off-by: Alberto Benegiamo --- node/node.go | 49 ++-- vms/platformvm/block/builder/helpers_test.go | 19 +- vms/platformvm/block/executor/helpers_test.go | 19 +- vms/platformvm/config/config.go | 28 +- vms/platformvm/service_test.go | 6 +- vms/platformvm/txs/executor/helpers_test.go | 19 +- .../txs/executor/staker_tx_verification.go | 43 ++- .../txs/executor/standard_tx_executor.go | 38 ++- .../txs/executor/standard_tx_executor_test.go | 4 +- vms/platformvm/txs/fee/calculator.go | 48 ++-- vms/platformvm/txs/fee/calculator_test.go | 257 ++++++++++-------- vms/platformvm/txs/fee/config.go | 45 +++ vms/platformvm/txs/txstest/context.go | 16 +- vms/platformvm/validator_set_property_test.go | 23 +- vms/platformvm/vm_test.go | 23 +- 15 files changed, 376 insertions(+), 261 deletions(-) create mode 100644 vms/platformvm/txs/fee/config.go diff --git a/node/node.go b/node/node.go index a29e275b7666..fd5781c9490c 100644 --- a/node/node.go +++ b/node/node.go @@ -75,6 +75,7 @@ import ( "github.com/ava-labs/avalanchego/vms/avm" "github.com/ava-labs/avalanchego/vms/platformvm" "github.com/ava-labs/avalanchego/vms/platformvm/signer" + "github.com/ava-labs/avalanchego/vms/platformvm/txs/fee" "github.com/ava-labs/avalanchego/vms/platformvm/upgrade" "github.com/ava-labs/avalanchego/vms/registry" "github.com/ava-labs/avalanchego/vms/rpcchainvm/runtime" @@ -1127,29 +1128,31 @@ func (n *Node) initVMs() error { err := utils.Err( n.VMManager.RegisterFactory(context.TODO(), constants.PlatformVMID, &platformvm.Factory{ Config: platformconfig.Config{ - Chains: n.chainManager, - Validators: vdrs, - UptimeLockedCalculator: n.uptimeCalculator, - SybilProtectionEnabled: n.Config.SybilProtectionEnabled, - PartialSyncPrimaryNetwork: n.Config.PartialSyncPrimaryNetwork, - TrackedSubnets: n.Config.TrackedSubnets, - TxFee: n.Config.TxFee, - CreateAssetTxFee: n.Config.CreateAssetTxFee, - CreateSubnetTxFee: n.Config.CreateSubnetTxFee, - TransformSubnetTxFee: n.Config.TransformSubnetTxFee, - CreateBlockchainTxFee: n.Config.CreateBlockchainTxFee, - AddPrimaryNetworkValidatorFee: n.Config.AddPrimaryNetworkValidatorFee, - AddPrimaryNetworkDelegatorFee: n.Config.AddPrimaryNetworkDelegatorFee, - AddSubnetValidatorFee: n.Config.AddSubnetValidatorFee, - AddSubnetDelegatorFee: n.Config.AddSubnetDelegatorFee, - UptimePercentage: n.Config.UptimeRequirement, - MinValidatorStake: n.Config.MinValidatorStake, - MaxValidatorStake: n.Config.MaxValidatorStake, - MinDelegatorStake: n.Config.MinDelegatorStake, - MinDelegationFee: n.Config.MinDelegationFee, - MinStakeDuration: n.Config.MinStakeDuration, - MaxStakeDuration: n.Config.MaxStakeDuration, - RewardConfig: n.Config.RewardConfig, + Chains: n.chainManager, + Validators: vdrs, + UptimeLockedCalculator: n.uptimeCalculator, + SybilProtectionEnabled: n.Config.SybilProtectionEnabled, + PartialSyncPrimaryNetwork: n.Config.PartialSyncPrimaryNetwork, + TrackedSubnets: n.Config.TrackedSubnets, + StaticConfig: fee.StaticConfig{ + TxFee: n.Config.TxFee, + CreateAssetTxFee: n.Config.CreateAssetTxFee, + CreateSubnetTxFee: n.Config.CreateSubnetTxFee, + TransformSubnetTxFee: n.Config.TransformSubnetTxFee, + CreateBlockchainTxFee: n.Config.CreateBlockchainTxFee, + AddPrimaryNetworkValidatorFee: n.Config.AddPrimaryNetworkValidatorFee, + AddPrimaryNetworkDelegatorFee: n.Config.AddPrimaryNetworkDelegatorFee, + AddSubnetValidatorFee: n.Config.AddSubnetValidatorFee, + AddSubnetDelegatorFee: n.Config.AddSubnetDelegatorFee, + }, + UptimePercentage: n.Config.UptimeRequirement, + MinValidatorStake: n.Config.MinValidatorStake, + MaxValidatorStake: n.Config.MaxValidatorStake, + MinDelegatorStake: n.Config.MinDelegatorStake, + MinDelegationFee: n.Config.MinDelegationFee, + MinStakeDuration: n.Config.MinStakeDuration, + MaxStakeDuration: n.Config.MaxStakeDuration, + RewardConfig: n.Config.RewardConfig, Times: upgrade.Times{ ApricotPhase3Time: version.GetApricotPhase3Time(n.Config.NetworkID), ApricotPhase5Time: version.GetApricotPhase5Time(n.Config.NetworkID), diff --git a/vms/platformvm/block/builder/helpers_test.go b/vms/platformvm/block/builder/helpers_test.go index c26e0542dcf2..46f1731f6efe 100644 --- a/vms/platformvm/block/builder/helpers_test.go +++ b/vms/platformvm/block/builder/helpers_test.go @@ -43,6 +43,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/platformvm/txs/mempool" "github.com/ava-labs/avalanchego/vms/platformvm/txs/txstest" "github.com/ava-labs/avalanchego/vms/platformvm/upgrade" @@ -308,14 +309,16 @@ func defaultConfig(t *testing.T, f fork) *config.Config { Chains: chains.TestManager, UptimeLockedCalculator: uptime.NewLockedCalculator(), Validators: validators.NewManager(), - TxFee: defaultTxFee, - CreateSubnetTxFee: 100 * defaultTxFee, - CreateBlockchainTxFee: 100 * defaultTxFee, - MinValidatorStake: 5 * units.MilliAvax, - MaxValidatorStake: 500 * units.MilliAvax, - MinDelegatorStake: 1 * units.MilliAvax, - MinStakeDuration: defaultMinStakingDuration, - MaxStakeDuration: defaultMaxStakingDuration, + StaticConfig: fee.StaticConfig{ + TxFee: defaultTxFee, + CreateSubnetTxFee: 100 * defaultTxFee, + CreateBlockchainTxFee: 100 * defaultTxFee, + }, + MinValidatorStake: 5 * units.MilliAvax, + MaxValidatorStake: 500 * units.MilliAvax, + MinDelegatorStake: 1 * units.MilliAvax, + MinStakeDuration: defaultMinStakingDuration, + MaxStakeDuration: defaultMaxStakingDuration, RewardConfig: reward.Config{ MaxConsumptionRate: .12 * reward.PercentDenominator, MinConsumptionRate: .10 * reward.PercentDenominator, diff --git a/vms/platformvm/block/executor/helpers_test.go b/vms/platformvm/block/executor/helpers_test.go index 53949ea791e7..bf17dcc84dd1 100644 --- a/vms/platformvm/block/executor/helpers_test.go +++ b/vms/platformvm/block/executor/helpers_test.go @@ -44,6 +44,7 @@ import ( "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/txs/txstest" "github.com/ava-labs/avalanchego/vms/platformvm/upgrade" @@ -330,14 +331,16 @@ func defaultConfig(t *testing.T, f fork) *config.Config { Chains: chains.TestManager, UptimeLockedCalculator: uptime.NewLockedCalculator(), Validators: validators.NewManager(), - TxFee: defaultTxFee, - CreateSubnetTxFee: 100 * defaultTxFee, - CreateBlockchainTxFee: 100 * defaultTxFee, - MinValidatorStake: 5 * units.MilliAvax, - MaxValidatorStake: 500 * units.MilliAvax, - MinDelegatorStake: 1 * units.MilliAvax, - MinStakeDuration: defaultMinStakingDuration, - MaxStakeDuration: defaultMaxStakingDuration, + StaticConfig: fee.StaticConfig{ + TxFee: defaultTxFee, + CreateSubnetTxFee: 100 * defaultTxFee, + CreateBlockchainTxFee: 100 * defaultTxFee, + }, + MinValidatorStake: 5 * units.MilliAvax, + MaxValidatorStake: 500 * units.MilliAvax, + MinDelegatorStake: 1 * units.MilliAvax, + MinStakeDuration: defaultMinStakingDuration, + MaxStakeDuration: defaultMaxStakingDuration, RewardConfig: reward.Config{ MaxConsumptionRate: .12 * reward.PercentDenominator, MinConsumptionRate: .10 * reward.PercentDenominator, diff --git a/vms/platformvm/config/config.go b/vms/platformvm/config/config.go index db3af99154b0..ed7ab7945ec7 100644 --- a/vms/platformvm/config/config.go +++ b/vms/platformvm/config/config.go @@ -14,6 +14,7 @@ import ( "github.com/ava-labs/avalanchego/utils/set" "github.com/ava-labs/avalanchego/vms/platformvm/reward" "github.com/ava-labs/avalanchego/vms/platformvm/txs" + "github.com/ava-labs/avalanchego/vms/platformvm/txs/fee" "github.com/ava-labs/avalanchego/vms/platformvm/upgrade" ) @@ -42,32 +43,7 @@ type Config struct { // Set of subnets that this node is validating TrackedSubnets set.Set[ids.ID] - // Fee that is burned by every non-state creating transaction - TxFee uint64 - - // Fee that must be burned by every state creating transaction before AP3 - CreateAssetTxFee uint64 - - // Fee that must be burned by every subnet creating transaction after AP3 - CreateSubnetTxFee uint64 - - // Fee that must be burned by every transform subnet transaction - TransformSubnetTxFee uint64 - - // Fee that must be burned by every blockchain creating transaction after AP3 - CreateBlockchainTxFee uint64 - - // Transaction fee for adding a primary network validator - AddPrimaryNetworkValidatorFee uint64 - - // Transaction fee for adding a primary network delegator - AddPrimaryNetworkDelegatorFee uint64 - - // Transaction fee for adding a subnet validator - AddSubnetValidatorFee uint64 - - // Transaction fee for adding a subnet delegator - AddSubnetDelegatorFee uint64 + fee.StaticConfig // The minimum amount of tokens one must bond to be a validator MinValidatorStake uint64 diff --git a/vms/platformvm/service_test.go b/vms/platformvm/service_test.go index 3224edb2d73d..e36e06e29d4d 100644 --- a/vms/platformvm/service_test.go +++ b/vms/platformvm/service_test.go @@ -366,7 +366,9 @@ func TestGetBalance(t *testing.T) { require := require.New(t) service, _, _ := defaultService(t) - staticFeeCalc := fee.NewStaticCalculator(&service.vm.Config, service.vm.clock.Time()) + staticFeeCfg := service.vm.Config.StaticConfig + upgrades := service.vm.Config.Times + staticFeeCalc := fee.NewStaticCalculator(staticFeeCfg, upgrades, service.vm.clock.Time()) dummyCreateSubnetTx := &txs.CreateSubnetTx{} require.NoError(dummyCreateSubnetTx.Visit(staticFeeCalc)) createSubnetFee := staticFeeCalc.Fee @@ -755,7 +757,7 @@ func TestGetBlock(t *testing.T) { service, _, txBuilder := defaultService(t) service.vm.ctx.Lock.Lock() - service.vm.Config.CreateAssetTxFee = 100 * defaultTxFee + service.vm.CreateAssetTxFee = 100 * defaultTxFee // Make a block an accept it, then check we can get it. tx, err := txBuilder.NewCreateChainTx( // Test GetTx works for standard blocks diff --git a/vms/platformvm/txs/executor/helpers_test.go b/vms/platformvm/txs/executor/helpers_test.go index 3f738b84f6ea..c14dbe9c459c 100644 --- a/vms/platformvm/txs/executor/helpers_test.go +++ b/vms/platformvm/txs/executor/helpers_test.go @@ -41,6 +41,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/platformvm/txs/txstest" "github.com/ava-labs/avalanchego/vms/platformvm/upgrade" "github.com/ava-labs/avalanchego/vms/platformvm/utxo" @@ -279,14 +280,16 @@ func defaultConfig(t *testing.T, f fork) *config.Config { Chains: chains.TestManager, UptimeLockedCalculator: uptime.NewLockedCalculator(), Validators: validators.NewManager(), - TxFee: defaultTxFee, - CreateSubnetTxFee: 100 * defaultTxFee, - CreateBlockchainTxFee: 100 * defaultTxFee, - MinValidatorStake: 5 * units.MilliAvax, - MaxValidatorStake: 500 * units.MilliAvax, - MinDelegatorStake: 1 * units.MilliAvax, - MinStakeDuration: defaultMinStakingDuration, - MaxStakeDuration: defaultMaxStakingDuration, + StaticConfig: fee.StaticConfig{ + TxFee: defaultTxFee, + CreateSubnetTxFee: 100 * defaultTxFee, + CreateBlockchainTxFee: 100 * defaultTxFee, + }, + MinValidatorStake: 5 * units.MilliAvax, + MaxValidatorStake: 500 * units.MilliAvax, + MinDelegatorStake: 1 * units.MilliAvax, + MinStakeDuration: defaultMinStakingDuration, + MaxStakeDuration: defaultMaxStakingDuration, RewardConfig: reward.Config{ MaxConsumptionRate: .12 * reward.PercentDenominator, MinConsumptionRate: .10 * reward.PercentDenominator, diff --git a/vms/platformvm/txs/executor/staker_tx_verification.go b/vms/platformvm/txs/executor/staker_tx_verification.go index 86cf4b179985..6a235a0fa011 100644 --- a/vms/platformvm/txs/executor/staker_tx_verification.go +++ b/vms/platformvm/txs/executor/staker_tx_verification.go @@ -164,7 +164,11 @@ func verifyAddValidatorTx( } // Verify the flowcheck - feeCalculator := fee.NewStaticCalculator(backend.Config, currentTimestamp) + var ( + staticFeesCfg = backend.Config.StaticConfig + upgrades = backend.Config.Times + ) + feeCalculator := fee.NewStaticCalculator(staticFeesCfg, upgrades, currentTimestamp) if err := tx.Visit(feeCalculator); err != nil { return nil, err } @@ -257,7 +261,11 @@ func verifyAddSubnetValidatorTx( } // Verify the flowcheck - feeCalculator := fee.NewStaticCalculator(backend.Config, currentTimestamp) + var ( + staticFeesCfg = backend.Config.StaticConfig + upgrades = backend.Config.Times + ) + feeCalculator := fee.NewStaticCalculator(staticFeesCfg, upgrades, currentTimestamp) if err := tx.Visit(feeCalculator); err != nil { return err } @@ -337,7 +345,11 @@ func verifyRemoveSubnetValidatorTx( } // Verify the flowcheck - feeCalculator := fee.NewStaticCalculator(backend.Config, chainState.GetTimestamp()) + var ( + staticFeesCfg = backend.Config.StaticConfig + upgrades = backend.Config.Times + ) + feeCalculator := fee.NewStaticCalculator(staticFeesCfg, upgrades, currentTimestamp) if err := tx.Visit(feeCalculator); err != nil { return nil, false, err } @@ -457,7 +469,11 @@ func verifyAddDelegatorTx( } // Verify the flowcheck - feeCalculator := fee.NewStaticCalculator(backend.Config, chainState.GetTimestamp()) + var ( + staticFeesCfg = backend.Config.StaticConfig + upgrades = backend.Config.Times + ) + feeCalculator := fee.NewStaticCalculator(staticFeesCfg, upgrades, currentTimestamp) if err := tx.Visit(feeCalculator); err != nil { return nil, err } @@ -579,7 +595,11 @@ func verifyAddPermissionlessValidatorTx( copy(outs[len(tx.Outs):], tx.StakeOuts) // Verify the flowcheck - feeCalculator := fee.NewStaticCalculator(backend.Config, currentTimestamp) + var ( + staticFeesCfg = backend.Config.StaticConfig + upgrades = backend.Config.Times + ) + feeCalculator := fee.NewStaticCalculator(staticFeesCfg, upgrades, currentTimestamp) if err := tx.Visit(feeCalculator); err != nil { return err } @@ -726,7 +746,11 @@ func verifyAddPermissionlessDelegatorTx( } // Verify the flowcheck - feeCalculator := fee.NewStaticCalculator(backend.Config, currentTimestamp) + var ( + staticFeesCfg = backend.Config.StaticConfig + upgrades = backend.Config.Times + ) + feeCalculator := fee.NewStaticCalculator(staticFeesCfg, upgrades, currentTimestamp) if err := tx.Visit(feeCalculator); err != nil { return err } @@ -783,7 +807,12 @@ func verifyTransferSubnetOwnershipTx( } // Verify the flowcheck - feeCalculator := fee.NewStaticCalculator(backend.Config, chainState.GetTimestamp()) + var ( + staticFeesCfg = backend.Config.StaticConfig + upgrades = backend.Config.Times + currentTimestamp = chainState.GetTimestamp() + ) + feeCalculator := fee.NewStaticCalculator(staticFeesCfg, upgrades, currentTimestamp) if err := tx.Visit(feeCalculator); err != nil { return err } diff --git a/vms/platformvm/txs/executor/standard_tx_executor.go b/vms/platformvm/txs/executor/standard_tx_executor.go index 8cbc0a58cd5a..487420e1142a 100644 --- a/vms/platformvm/txs/executor/standard_tx_executor.go +++ b/vms/platformvm/txs/executor/standard_tx_executor.go @@ -69,7 +69,11 @@ func (e *StandardTxExecutor) CreateChainTx(tx *txs.CreateChainTx) error { } // Verify the flowcheck - feeCalculator := fee.NewStaticCalculator(e.Backend.Config, e.State.GetTimestamp()) + var ( + staticFeesCfg = e.Backend.Config.StaticConfig + upgrades = e.Backend.Config.Times + ) + feeCalculator := fee.NewStaticCalculator(staticFeesCfg, upgrades, currentTimestamp) if err := tx.Visit(feeCalculator); err != nil { return err } @@ -119,7 +123,11 @@ func (e *StandardTxExecutor) CreateSubnetTx(tx *txs.CreateSubnetTx) error { } // Verify the flowcheck - feeCalculator := fee.NewStaticCalculator(e.Backend.Config, e.State.GetTimestamp()) + var ( + staticFeesCfg = e.Backend.Config.StaticConfig + upgrades = e.Backend.Config.Times + ) + feeCalculator := fee.NewStaticCalculator(staticFeesCfg, upgrades, currentTimestamp) if err := tx.Visit(feeCalculator); err != nil { return err } @@ -204,7 +212,11 @@ func (e *StandardTxExecutor) ImportTx(tx *txs.ImportTx) error { copy(ins[len(tx.Ins):], tx.ImportedInputs) // Verify the flowcheck - feeCalculator := fee.NewStaticCalculator(e.Backend.Config, e.State.GetTimestamp()) + var ( + staticFeesCfg = e.Backend.Config.StaticConfig + upgrades = e.Backend.Config.Times + ) + feeCalculator := fee.NewStaticCalculator(staticFeesCfg, upgrades, currentTimestamp) if err := tx.Visit(feeCalculator); err != nil { return err } @@ -265,7 +277,11 @@ func (e *StandardTxExecutor) ExportTx(tx *txs.ExportTx) error { } // Verify the flowcheck - feeCalculator := fee.NewStaticCalculator(e.Backend.Config, e.State.GetTimestamp()) + var ( + staticFeesCfg = e.Backend.Config.StaticConfig + upgrades = e.Backend.Config.Times + ) + feeCalculator := fee.NewStaticCalculator(staticFeesCfg, upgrades, currentTimestamp) if err := tx.Visit(feeCalculator); err != nil { return err } @@ -455,11 +471,16 @@ func (e *StandardTxExecutor) TransformSubnetTx(tx *txs.TransformSubnetTx) error return err } - totalRewardAmount := tx.MaximumSupply - tx.InitialSupply - feeCalculator := fee.NewStaticCalculator(e.Backend.Config, currentTimestamp) + var ( + staticFeesCfg = e.Backend.Config.StaticConfig + upgrades = e.Backend.Config.Times + ) + feeCalculator := fee.NewStaticCalculator(staticFeesCfg, upgrades, currentTimestamp) if err := tx.Visit(feeCalculator); err != nil { return err } + + totalRewardAmount := tx.MaximumSupply - tx.InitialSupply if err := e.Backend.FlowChecker.VerifySpend( tx, e.State, @@ -580,10 +601,11 @@ func (e *StandardTxExecutor) BaseTx(tx *txs.BaseTx) error { // Verify the flowcheck var ( - cfg = e.Backend.Config + staticFeesCfg = e.Backend.Config.StaticConfig + upgrades = e.Backend.Config.Times currentTimestamp = e.State.GetTimestamp() ) - feeCalculator := fee.NewStaticCalculator(cfg, currentTimestamp) + feeCalculator := fee.NewStaticCalculator(staticFeesCfg, upgrades, currentTimestamp) if err := tx.Visit(feeCalculator); err != nil { return err } diff --git a/vms/platformvm/txs/executor/standard_tx_executor_test.go b/vms/platformvm/txs/executor/standard_tx_executor_test.go index 0d51555aed72..8463645a624a 100644 --- a/vms/platformvm/txs/executor/standard_tx_executor_test.go +++ b/vms/platformvm/txs/executor/standard_tx_executor_test.go @@ -1586,7 +1586,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { env := newValidRemoveSubnetValidatorTxVerifyEnv(t, ctrl) // Set dependency expectations. - env.state.EXPECT().GetTimestamp().Return(env.latestForkTime).Times(2) + env.state.EXPECT().GetTimestamp().Return(env.latestForkTime) env.state.EXPECT().GetCurrentValidator(env.unsignedTx.Subnet, env.unsignedTx.NodeID).Return(env.staker, nil).Times(1) subnetOwner := fx.NewMockOwner(ctrl) env.state.EXPECT().GetSubnetOwner(env.unsignedTx.Subnet).Return(subnetOwner, nil).Times(1) @@ -1767,7 +1767,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { newExecutor: func(ctrl *gomock.Controller) (*txs.RemoveSubnetValidatorTx, *StandardTxExecutor) { env := newValidRemoveSubnetValidatorTxVerifyEnv(t, ctrl) env.state = state.NewMockDiff(ctrl) - env.state.EXPECT().GetTimestamp().Return(env.latestForkTime).Times(2) + env.state.EXPECT().GetTimestamp().Return(env.latestForkTime) env.state.EXPECT().GetCurrentValidator(env.unsignedTx.Subnet, env.unsignedTx.NodeID).Return(env.staker, nil) subnetOwner := fx.NewMockOwner(ctrl) env.state.EXPECT().GetSubnetOwner(env.unsignedTx.Subnet).Return(subnetOwner, nil) diff --git a/vms/platformvm/txs/fee/calculator.go b/vms/platformvm/txs/fee/calculator.go index 038cbdc7ebf5..153b85458a09 100644 --- a/vms/platformvm/txs/fee/calculator.go +++ b/vms/platformvm/txs/fee/calculator.go @@ -7,57 +7,59 @@ import ( "time" "github.com/ava-labs/avalanchego/utils/constants" - "github.com/ava-labs/avalanchego/vms/platformvm/config" "github.com/ava-labs/avalanchego/vms/platformvm/txs" + "github.com/ava-labs/avalanchego/vms/platformvm/upgrade" ) var _ txs.Visitor = (*Calculator)(nil) type Calculator struct { // Pre E-fork inputs - config *config.Config + upgrades upgrade.Times + staticCfg StaticConfig chainTime time.Time // outputs of visitor execution Fee uint64 } -func NewStaticCalculator(cfg *config.Config, chainTime time.Time) *Calculator { +func NewStaticCalculator(cfg StaticConfig, ut upgrade.Times, chainTime time.Time) *Calculator { return &Calculator{ - config: cfg, + upgrades: ut, + staticCfg: cfg, chainTime: chainTime, } } func (fc *Calculator) AddValidatorTx(*txs.AddValidatorTx) error { - fc.Fee = fc.config.AddPrimaryNetworkValidatorFee + fc.Fee = fc.staticCfg.AddPrimaryNetworkValidatorFee return nil } func (fc *Calculator) AddSubnetValidatorTx(*txs.AddSubnetValidatorTx) error { - fc.Fee = fc.config.AddSubnetValidatorFee + fc.Fee = fc.staticCfg.AddSubnetValidatorFee return nil } func (fc *Calculator) AddDelegatorTx(*txs.AddDelegatorTx) error { - fc.Fee = fc.config.AddPrimaryNetworkDelegatorFee + fc.Fee = fc.staticCfg.AddPrimaryNetworkDelegatorFee return nil } func (fc *Calculator) CreateChainTx(*txs.CreateChainTx) error { - if fc.config.IsApricotPhase3Activated(fc.chainTime) { - fc.Fee = fc.config.CreateBlockchainTxFee + if fc.upgrades.IsApricotPhase3Activated(fc.chainTime) { + fc.Fee = fc.staticCfg.CreateBlockchainTxFee } else { - fc.Fee = fc.config.CreateAssetTxFee + fc.Fee = fc.staticCfg.CreateAssetTxFee } return nil } func (fc *Calculator) CreateSubnetTx(*txs.CreateSubnetTx) error { - if fc.config.IsApricotPhase3Activated(fc.chainTime) { - fc.Fee = fc.config.CreateSubnetTxFee + if fc.upgrades.IsApricotPhase3Activated(fc.chainTime) { + fc.Fee = fc.staticCfg.CreateSubnetTxFee } else { - fc.Fee = fc.config.CreateAssetTxFee + fc.Fee = fc.staticCfg.CreateAssetTxFee } return nil } @@ -71,49 +73,49 @@ func (*Calculator) RewardValidatorTx(*txs.RewardValidatorTx) error { } func (fc *Calculator) RemoveSubnetValidatorTx(*txs.RemoveSubnetValidatorTx) error { - fc.Fee = fc.config.TxFee + fc.Fee = fc.staticCfg.TxFee return nil } func (fc *Calculator) TransformSubnetTx(*txs.TransformSubnetTx) error { - fc.Fee = fc.config.TransformSubnetTxFee + fc.Fee = fc.staticCfg.TransformSubnetTxFee return nil } func (fc *Calculator) TransferSubnetOwnershipTx(*txs.TransferSubnetOwnershipTx) error { - fc.Fee = fc.config.TxFee + fc.Fee = fc.staticCfg.TxFee return nil } func (fc *Calculator) AddPermissionlessValidatorTx(tx *txs.AddPermissionlessValidatorTx) error { if tx.Subnet != constants.PrimaryNetworkID { - fc.Fee = fc.config.AddSubnetValidatorFee + fc.Fee = fc.staticCfg.AddSubnetValidatorFee } else { - fc.Fee = fc.config.AddPrimaryNetworkValidatorFee + fc.Fee = fc.staticCfg.AddPrimaryNetworkValidatorFee } return nil } func (fc *Calculator) AddPermissionlessDelegatorTx(tx *txs.AddPermissionlessDelegatorTx) error { if tx.Subnet != constants.PrimaryNetworkID { - fc.Fee = fc.config.AddSubnetDelegatorFee + fc.Fee = fc.staticCfg.AddSubnetDelegatorFee } else { - fc.Fee = fc.config.AddPrimaryNetworkDelegatorFee + fc.Fee = fc.staticCfg.AddPrimaryNetworkDelegatorFee } return nil } func (fc *Calculator) BaseTx(*txs.BaseTx) error { - fc.Fee = fc.config.TxFee + fc.Fee = fc.staticCfg.TxFee return nil } func (fc *Calculator) ImportTx(*txs.ImportTx) error { - fc.Fee = fc.config.TxFee + fc.Fee = fc.staticCfg.TxFee return nil } func (fc *Calculator) ExportTx(*txs.ExportTx) error { - fc.Fee = fc.config.TxFee + fc.Fee = fc.staticCfg.TxFee return nil } diff --git a/vms/platformvm/txs/fee/calculator_test.go b/vms/platformvm/txs/fee/calculator_test.go index fd2348dd6d0a..c4424e3a2d4f 100644 --- a/vms/platformvm/txs/fee/calculator_test.go +++ b/vms/platformvm/txs/fee/calculator_test.go @@ -18,16 +18,16 @@ import ( "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/config" "github.com/ava-labs/avalanchego/vms/platformvm/reward" "github.com/ava-labs/avalanchego/vms/platformvm/signer" "github.com/ava-labs/avalanchego/vms/platformvm/stakeable" "github.com/ava-labs/avalanchego/vms/platformvm/txs" + "github.com/ava-labs/avalanchego/vms/platformvm/upgrade" "github.com/ava-labs/avalanchego/vms/secp256k1fx" ) var ( - feeTestsDefaultCfg = config.Config{ + feeTestsDefaultCfg = StaticConfig{ TxFee: 1 * units.Avax, CreateAssetTxFee: 2 * units.Avax, CreateSubnetTxFee: 3 * units.Avax, @@ -47,7 +47,7 @@ var ( type feeTests struct { description string - cfgAndChainTimeF func() (*config.Config, time.Time) + cfgAndChainTimeF func() (StaticConfig, upgrade.Times, time.Time) unsignedAndSignedTx func(t *testing.T) (txs.UnsignedTx, *txs.Tx) expectedError error checksF func(*testing.T, *Calculator) @@ -59,217 +59,229 @@ func TestTxFees(t *testing.T) { tests := []feeTests{ { description: "AddValidatorTx pre EUpgrade", - cfgAndChainTimeF: func() (*config.Config, time.Time) { + cfgAndChainTimeF: func() (StaticConfig, upgrade.Times, time.Time) { eUpgradeTime := time.Now().Truncate(time.Second) chainTime := eUpgradeTime.Add(-1 * time.Second) cfg := feeTestsDefaultCfg - cfg.DurangoTime = durangoTime - cfg.EUpgradeTime = eUpgradeTime - - return &cfg, chainTime + upgrade := upgrade.Times{ + DurangoTime: durangoTime, + EUpgradeTime: eUpgradeTime, + } + return cfg, upgrade, chainTime }, unsignedAndSignedTx: addValidatorTx, expectedError: nil, checksF: func(t *testing.T, fc *Calculator) { - require.Equal(t, fc.config.AddPrimaryNetworkValidatorFee, fc.Fee) + require.Equal(t, fc.staticCfg.AddPrimaryNetworkValidatorFee, fc.Fee) }, }, { description: "AddSubnetValidatorTx pre EUpgrade", - cfgAndChainTimeF: func() (*config.Config, time.Time) { + cfgAndChainTimeF: func() (StaticConfig, upgrade.Times, time.Time) { eUpgradeTime := time.Now().Truncate(time.Second) chainTime := eUpgradeTime.Add(-1 * time.Second) cfg := feeTestsDefaultCfg - cfg.DurangoTime = durangoTime - cfg.EUpgradeTime = eUpgradeTime - - return &cfg, chainTime + upgrade := upgrade.Times{ + DurangoTime: durangoTime, + EUpgradeTime: eUpgradeTime, + } + return cfg, upgrade, chainTime }, unsignedAndSignedTx: addSubnetValidatorTx, expectedError: nil, checksF: func(t *testing.T, fc *Calculator) { - require.Equal(t, fc.config.AddSubnetValidatorFee, fc.Fee) + require.Equal(t, fc.staticCfg.AddSubnetValidatorFee, fc.Fee) }, }, { description: "AddDelegatorTx pre EUpgrade", - cfgAndChainTimeF: func() (*config.Config, time.Time) { + cfgAndChainTimeF: func() (StaticConfig, upgrade.Times, time.Time) { eUpgradeTime := time.Now().Truncate(time.Second) chainTime := eUpgradeTime.Add(-1 * time.Second) cfg := feeTestsDefaultCfg - cfg.DurangoTime = durangoTime - cfg.EUpgradeTime = eUpgradeTime - - return &cfg, chainTime + upgrade := upgrade.Times{ + DurangoTime: durangoTime, + EUpgradeTime: eUpgradeTime, + } + return cfg, upgrade, chainTime }, unsignedAndSignedTx: addDelegatorTx, expectedError: nil, checksF: func(t *testing.T, fc *Calculator) { - require.Equal(t, fc.config.AddPrimaryNetworkDelegatorFee, fc.Fee) + require.Equal(t, fc.staticCfg.AddPrimaryNetworkDelegatorFee, fc.Fee) }, }, { description: "CreateChainTx pre ApricotPhase3", - cfgAndChainTimeF: func() (*config.Config, time.Time) { + cfgAndChainTimeF: func() (StaticConfig, upgrade.Times, time.Time) { apricotPhase3Time := time.Now().Truncate(time.Second) chainTime := apricotPhase3Time.Add(-1 * time.Second) cfg := feeTestsDefaultCfg - cfg.ApricotPhase3Time = apricotPhase3Time - cfg.DurangoTime = mockable.MaxTime - cfg.EUpgradeTime = mockable.MaxTime - - return &cfg, chainTime + upgrade := upgrade.Times{ + ApricotPhase3Time: apricotPhase3Time, + DurangoTime: mockable.MaxTime, + EUpgradeTime: mockable.MaxTime, + } + return cfg, upgrade, chainTime }, unsignedAndSignedTx: createChainTx, expectedError: nil, checksF: func(t *testing.T, fc *Calculator) { - require.Equal(t, fc.config.CreateAssetTxFee, fc.Fee) + require.Equal(t, fc.staticCfg.CreateAssetTxFee, fc.Fee) }, }, { description: "CreateChainTx pre EUpgrade", - cfgAndChainTimeF: func() (*config.Config, time.Time) { + cfgAndChainTimeF: func() (StaticConfig, upgrade.Times, time.Time) { eUpgradeTime := time.Now().Truncate(time.Second) chainTime := eUpgradeTime.Add(-1 * time.Second) cfg := feeTestsDefaultCfg - cfg.DurangoTime = durangoTime - cfg.EUpgradeTime = eUpgradeTime - - return &cfg, chainTime + upgrade := upgrade.Times{ + DurangoTime: durangoTime, + EUpgradeTime: eUpgradeTime, + } + return cfg, upgrade, chainTime }, unsignedAndSignedTx: createChainTx, expectedError: nil, checksF: func(t *testing.T, fc *Calculator) { - require.Equal(t, fc.config.CreateBlockchainTxFee, fc.Fee) + require.Equal(t, fc.staticCfg.CreateBlockchainTxFee, fc.Fee) }, }, { description: "CreateSubnetTx pre ApricotPhase3", - cfgAndChainTimeF: func() (*config.Config, time.Time) { + cfgAndChainTimeF: func() (StaticConfig, upgrade.Times, time.Time) { apricotPhase3Time := time.Now().Truncate(time.Second) chainTime := apricotPhase3Time.Add(-1 * time.Second) cfg := feeTestsDefaultCfg - cfg.ApricotPhase3Time = apricotPhase3Time - cfg.DurangoTime = mockable.MaxTime - cfg.EUpgradeTime = mockable.MaxTime - - return &cfg, chainTime + upgrade := upgrade.Times{ + ApricotPhase3Time: apricotPhase3Time, + DurangoTime: mockable.MaxTime, + EUpgradeTime: mockable.MaxTime, + } + return cfg, upgrade, chainTime }, unsignedAndSignedTx: createSubnetTx, expectedError: nil, checksF: func(t *testing.T, fc *Calculator) { - require.Equal(t, fc.config.CreateAssetTxFee, fc.Fee) + require.Equal(t, fc.staticCfg.CreateAssetTxFee, fc.Fee) }, }, { description: "CreateSubnetTx pre EUpgrade", - cfgAndChainTimeF: func() (*config.Config, time.Time) { + cfgAndChainTimeF: func() (StaticConfig, upgrade.Times, time.Time) { eUpgradeTime := time.Now().Truncate(time.Second) chainTime := eUpgradeTime.Add(-1 * time.Second) cfg := feeTestsDefaultCfg - cfg.DurangoTime = durangoTime - cfg.EUpgradeTime = eUpgradeTime - - return &cfg, chainTime + upgrade := upgrade.Times{ + DurangoTime: durangoTime, + EUpgradeTime: eUpgradeTime, + } + return cfg, upgrade, chainTime }, unsignedAndSignedTx: createSubnetTx, expectedError: nil, checksF: func(t *testing.T, fc *Calculator) { - require.Equal(t, fc.config.CreateSubnetTxFee, fc.Fee) + require.Equal(t, fc.staticCfg.CreateSubnetTxFee, fc.Fee) }, }, { description: "RemoveSubnetValidatorTx pre EUpgrade", - cfgAndChainTimeF: func() (*config.Config, time.Time) { + cfgAndChainTimeF: func() (StaticConfig, upgrade.Times, time.Time) { eUpgradeTime := time.Now().Truncate(time.Second) chainTime := eUpgradeTime.Add(-1 * time.Second) cfg := feeTestsDefaultCfg - cfg.DurangoTime = durangoTime - cfg.EUpgradeTime = eUpgradeTime - - return &cfg, chainTime + upgrade := upgrade.Times{ + DurangoTime: durangoTime, + EUpgradeTime: eUpgradeTime, + } + return cfg, upgrade, chainTime }, unsignedAndSignedTx: removeSubnetValidatorTx, expectedError: nil, checksF: func(t *testing.T, fc *Calculator) { - require.Equal(t, fc.config.TxFee, fc.Fee) + require.Equal(t, fc.staticCfg.TxFee, fc.Fee) }, }, { description: "TransformSubnetTx pre EUpgrade", - cfgAndChainTimeF: func() (*config.Config, time.Time) { + cfgAndChainTimeF: func() (StaticConfig, upgrade.Times, time.Time) { eUpgradeTime := time.Now().Truncate(time.Second) chainTime := eUpgradeTime.Add(-1 * time.Second) cfg := feeTestsDefaultCfg - cfg.DurangoTime = durangoTime - cfg.EUpgradeTime = eUpgradeTime - - return &cfg, chainTime + upgrade := upgrade.Times{ + DurangoTime: durangoTime, + EUpgradeTime: eUpgradeTime, + } + return cfg, upgrade, chainTime }, unsignedAndSignedTx: transformSubnetTx, expectedError: nil, checksF: func(t *testing.T, fc *Calculator) { - require.Equal(t, fc.config.TransformSubnetTxFee, fc.Fee) + require.Equal(t, fc.staticCfg.TransformSubnetTxFee, fc.Fee) }, }, { description: "TransferSubnetOwnershipTx pre EUpgrade", - cfgAndChainTimeF: func() (*config.Config, time.Time) { + cfgAndChainTimeF: func() (StaticConfig, upgrade.Times, time.Time) { eUpgradeTime := time.Now().Truncate(time.Second) chainTime := eUpgradeTime.Add(-1 * time.Second) cfg := feeTestsDefaultCfg - cfg.DurangoTime = durangoTime - cfg.EUpgradeTime = eUpgradeTime - - return &cfg, chainTime + upgrade := upgrade.Times{ + DurangoTime: durangoTime, + EUpgradeTime: eUpgradeTime, + } + return cfg, upgrade, chainTime }, unsignedAndSignedTx: transferSubnetOwnershipTx, expectedError: nil, checksF: func(t *testing.T, fc *Calculator) { - require.Equal(t, fc.config.TxFee, fc.Fee) + require.Equal(t, fc.staticCfg.TxFee, fc.Fee) }, }, { description: "AddPermissionlessValidatorTx Primary Network pre EUpgrade", - cfgAndChainTimeF: func() (*config.Config, time.Time) { + cfgAndChainTimeF: func() (StaticConfig, upgrade.Times, time.Time) { eUpgradeTime := time.Now().Truncate(time.Second) chainTime := eUpgradeTime.Add(-1 * time.Second) cfg := feeTestsDefaultCfg - cfg.DurangoTime = durangoTime - cfg.EUpgradeTime = eUpgradeTime - - return &cfg, chainTime + upgrade := upgrade.Times{ + DurangoTime: durangoTime, + EUpgradeTime: eUpgradeTime, + } + return cfg, upgrade, chainTime }, unsignedAndSignedTx: func(t *testing.T) (txs.UnsignedTx, *txs.Tx) { return addPermissionlessValidatorTx(t, constants.PrimaryNetworkID) }, expectedError: nil, checksF: func(t *testing.T, fc *Calculator) { - require.Equal(t, fc.config.AddPrimaryNetworkValidatorFee, fc.Fee) + require.Equal(t, fc.staticCfg.AddPrimaryNetworkValidatorFee, fc.Fee) }, }, { description: "AddPermissionlessValidatorTx Subnet pre EUpgrade", - cfgAndChainTimeF: func() (*config.Config, time.Time) { + cfgAndChainTimeF: func() (StaticConfig, upgrade.Times, time.Time) { eUpgradeTime := time.Now().Truncate(time.Second) chainTime := eUpgradeTime.Add(-1 * time.Second) cfg := feeTestsDefaultCfg - cfg.DurangoTime = durangoTime - cfg.EUpgradeTime = eUpgradeTime - - return &cfg, chainTime + upgrade := upgrade.Times{ + DurangoTime: durangoTime, + EUpgradeTime: eUpgradeTime, + } + return cfg, upgrade, chainTime }, unsignedAndSignedTx: func(t *testing.T) (txs.UnsignedTx, *txs.Tx) { subnetID := ids.GenerateTestID() @@ -278,40 +290,42 @@ func TestTxFees(t *testing.T) { }, expectedError: nil, checksF: func(t *testing.T, fc *Calculator) { - require.Equal(t, fc.config.AddSubnetValidatorFee, fc.Fee) + require.Equal(t, fc.staticCfg.AddSubnetValidatorFee, fc.Fee) }, }, { description: "AddPermissionlessDelegatorTx Primary Network pre EUpgrade", - cfgAndChainTimeF: func() (*config.Config, time.Time) { + cfgAndChainTimeF: func() (StaticConfig, upgrade.Times, time.Time) { eUpgradeTime := time.Now().Truncate(time.Second) chainTime := eUpgradeTime.Add(-1 * time.Second) cfg := feeTestsDefaultCfg - cfg.DurangoTime = durangoTime - cfg.EUpgradeTime = eUpgradeTime - - return &cfg, chainTime + upgrade := upgrade.Times{ + DurangoTime: durangoTime, + EUpgradeTime: eUpgradeTime, + } + return cfg, upgrade, chainTime }, unsignedAndSignedTx: func(t *testing.T) (txs.UnsignedTx, *txs.Tx) { return addPermissionlessDelegatorTx(t, constants.PrimaryNetworkID) }, expectedError: nil, checksF: func(t *testing.T, fc *Calculator) { - require.Equal(t, fc.config.AddPrimaryNetworkDelegatorFee, fc.Fee) + require.Equal(t, fc.staticCfg.AddPrimaryNetworkDelegatorFee, fc.Fee) }, }, { description: "AddPermissionlessDelegatorTx pre EUpgrade", - cfgAndChainTimeF: func() (*config.Config, time.Time) { + cfgAndChainTimeF: func() (StaticConfig, upgrade.Times, time.Time) { eUpgradeTime := time.Now().Truncate(time.Second) chainTime := eUpgradeTime.Add(-1 * time.Second) cfg := feeTestsDefaultCfg - cfg.DurangoTime = durangoTime - cfg.EUpgradeTime = eUpgradeTime - - return &cfg, chainTime + upgrade := upgrade.Times{ + DurangoTime: durangoTime, + EUpgradeTime: eUpgradeTime, + } + return cfg, upgrade, chainTime }, unsignedAndSignedTx: func(t *testing.T) (txs.UnsignedTx, *txs.Tx) { subnetID := ids.GenerateTestID() @@ -320,74 +334,78 @@ func TestTxFees(t *testing.T) { }, expectedError: nil, checksF: func(t *testing.T, fc *Calculator) { - require.Equal(t, fc.config.AddSubnetDelegatorFee, fc.Fee) + require.Equal(t, fc.staticCfg.AddSubnetDelegatorFee, fc.Fee) }, }, { description: "BaseTx pre EUpgrade", - cfgAndChainTimeF: func() (*config.Config, time.Time) { + cfgAndChainTimeF: func() (StaticConfig, upgrade.Times, time.Time) { eUpgradeTime := time.Now().Truncate(time.Second) chainTime := eUpgradeTime.Add(-1 * time.Second) cfg := feeTestsDefaultCfg - cfg.DurangoTime = durangoTime - cfg.EUpgradeTime = eUpgradeTime - - return &cfg, chainTime + upgrade := upgrade.Times{ + DurangoTime: durangoTime, + EUpgradeTime: eUpgradeTime, + } + return cfg, upgrade, chainTime }, unsignedAndSignedTx: baseTx, expectedError: nil, checksF: func(t *testing.T, fc *Calculator) { - require.Equal(t, fc.config.TxFee, fc.Fee) + require.Equal(t, fc.staticCfg.TxFee, fc.Fee) }, }, { description: "ImportTx pre EUpgrade", - cfgAndChainTimeF: func() (*config.Config, time.Time) { + cfgAndChainTimeF: func() (StaticConfig, upgrade.Times, time.Time) { eUpgradeTime := time.Now().Truncate(time.Second) chainTime := eUpgradeTime.Add(-1 * time.Second) cfg := feeTestsDefaultCfg - cfg.DurangoTime = durangoTime - cfg.EUpgradeTime = eUpgradeTime - - return &cfg, chainTime + upgrade := upgrade.Times{ + DurangoTime: durangoTime, + EUpgradeTime: eUpgradeTime, + } + return cfg, upgrade, chainTime }, unsignedAndSignedTx: importTx, expectedError: nil, checksF: func(t *testing.T, fc *Calculator) { - require.Equal(t, fc.config.TxFee, fc.Fee) + require.Equal(t, fc.staticCfg.TxFee, fc.Fee) }, }, { description: "ExportTx pre EUpgrade", - cfgAndChainTimeF: func() (*config.Config, time.Time) { + cfgAndChainTimeF: func() (StaticConfig, upgrade.Times, time.Time) { eUpgradeTime := time.Now().Truncate(time.Second) chainTime := eUpgradeTime.Add(-1 * time.Second) cfg := feeTestsDefaultCfg - cfg.DurangoTime = durangoTime - cfg.EUpgradeTime = eUpgradeTime - - return &cfg, chainTime + upgrade := upgrade.Times{ + DurangoTime: durangoTime, + EUpgradeTime: eUpgradeTime, + } + return cfg, upgrade, chainTime }, unsignedAndSignedTx: exportTx, expectedError: nil, checksF: func(t *testing.T, fc *Calculator) { - require.Equal(t, fc.config.TxFee, fc.Fee) + require.Equal(t, fc.staticCfg.TxFee, fc.Fee) }, }, { description: "RewardValidatorTx pre EUpgrade", - cfgAndChainTimeF: func() (*config.Config, time.Time) { + cfgAndChainTimeF: func() (StaticConfig, upgrade.Times, time.Time) { eUpgradeTime := time.Now().Truncate(time.Second) chainTime := eUpgradeTime.Add(-1 * time.Second) cfg := feeTestsDefaultCfg - cfg.DurangoTime = durangoTime - cfg.EUpgradeTime = eUpgradeTime - - return &cfg, chainTime + upgrade := upgrade.Times{ + DurangoTime: durangoTime, + EUpgradeTime: eUpgradeTime, + } + return cfg, upgrade, chainTime }, unsignedAndSignedTx: func(_ *testing.T) (txs.UnsignedTx, *txs.Tx) { return &txs.RewardValidatorTx{ @@ -401,15 +419,16 @@ func TestTxFees(t *testing.T) { }, { description: "AdvanceTimeTx pre EUpgrade", - cfgAndChainTimeF: func() (*config.Config, time.Time) { + cfgAndChainTimeF: func() (StaticConfig, upgrade.Times, time.Time) { eUpgradeTime := time.Now().Truncate(time.Second) chainTime := eUpgradeTime.Add(-1 * time.Second) cfg := feeTestsDefaultCfg - cfg.DurangoTime = durangoTime - cfg.EUpgradeTime = eUpgradeTime - - return &cfg, chainTime + upgrade := upgrade.Times{ + DurangoTime: durangoTime, + EUpgradeTime: eUpgradeTime, + } + return cfg, upgrade, chainTime }, unsignedAndSignedTx: func(_ *testing.T) (txs.UnsignedTx, *txs.Tx) { return &txs.AdvanceTimeTx{ @@ -425,10 +444,10 @@ func TestTxFees(t *testing.T) { for _, tt := range tests { t.Run(tt.description, func(t *testing.T) { - cfg, chainTime := tt.cfgAndChainTimeF() + cfg, upgrades, chainTime := tt.cfgAndChainTimeF() uTx, _ := tt.unsignedAndSignedTx(t) - fc := NewStaticCalculator(cfg, chainTime) + fc := NewStaticCalculator(cfg, upgrades, chainTime) err := uTx.Visit(fc) r.ErrorIs(err, tt.expectedError) diff --git a/vms/platformvm/txs/fee/config.go b/vms/platformvm/txs/fee/config.go new file mode 100644 index 000000000000..12899b315b32 --- /dev/null +++ b/vms/platformvm/txs/fee/config.go @@ -0,0 +1,45 @@ +// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package fee + +type StaticConfig struct { + // Fee that is burned by every non-state creating transaction + TxFee uint64 + + // Fee that must be burned by every state creating transaction before AP3 + CreateAssetTxFee uint64 + + // Fee that must be burned by every subnet creating transaction after AP3 + CreateSubnetTxFee uint64 + + // Fee that must be burned by every transform subnet transaction + TransformSubnetTxFee uint64 + + // Fee that must be burned by every blockchain creating transaction after AP3 + CreateBlockchainTxFee uint64 + + // Transaction fee for adding a primary network validator + AddPrimaryNetworkValidatorFee uint64 + + // Transaction fee for adding a primary network delegator + AddPrimaryNetworkDelegatorFee uint64 + + // Transaction fee for adding a subnet validator + AddSubnetValidatorFee uint64 + + // Transaction fee for adding a subnet delegator + AddSubnetDelegatorFee uint64 + + // The minimum amount of tokens one must bond to be a validator + MinValidatorStake uint64 + + // The maximum amount of tokens that can be bonded on a validator + MaxValidatorStake uint64 + + // Minimum stake, in nAVAX, that can be delegated on the primary network + MinDelegatorStake uint64 + + // Minimum fee that can be charged for delegation + MinDelegationFee uint32 +} diff --git a/vms/platformvm/txs/txstest/context.go b/vms/platformvm/txs/txstest/context.go index e756d145e57b..a914e9b24085 100644 --- a/vms/platformvm/txs/txstest/context.go +++ b/vms/platformvm/txs/txstest/context.go @@ -19,7 +19,9 @@ func newContext( timestamp time.Time, ) (*builder.Context, error) { var ( - staticFeeCalc = fee.NewStaticCalculator(cfg, timestamp) + staticFeesCfg = cfg.StaticConfig + upgrades = cfg.Times + staticFeeCalc = fee.NewStaticCalculator(staticFeesCfg, upgrades, timestamp) createSubnetTx = &txs.CreateSubnetTx{} createChainTx = &txs.CreateChainTx{} ) @@ -36,13 +38,13 @@ func newContext( return &builder.Context{ NetworkID: ctx.NetworkID, AVAXAssetID: ctx.AVAXAssetID, - BaseTxFee: cfg.TxFee, + BaseTxFee: staticFeesCfg.TxFee, CreateSubnetTxFee: createSubnetFee, - TransformSubnetTxFee: cfg.TransformSubnetTxFee, + TransformSubnetTxFee: staticFeesCfg.TransformSubnetTxFee, CreateBlockchainTxFee: createChainFee, - AddPrimaryNetworkValidatorFee: cfg.AddPrimaryNetworkValidatorFee, - AddPrimaryNetworkDelegatorFee: cfg.AddPrimaryNetworkDelegatorFee, - AddSubnetValidatorFee: cfg.AddSubnetValidatorFee, - AddSubnetDelegatorFee: cfg.AddSubnetDelegatorFee, + AddPrimaryNetworkValidatorFee: staticFeesCfg.AddPrimaryNetworkValidatorFee, + AddPrimaryNetworkDelegatorFee: staticFeesCfg.AddPrimaryNetworkDelegatorFee, + AddSubnetValidatorFee: staticFeesCfg.AddSubnetValidatorFee, + AddSubnetDelegatorFee: staticFeesCfg.AddSubnetDelegatorFee, }, nil } diff --git a/vms/platformvm/validator_set_property_test.go b/vms/platformvm/validator_set_property_test.go index 162a02a70887..5c7d3eb415ff 100644 --- a/vms/platformvm/validator_set_property_test.go +++ b/vms/platformvm/validator_set_property_test.go @@ -43,6 +43,7 @@ import ( "github.com/ava-labs/avalanchego/vms/platformvm/signer" "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/txs/txstest" "github.com/ava-labs/avalanchego/vms/platformvm/upgrade" "github.com/ava-labs/avalanchego/vms/secp256k1fx" @@ -652,16 +653,18 @@ func buildVM(t *testing.T) (*VM, ids.ID, error) { UptimeLockedCalculator: uptime.NewLockedCalculator(), SybilProtectionEnabled: true, Validators: validators.NewManager(), - TxFee: defaultTxFee, - CreateSubnetTxFee: 100 * defaultTxFee, - TransformSubnetTxFee: 100 * defaultTxFee, - CreateBlockchainTxFee: 100 * defaultTxFee, - MinValidatorStake: defaultMinValidatorStake, - MaxValidatorStake: defaultMaxValidatorStake, - MinDelegatorStake: defaultMinDelegatorStake, - MinStakeDuration: defaultMinStakingDuration, - MaxStakeDuration: defaultMaxStakingDuration, - RewardConfig: defaultRewardConfig, + StaticConfig: fee.StaticConfig{ + TxFee: defaultTxFee, + CreateSubnetTxFee: 100 * defaultTxFee, + TransformSubnetTxFee: 100 * defaultTxFee, + CreateBlockchainTxFee: 100 * defaultTxFee, + }, + MinValidatorStake: defaultMinValidatorStake, + MaxValidatorStake: defaultMaxValidatorStake, + MinDelegatorStake: defaultMinDelegatorStake, + MinStakeDuration: defaultMinStakingDuration, + MaxStakeDuration: defaultMaxStakingDuration, + RewardConfig: defaultRewardConfig, Times: upgrade.Times{ ApricotPhase3Time: forkTime, ApricotPhase5Time: forkTime, diff --git a/vms/platformvm/vm_test.go b/vms/platformvm/vm_test.go index e2fa50d121e8..c6c39f5c3f46 100644 --- a/vms/platformvm/vm_test.go +++ b/vms/platformvm/vm_test.go @@ -57,6 +57,7 @@ import ( "github.com/ava-labs/avalanchego/vms/platformvm/signer" "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/platformvm/upgrade" "github.com/ava-labs/avalanchego/vms/secp256k1fx" @@ -245,16 +246,18 @@ func defaultVM(t *testing.T, f fork) (*VM, *txstest.Builder, database.Database, UptimeLockedCalculator: uptime.NewLockedCalculator(), SybilProtectionEnabled: true, Validators: validators.NewManager(), - TxFee: defaultTxFee, - CreateSubnetTxFee: 100 * defaultTxFee, - TransformSubnetTxFee: 100 * defaultTxFee, - CreateBlockchainTxFee: 100 * defaultTxFee, - MinValidatorStake: defaultMinValidatorStake, - MaxValidatorStake: defaultMaxValidatorStake, - MinDelegatorStake: defaultMinDelegatorStake, - MinStakeDuration: defaultMinStakingDuration, - MaxStakeDuration: defaultMaxStakingDuration, - RewardConfig: defaultRewardConfig, + StaticConfig: fee.StaticConfig{ + TxFee: defaultTxFee, + CreateSubnetTxFee: 100 * defaultTxFee, + TransformSubnetTxFee: 100 * defaultTxFee, + CreateBlockchainTxFee: 100 * defaultTxFee, + }, + MinValidatorStake: defaultMinValidatorStake, + MaxValidatorStake: defaultMaxValidatorStake, + MinDelegatorStake: defaultMinDelegatorStake, + MinStakeDuration: defaultMinStakingDuration, + MaxStakeDuration: defaultMaxStakingDuration, + RewardConfig: defaultRewardConfig, Times: upgrade.Times{ ApricotPhase3Time: apricotPhase3Time, ApricotPhase5Time: apricotPhase5Time, From 922b38110b7c57ee93d2f312c8baa3bf80764a84 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Wed, 24 Apr 2024 13:07:10 +0200 Subject: [PATCH 148/190] Merge --- vms/platformvm/block/builder/builder.go | 2 +- vms/platformvm/block/executor/helpers_test.go | 2 +- vms/platformvm/block/executor/manager.go | 2 +- vms/platformvm/block/executor/verifier.go | 2 +- vms/platformvm/service.go | 2 +- vms/platformvm/txs/executor/create_chain_test.go | 8 ++++---- vms/platformvm/txs/executor/helpers_test.go | 2 +- vms/platformvm/txs/fee/helpers.go | 2 +- vms/platformvm/txs/txstest/builder.go | 2 +- 9 files changed, 12 insertions(+), 12 deletions(-) diff --git a/vms/platformvm/block/builder/builder.go b/vms/platformvm/block/builder/builder.go index 21b45aea56e4..430aaf46cfc9 100644 --- a/vms/platformvm/block/builder/builder.go +++ b/vms/platformvm/block/builder/builder.go @@ -360,7 +360,7 @@ func packBlockTxs( return nil, fmt.Errorf("failed retrieving last block complexity: %w", err) } - feeMan, err = fee.UpdatedFeeManager(feeRates, parentBlkComplexity, backend.Config.Times, parentBlkTime, timestamp) + feeMan, err = fee.UpdatedFeeManager(feeRates, parentBlkComplexity, backend.Config.Config, parentBlkTime, timestamp) if err != nil { return nil, err } diff --git a/vms/platformvm/block/executor/helpers_test.go b/vms/platformvm/block/executor/helpers_test.go index 3223e5a663b0..b45d0e4e93fb 100644 --- a/vms/platformvm/block/executor/helpers_test.go +++ b/vms/platformvm/block/executor/helpers_test.go @@ -315,7 +315,7 @@ func addSubnet(env *environment) { panic(fmt.Errorf("failed retrieving last block complexity: %w", err)) } - feeManager, err := fee.UpdatedFeeManager(feeRates, parentBlkComplexity, env.config.Times, chainTime, nextChainTime) + feeManager, err := fee.UpdatedFeeManager(feeRates, parentBlkComplexity, env.config.Config, chainTime, nextChainTime) if err != nil { panic(err) } diff --git a/vms/platformvm/block/executor/manager.go b/vms/platformvm/block/executor/manager.go index 35f03dbdf64f..ed4f1536ef04 100644 --- a/vms/platformvm/block/executor/manager.go +++ b/vms/platformvm/block/executor/manager.go @@ -169,7 +169,7 @@ func (m *manager) VerifyTx(tx *txs.Tx) error { if err != nil { return fmt.Errorf("failed retrieving last block complexity: %w", err) } - feeManager, err = fee.UpdatedFeeManager(feeRates, parentBlkComplexity, m.txExecutorBackend.Config.Times, parentBlkTime, nextBlkTime) + feeManager, err = fee.UpdatedFeeManager(feeRates, parentBlkComplexity, m.txExecutorBackend.Config.Config, parentBlkTime, nextBlkTime) if err != nil { return err } diff --git a/vms/platformvm/block/executor/verifier.go b/vms/platformvm/block/executor/verifier.go index 5468aa8fb434..b1887582e97b 100644 --- a/vms/platformvm/block/executor/verifier.go +++ b/vms/platformvm/block/executor/verifier.go @@ -498,7 +498,7 @@ func (v *verifier) processStandardTxs( if err != nil { return nil, nil, nil, nil, fmt.Errorf("failed retrieving last block complexity: %w", err) } - feeMan, err = fee.UpdatedFeeManager(feeRates, parentBlkComplexity, v.txExecutorBackend.Config.Times, parentBlkTime, blkTimestamp) + feeMan, err = fee.UpdatedFeeManager(feeRates, parentBlkComplexity, v.txExecutorBackend.Config.Config, parentBlkTime, blkTimestamp) if err != nil { return nil, nil, nil, nil, err } diff --git a/vms/platformvm/service.go b/vms/platformvm/service.go index ad1775ee9203..47e293801b9d 100644 --- a/vms/platformvm/service.go +++ b/vms/platformvm/service.go @@ -1877,7 +1877,7 @@ func (s *Service) GetFeeRates(_ *http.Request, _ *struct{}, reply *GetFeeRatesRe if err != nil { return fmt.Errorf("failed retrieving last block complexity: %w", err) } - feeManager, err = fee.UpdatedFeeManager(feeRates, parentBlkComplexity, s.vm.Config.Times, currentTimestamp, nextTimestamp) + feeManager, err = fee.UpdatedFeeManager(feeRates, parentBlkComplexity, s.vm.Config.Config, currentTimestamp, nextTimestamp) if err != nil { return err } diff --git a/vms/platformvm/txs/executor/create_chain_test.go b/vms/platformvm/txs/executor/create_chain_test.go index e703b7202cb1..70d75712d863 100644 --- a/vms/platformvm/txs/executor/create_chain_test.go +++ b/vms/platformvm/txs/executor/create_chain_test.go @@ -61,7 +61,7 @@ func TestCreateChainTxInsufficientControlSigs(t *testing.T) { parentBlkComplexity, err := stateDiff.GetLastBlockComplexity() require.NoError(err) - feeMan, err := fee.UpdatedFeeManager(feeRates, parentBlkComplexity, env.config.Times, currentTime, nextBlkTime) + feeMan, err := fee.UpdatedFeeManager(feeRates, parentBlkComplexity, env.config.Config, currentTime, nextBlkTime) require.NoError(err) executor := StandardTxExecutor{ @@ -116,7 +116,7 @@ func TestCreateChainTxWrongControlSig(t *testing.T) { parentBlkComplexity, err := stateDiff.GetLastBlockComplexity() require.NoError(err) - feeMan, err := fee.UpdatedFeeManager(feeRates, parentBlkComplexity, env.config.Times, currentTime, nextBlkTime) + feeMan, err := fee.UpdatedFeeManager(feeRates, parentBlkComplexity, env.config.Config, currentTime, nextBlkTime) require.NoError(err) executor := StandardTxExecutor{ @@ -165,7 +165,7 @@ func TestCreateChainTxNoSuchSubnet(t *testing.T) { parentBlkComplexity, err := stateDiff.GetLastBlockComplexity() require.NoError(err) - feeMan, err := fee.UpdatedFeeManager(feeRates, parentBlkComplexity, env.config.Times, currentTime, nextBlkTime) + feeMan, err := fee.UpdatedFeeManager(feeRates, parentBlkComplexity, env.config.Config, currentTime, nextBlkTime) require.NoError(err) executor := StandardTxExecutor{ @@ -211,7 +211,7 @@ func TestCreateChainTxValid(t *testing.T) { parentBlkComplexity, err := stateDiff.GetLastBlockComplexity() require.NoError(err) - feeMan, err := fee.UpdatedFeeManager(feeRates, parentBlkComplexity, env.config.Times, currentTime, nextBlkTime) + feeMan, err := fee.UpdatedFeeManager(feeRates, parentBlkComplexity, env.config.Config, currentTime, nextBlkTime) require.NoError(err) executor := StandardTxExecutor{ diff --git a/vms/platformvm/txs/executor/helpers_test.go b/vms/platformvm/txs/executor/helpers_test.go index 499898de5a1e..0ecd660c8bfb 100644 --- a/vms/platformvm/txs/executor/helpers_test.go +++ b/vms/platformvm/txs/executor/helpers_test.go @@ -240,7 +240,7 @@ func addSubnet(t *testing.T, env *environment) { require.NoError(err) parentBlkComplexity, err := stateDiff.GetLastBlockComplexity() require.NoError(err) - feeManager, err := fee.UpdatedFeeManager(feeRates, parentBlkComplexity, env.config.Times, currentChainTime, nextChainTime) + feeManager, err := fee.UpdatedFeeManager(feeRates, parentBlkComplexity, env.config.Config, currentChainTime, nextChainTime) require.NoError(err) feeCfg := fee.GetDynamicConfig(env.config.IsEActivated(currentChainTime)) diff --git a/vms/platformvm/txs/fee/helpers.go b/vms/platformvm/txs/fee/helpers.go index e67dc997d49f..3dad72675ee9 100644 --- a/vms/platformvm/txs/fee/helpers.go +++ b/vms/platformvm/txs/fee/helpers.go @@ -61,7 +61,7 @@ func FinanceCredential(feeCalc *Calculator, keysCount int) (uint64, error) { return addedFees, nil } -func UpdatedFeeManager(feeRates, parentBlkComplexity fees.Dimensions, upgrades upgrade.Times, parentBlkTime, nextBlkTime time.Time) (*fees.Manager, error) { +func UpdatedFeeManager(feeRates, parentBlkComplexity fees.Dimensions, upgrades upgrade.Config, parentBlkTime, nextBlkTime time.Time) (*fees.Manager, error) { var ( isEActive = upgrades.IsEActivated(parentBlkTime) feeCfg = GetDynamicConfig(isEActive) diff --git a/vms/platformvm/txs/txstest/builder.go b/vms/platformvm/txs/txstest/builder.go index 5082da06ab3a..919352e62d5b 100644 --- a/vms/platformvm/txs/txstest/builder.go +++ b/vms/platformvm/txs/txstest/builder.go @@ -445,7 +445,7 @@ func (b *Builder) feeCalculator() (*fee.Calculator, error) { return nil, fmt.Errorf("failed retrieving last block complexity: %w", err) } - feeManager, err := fee.UpdatedFeeManager(feeRates, parentBlkComplexity, b.cfg.Times, chainTime, nextChainTime) + feeManager, err := fee.UpdatedFeeManager(feeRates, parentBlkComplexity, b.cfg.Config, chainTime, nextChainTime) if err != nil { return nil, err } From 16dedd041f8dfc92e69318130cb089961fd1e932 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 2 May 2024 11:43:51 +0200 Subject: [PATCH 149/190] fix update algo + tune P-chain params --- vms/components/fees/manager.go | 16 ++-- vms/components/fees/manager_test.go | 108 ++++++++++++----------- vms/platformvm/txs/fee/dynamic_config.go | 6 +- 3 files changed, 69 insertions(+), 61 deletions(-) diff --git a/vms/components/fees/manager.go b/vms/components/fees/manager.go index 85ee1f539064..d5cdf29021f3 100644 --- a/vms/components/fees/manager.go +++ b/vms/components/fees/manager.go @@ -110,6 +110,7 @@ func (m *Manager) UpdateFeeRates( m.feeRates[i], feesConfig.UpdateCoefficient[i], parentBlkComplexity[i], + feesConfig.BlockMaxComplexity[i], feesConfig.BlockTargetComplexityRate[i], elapsedTime, ) @@ -123,6 +124,7 @@ func nextFeeRate( currentFeeRate, coeff, parentBlkComplexity, + maxBlockComplexity, targetComplexityRate, elapsedTime uint64, ) uint64 { @@ -134,9 +136,9 @@ func nextFeeRate( // // We approximate the exponential as follows: // - // 1 + k * delta^2 if delta >= 0 + // 1 + (k * delta)^2 if delta >= 0 // feeRate_{t+1} = feeRate_t * - // 1 / (1 + k * delta^2) if delta < 0 + // 1 / (1 + (k * delta)^2) if delta < 0 // // The approximation keeps two key properties of the exponential formula: // 1. It's strictly increasing with delta @@ -148,9 +150,13 @@ func nextFeeRate( elapsedTime = max(1, elapsedTime) targetComplexity, over := safemath.Mul64(targetComplexityRate, elapsedTime) if over != nil { - targetComplexity = math.MaxUint64 + targetComplexity = maxBlockComplexity } + // regardless how low network load has been, we won't allow + // blocks larger than max block complexity + targetComplexity = min(targetComplexity, maxBlockComplexity) + if parentBlkComplexity == targetComplexity { return currentFeeRate // complexity matches target, nothing to update } @@ -168,8 +174,8 @@ func nextFeeRate( delta = targetComplexity - parentBlkComplexity } - num := coeff * delta * delta - denom := targetComplexity * targetComplexity * CoeffDenom + num := coeff * coeff * delta * delta + denom := targetComplexity * targetComplexity * CoeffDenom * CoeffDenom if increaseFee { res, over := safemath.Mul64(currentFeeRate, denom+num) diff --git a/vms/components/fees/manager_test.go b/vms/components/fees/manager_test.go index c40b49ef96f0..453979550c3b 100644 --- a/vms/components/fees/manager_test.go +++ b/vms/components/fees/manager_test.go @@ -25,6 +25,7 @@ func TestUpdateFeeRates(t *testing.T) { feesCfg = DynamicFeesConfig{ MinFeeRate: Dimensions{1, 1, 1, 1}, UpdateCoefficient: Dimensions{10, 20, 50, 100}, + BlockMaxComplexity: Dimensions{100, 100, 100, 100}, BlockTargetComplexityRate: Dimensions{25, 25, 25, 25}, } parentFeeRate = Dimensions{10, 20, 100, 200} @@ -56,7 +57,7 @@ func TestUpdateFeeRates(t *testing.T) { require.Equal(uint64(99), m.feeRates[UTXOWrite]) // Compute complexoty is below target, fee rate is pushed down to the minimum - require.Equal(uint64(193), m.feeRates[Compute]) + require.Equal(uint64(199), m.feeRates[Compute]) } func TestUpdateFeeRatesStability(t *testing.T) { @@ -72,6 +73,7 @@ func TestUpdateFeeRatesStability(t *testing.T) { feesCfg = DynamicFeesConfig{ MinFeeRate: Dimensions{0, 0, 0, 0}, UpdateCoefficient: Dimensions{2, 4, 5, 10}, + BlockMaxComplexity: Dimensions{100_000, 100_000, 100_000, 100_000}, BlockTargetComplexityRate: Dimensions{200, 60, 80, 600}, } initialFeeRate = Dimensions{ @@ -135,16 +137,16 @@ func TestPChainFeeRateIncreaseDueToPeak(t *testing.T) { 35 * units.NanoAvax, }, UpdateCoefficient: Dimensions{ // over CoeffDenom - 4, - 1, + 5, + 2, 2, - 3, + 4, }, BlockTargetComplexityRate: Dimensions{ - 4 * 200, - 4 * 60, - 4 * 80, - 4 * 600, + 250, + 60, + 120, + 650, }, BlockMaxComplexity: Dimensions{ 100_000, @@ -154,38 +156,42 @@ func TestPChainFeeRateIncreaseDueToPeak(t *testing.T) { }, } - // See mainnet P-chain block 298vMuyYEi8R3XX6Ewi5orsDVYn5jrNDrPEaPG89UsckcN8e8K its descendants + // See mainnet P-chain block 2LJVD1rfEfaJtTwRggFXaUXhME4t5WYGhYP9Aj7eTYqGsfknuC its descendants blockComplexities = []blkTimeAndComplexity{ - {1703455204, Dimensions{41388, 23040, 23122, 256000}}, - {1703455209, Dimensions{41388, 23040, 23122, 256000}}, - {1703455222, Dimensions{41388, 23040, 23122, 256000}}, - {1703455228, Dimensions{41388, 23040, 23122, 256000}}, - {1703455236, Dimensions{41388, 23040, 23122, 256000}}, - {1703455242, Dimensions{41388, 23040, 23122, 256000}}, - {1703455250, Dimensions{41388, 23040, 23122, 256000}}, - {1703455256, Dimensions{41388, 23040, 23122, 256000}}, - {1703455320, Dimensions{41388, 23040, 23122, 256000}}, - {1703455328, Dimensions{41388, 23040, 23122, 256000}}, - {1703455334, Dimensions{41388, 23040, 23122, 256000}}, - {1703455349, Dimensions{41388, 23040, 23122, 256000}}, - {1703455356, Dimensions{41388, 23040, 23122, 256000}}, - {1703455362, Dimensions{41388, 23040, 23122, 256000}}, - {1703455412, Dimensions{41388, 23040, 23122, 256000}}, - {1703455418, Dimensions{41388, 23040, 23122, 256000}}, - {1703455424, Dimensions{41388, 23040, 23122, 256000}}, - {1703455430, Dimensions{41388, 23040, 23122, 256000}}, - {1703455437, Dimensions{41388, 23040, 23122, 256000}}, - {1703455442, Dimensions{41388, 23040, 23122, 256000}}, - {1703455448, Dimensions{41388, 23040, 23122, 256000}}, - {1703455454, Dimensions{41388, 23040, 23122, 256000}}, - {1703455460, Dimensions{41388, 23040, 23122, 256000}}, - {1703455468, Dimensions{41388, 23040, 23122, 256000}}, - {1703455489, Dimensions{41388, 23040, 23122, 256000}}, - {1703455497, Dimensions{41388, 23040, 23122, 256000}}, - {1703455503, Dimensions{41388, 23040, 23122, 256000}}, - {1703455509, Dimensions{41388, 23040, 23122, 256000}}, - {1703455517, Dimensions{41388, 23040, 23122, 256000}}, - {1703455528, Dimensions{41388, 23040, 23122, 256000}}, + {1615237936, Dimensions{28234, 10812, 10812, 106000}}, + {1615237936, Dimensions{17634, 6732, 6732, 66000}}, + {1615237936, Dimensions{12334, 4692, 4692, 46000}}, + {1615237936, Dimensions{5709, 2142, 2142, 21000}}, + {1615237936, Dimensions{15514, 5916, 5916, 58000}}, + {1615237936, Dimensions{12069, 4590, 4590, 45000}}, + {1615237936, Dimensions{8359, 3162, 3162, 31000}}, + {1615237936, Dimensions{5444, 2040, 2040, 20000}}, + {1615237936, Dimensions{1734, 612, 612, 6000}}, + {1615237936, Dimensions{5974, 2244, 2244, 22000}}, + {1615237936, Dimensions{3059, 1122, 1122, 11000}}, + {1615237936, Dimensions{7034, 2652, 2652, 26000}}, + {1615237936, Dimensions{7564, 2856, 2856, 28000}}, + {1615237936, Dimensions{34064, 13056, 13056, 128000}}, + {1615237936, Dimensions{34064, 13056, 13056, 128000}}, + {1615237936, Dimensions{34064, 13056, 13056, 128000}}, + {1615237936, Dimensions{34064, 13056, 13056, 128000}}, + {1615237936, Dimensions{34064, 13056, 13056, 128000}}, + {1615237936, Dimensions{34064, 13056, 13056, 128000}}, + {1615237936, Dimensions{34064, 13056, 13056, 128000}}, + {1615237936, Dimensions{34064, 13056, 13056, 128000}}, + {1615237936, Dimensions{820, 360, 442, 4000}}, + {1615237936, Dimensions{34064, 13056, 13056, 128000}}, + {1615237936, Dimensions{34064, 13056, 13056, 128000}}, + {1615237936, Dimensions{34064, 13056, 13056, 128000}}, + {1615237936, Dimensions{34064, 13056, 13056, 128000}}, + {1615237936, Dimensions{34064, 13056, 13056, 128000}}, + {1615237936, Dimensions{34064, 13056, 13056, 128000}}, + {1615237936, Dimensions{34064, 13056, 13056, 128000}}, + {1615237936, Dimensions{34064, 13056, 13056, 128000}}, + {1615237936, Dimensions{3589, 1326, 1326, 13000}}, + {1615237936, Dimensions{550, 180, 180, 2000}}, + {1615237936, Dimensions{413, 102, 102, 1000}}, + {1615237936, Dimensions{0, 0, 0, 0}}, } ) @@ -205,18 +211,19 @@ func TestPChainFeeRateIncreaseDueToPeak(t *testing.T) { childBlkData.blkTime, )) - // check that at least a fee rate component has strictly increased + // check that fee rates are strictly above minimal require.False( - Compare(m.feeRates, peakFeeRate), + Compare(m.feeRates, feesCfg.MinFeeRate), fmt.Sprintf("failed at %d of %d iteration, \n curr fees %v \n next fees %v", i, len(blockComplexities), peakFeeRate, m.feeRates, - )) + ), + ) - // at peak the total fee for a median complexity tx should be in tens of Avax, no more. - fee, err := m.CalculateFee(feesCfg.BlockTargetComplexityRate) + // at peak the total fee should be no more than 100 Avax. + fee, err := m.CalculateFee(childBlkData.complexity) require.NoError(err) require.Less(fee, 100*units.Avax, fmt.Sprintf("iteration: %d, total: %d", i, len(blockComplexities))) @@ -224,13 +231,8 @@ func TestPChainFeeRateIncreaseDueToPeak(t *testing.T) { } // OFF PEAK - offPeakBlkComplexity := Dimensions{ - feesCfg.BlockTargetComplexityRate[Bandwidth] * 99 / 100, - feesCfg.BlockTargetComplexityRate[UTXORead] * 99 / 100, - feesCfg.BlockTargetComplexityRate[UTXOWrite] * 99 / 100, - feesCfg.BlockTargetComplexityRate[Compute] * 99 / 100, - } - elapsedTime := time.Second + offPeakBlkComplexity := Dimensions{1473, 510, 510, 5000} + elapsedTime := time.Unix(1615238881, 0).Sub(time.Unix(1615237936, 0)) parentBlkTime := time.Now().Truncate(time.Second) childBlkTime := parentBlkTime.Add(elapsedTime) @@ -241,9 +243,9 @@ func TestPChainFeeRateIncreaseDueToPeak(t *testing.T) { childBlkTime.Unix(), )) - // fee rates must be strictly smaller than peak ones + // check that fee rates decrease off peak require.Less(m.feeRates[Bandwidth], peakFeeRate[Bandwidth]) require.Less(m.feeRates[UTXORead], peakFeeRate[UTXORead]) - require.Less(m.feeRates[UTXOWrite], peakFeeRate[UTXOWrite]) + require.LessOrEqual(m.feeRates[UTXOWrite], peakFeeRate[UTXOWrite]) require.Less(m.feeRates[Compute], peakFeeRate[Compute]) } diff --git a/vms/platformvm/txs/fee/dynamic_config.go b/vms/platformvm/txs/fee/dynamic_config.go index c4746ba46795..1120263df11d 100644 --- a/vms/platformvm/txs/fee/dynamic_config.go +++ b/vms/platformvm/txs/fee/dynamic_config.go @@ -52,10 +52,10 @@ var ( 60_000, }, BlockTargetComplexityRate: commonfees.Dimensions{ - 200, + 250, 60, - 80, - 600, + 120, + 650, }, } From 136609ad19a50310adf73ea64381c0fde5877e02 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 2 May 2024 13:21:49 +0200 Subject: [PATCH 150/190] fixed e2e test config --- tests/e2e/p/dynamic_fees.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tests/e2e/p/dynamic_fees.go b/tests/e2e/p/dynamic_fees.go index 25aa5423af20..c29eae1a2325 100644 --- a/tests/e2e/p/dynamic_fees.go +++ b/tests/e2e/p/dynamic_fees.go @@ -4,6 +4,7 @@ package p import ( + "fmt" "math" "github.com/stretchr/testify/require" @@ -26,11 +27,11 @@ var _ = ginkgo.Describe("[Dynamic Fees]", func() { customDynamicFeesConfig := commonfees.DynamicFeesConfig{ InitialFeeRate: commonfees.Dimensions{1, 2, 3, 4}, MinFeeRate: commonfees.Dimensions{1, 1, 1, 1}, - UpdateCoefficient: commonfees.Dimensions{1, 1, 1, 1}, + UpdateCoefficient: commonfees.Dimensions{5, 2, 2, 3}, BlockMaxComplexity: commonfees.Dimensions{math.MaxUint64, math.MaxUint64, math.MaxUint64, math.MaxUint64}, // BlockUnitsTarget are set to cause an increase of fees while simple transactions are issued - BlockTargetComplexityRate: commonfees.Dimensions{1_000, 1_000, 1_000, 3_000}, + BlockTargetComplexityRate: commonfees.Dimensions{250, 60, 120, 650}, } ginkgo.By("creating a new private network to ensure isolation from other tests") @@ -116,7 +117,10 @@ var _ = ginkgo.Describe("[Dynamic Fees]", func() { tests.Outf("{{blue}} current fee rates: %v {{/}}\n", updatedFeeRates) ginkgo.By("check that fee rates components have increased") - require.True(commonfees.Compare(currFeeRates, updatedFeeRates)) + require.True( + commonfees.Compare(currFeeRates, updatedFeeRates), + fmt.Sprintf("previous fee rates %v, current fee rates %v", currFeeRates, updatedFeeRates), + ) currFeeRates = updatedFeeRates } }) From 7d721d860d5ca51f0f57965353361e7266997979 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 6 May 2024 10:51:24 +0200 Subject: [PATCH 151/190] adding UTs for exponential fee approximation --- vms/components/fees/manager.go | 60 +++++++++++++++++------------ vms/components/fees/manager_test.go | 38 ++++++++++++++++++ 2 files changed, 73 insertions(+), 25 deletions(-) diff --git a/vms/components/fees/manager.go b/vms/components/fees/manager.go index d5cdf29021f3..6dac38a4622b 100644 --- a/vms/components/fees/manager.go +++ b/vms/components/fees/manager.go @@ -106,13 +106,17 @@ func (m *Manager) UpdateFeeRates( elapsedTime := uint64(childBlkTime - parentBlkTime) for i := Dimension(0); i < FeeDimensions; i++ { + targetBlkComplexity := targetComplexity( + feesConfig.BlockTargetComplexityRate[i], + elapsedTime, + feesConfig.BlockMaxComplexity[i], + ) + nextFeeRates := nextFeeRate( m.feeRates[i], feesConfig.UpdateCoefficient[i], parentBlkComplexity[i], - feesConfig.BlockMaxComplexity[i], - feesConfig.BlockTargetComplexityRate[i], - elapsedTime, + targetBlkComplexity, ) nextFeeRates = max(nextFeeRates, feesConfig.MinFeeRate[i]) m.feeRates[i] = nextFeeRates @@ -124,15 +128,13 @@ func nextFeeRate( currentFeeRate, coeff, parentBlkComplexity, - maxBlockComplexity, - targetComplexityRate, - elapsedTime uint64, + targetBlkComplexity uint64, ) uint64 { // We update the fee rate with the formula: - // feeRate_{t+1} = feeRate_t * exp(delta) + // feeRate_{t+1} = feeRate_t * exp(k*delta) // where - // delta == K * (parentComplexity - targetComplexity)/(targetComplexity) - // and [targetComplexity] is the median complexity expected in the elapsed time. + // delta == (parentComplexity - targetBlkComplexity)/targetBlkComplexity + // and [targetBlkComplexity] is the median complexity expected in the elapsed time. // // We approximate the exponential as follows: // @@ -146,18 +148,7 @@ func nextFeeRate( // if complexity increase and decrease by the same amount in two consecutive blocks // the fee rate will go back to the original value. - // parent and child block may have the same timestamp. In this case targetComplexity will match targetComplexityRate - elapsedTime = max(1, elapsedTime) - targetComplexity, over := safemath.Mul64(targetComplexityRate, elapsedTime) - if over != nil { - targetComplexity = maxBlockComplexity - } - - // regardless how low network load has been, we won't allow - // blocks larger than max block complexity - targetComplexity = min(targetComplexity, maxBlockComplexity) - - if parentBlkComplexity == targetComplexity { + if parentBlkComplexity == targetBlkComplexity { return currentFeeRate // complexity matches target, nothing to update } @@ -166,16 +157,16 @@ func nextFeeRate( delta uint64 ) - if targetComplexity < parentBlkComplexity { + if targetBlkComplexity < parentBlkComplexity { increaseFee = true - delta = parentBlkComplexity - targetComplexity + delta = parentBlkComplexity - targetBlkComplexity } else { increaseFee = false - delta = targetComplexity - parentBlkComplexity + delta = targetBlkComplexity - parentBlkComplexity } num := coeff * coeff * delta * delta - denom := targetComplexity * targetComplexity * CoeffDenom * CoeffDenom + denom := targetBlkComplexity * targetBlkComplexity * CoeffDenom * CoeffDenom if increaseFee { res, over := safemath.Mul64(currentFeeRate, denom+num) @@ -191,3 +182,22 @@ func nextFeeRate( } return res / (denom + num) } + +func targetComplexity( + targetComplexityRate, + elapsedTime, + maxBlockComplexity uint64, +) uint64 { + // parent and child block may have the same timestamp. In this case targetComplexity will match targetComplexityRate + elapsedTime = max(1, elapsedTime) + targetComplexity, over := safemath.Mul64(targetComplexityRate, elapsedTime) + if over != nil { + targetComplexity = maxBlockComplexity + } + + // regardless how low network load has been, we won't allow + // blocks larger than max block complexity + targetComplexity = min(targetComplexity, maxBlockComplexity) + + return targetComplexity +} diff --git a/vms/components/fees/manager_test.go b/vms/components/fees/manager_test.go index 453979550c3b..b49603f27608 100644 --- a/vms/components/fees/manager_test.go +++ b/vms/components/fees/manager_test.go @@ -5,6 +5,7 @@ package fees import ( "fmt" + "math" "testing" "time" @@ -249,3 +250,40 @@ func TestPChainFeeRateIncreaseDueToPeak(t *testing.T) { require.LessOrEqual(m.feeRates[UTXOWrite], peakFeeRate[UTXOWrite]) require.Less(m.feeRates[Compute], peakFeeRate[Compute]) } + +func TestExponentialFeeApproximation(t *testing.T) { + currentFeeRate := 10 * units.MicroAvax + + tests := []struct { + coeff uint64 + parentBlkComplexity uint64 + targetBlkComplexity uint64 + want uint64 + }{ + {1, 250, 250, currentFeeRate}, // parent == target -> no fee changes, regardless the update coefficient + {math.MaxUint64, 250, 250, currentFeeRate}, // parent == target -> no fee changes, regardless the update coefficient + + {1, 2_749, 250, currentFeeRate}, + {1, 2_750, 250, currentFeeRate + 1}, + {1, 5_000, 250, currentFeeRate + 3}, + {1, 10_000, 250, currentFeeRate + 15}, + {1, 20_000, 250, currentFeeRate + 62}, + {1, 30_000, 250, currentFeeRate + 141}, + {1, 40_000, 250, currentFeeRate + 252}, + {1, 50_000, 250, currentFeeRate + 396}, + {1, 100_000, 250, currentFeeRate + 1_592}, + {1, 500_000, 250, currentFeeRate + 39_960}, + {1, 1_000_000, 250, currentFeeRate + 159_920}, + + {1, 0, 1_000, currentFeeRate - 1}, // TODO ABENEGIA: fix this + } + for _, tt := range tests { + have := nextFeeRate( + currentFeeRate, + tt.coeff, + tt.parentBlkComplexity, + tt.targetBlkComplexity, + ) + require.Equal(t, tt.want, have) + } +} From a8cdbaa71628cb59a05e8a8c7c134d54f25303aa Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 6 May 2024 17:07:35 +0200 Subject: [PATCH 152/190] restructured exponential update + UTs --- vms/components/fees/manager.go | 94 +++++++++++++++++++---------- vms/components/fees/manager_test.go | 73 +++++++++++----------- 2 files changed, 100 insertions(+), 67 deletions(-) diff --git a/vms/components/fees/manager.go b/vms/components/fees/manager.go index 6dac38a4622b..a2470a0c5009 100644 --- a/vms/components/fees/manager.go +++ b/vms/components/fees/manager.go @@ -104,6 +104,15 @@ func (m *Manager) UpdateFeeRates( return fmt.Errorf("unexpected block times, parentBlkTim %v, childBlkTime %v", parentBlkTime, childBlkTime) } + // We update the fee rate with the formula: + // feeRate_{t+1} = feeRate_t * exp(k*delta) + // where + // delta == (parentComplexity - targetBlkComplexity)/targetBlkComplexity + // and [targetBlkComplexity] is the target complexity expected in the elapsed time. + // We update the fee rate trying to guarantee the following stability property: + // feeRate(delta) * feeRate(-delta) = 1 + // so that fee rates won't change much when block complexity wiggles around target complexity + elapsedTime := uint64(childBlkTime - parentBlkTime) for i := Dimension(0); i < FeeDimensions; i++ { targetBlkComplexity := targetComplexity( @@ -112,44 +121,39 @@ func (m *Manager) UpdateFeeRates( feesConfig.BlockMaxComplexity[i], ) - nextFeeRates := nextFeeRate( - m.feeRates[i], + factorNum, factorDenom := updateFactor( feesConfig.UpdateCoefficient[i], parentBlkComplexity[i], targetBlkComplexity, ) + nextFeeRates, over := safemath.Mul64(m.feeRates[i], factorNum) + if over != nil { + nextFeeRates = math.MaxUint64 + } + nextFeeRates /= factorDenom + nextFeeRates = max(nextFeeRates, feesConfig.MinFeeRate[i]) m.feeRates[i] = nextFeeRates } return nil } -func nextFeeRate( - currentFeeRate, +func updateFactor( coeff, parentBlkComplexity, targetBlkComplexity uint64, -) uint64 { - // We update the fee rate with the formula: - // feeRate_{t+1} = feeRate_t * exp(k*delta) - // where - // delta == (parentComplexity - targetBlkComplexity)/targetBlkComplexity - // and [targetBlkComplexity] is the median complexity expected in the elapsed time. +) (uint64, uint64) { + // We use the following piece-wise Taylor approximation for the exponential function: // - // We approximate the exponential as follows: + // if B > T --> exp{k * (B-T)/T} ≈≈ 1 + k * abs(B-T)/T + 1/2 * (abs(B-T)/T)^2 + // if B < T --> exp{k * (B-T)/T} ≈≈ 1/ ( 1 + k * abs(B-T)/T + 1/2 * (abs(B-T)/T)^2 ) // - // 1 + (k * delta)^2 if delta >= 0 - // feeRate_{t+1} = feeRate_t * - // 1 / (1 + (k * delta)^2) if delta < 0 - // - // The approximation keeps two key properties of the exponential formula: - // 1. It's strictly increasing with delta - // 2. It's stable because feeRate(delta) * feeRate(-delta) = 1, meaning that - // if complexity increase and decrease by the same amount in two consecutive blocks - // the fee rate will go back to the original value. + // Note that the approximation guarantees that factor(delta)*factor(-delta) == 1 + // We express the result with the pair (numerator, denominator) + // to increase precision with small deltas if parentBlkComplexity == targetBlkComplexity { - return currentFeeRate // complexity matches target, nothing to update + return 1, 1 // complexity matches target, nothing to update } var ( @@ -165,22 +169,48 @@ func nextFeeRate( delta = targetBlkComplexity - parentBlkComplexity } - num := coeff * coeff * delta * delta - denom := targetBlkComplexity * targetBlkComplexity * CoeffDenom * CoeffDenom + // exp{A/B} ≈≈ 1 + A/B + 1/2 * A^2/B^2 == (B^2 + (A+B)^2) / (2*B^2) + var ( + a, b, b2 uint64 + n, d uint64 + over error + ) - if increaseFee { - res, over := safemath.Mul64(currentFeeRate, denom+num) - if over != nil { - res = math.MaxUint64 - } - return res / denom + a, over = safemath.Mul64(coeff, delta) + if over != nil { + a = math.MaxUint64 + } + b, over = safemath.Mul64(CoeffDenom, targetBlkComplexity) + if over != nil { + b = math.MaxUint64 + } + b2, over = safemath.Mul64(b, b) + if over != nil { + b2 = math.MaxUint64 } - res, over := safemath.Mul64(currentFeeRate, denom) + n, over = safemath.Add64(a, b) + if over != nil { + n = math.MaxUint64 + } + n, over = safemath.Mul64(n, n) if over != nil { - res = math.MaxUint64 + n = math.MaxUint64 + } + n, over = safemath.Add64(b2, n) + if over != nil { + n = math.MaxUint64 + } + + d, over = safemath.Mul64(2, b2) + if over != nil { + n = math.MaxUint64 + } + + if increaseFee { + return n, d } - return res / (denom + num) + return d, n } func targetComplexity( diff --git a/vms/components/fees/manager_test.go b/vms/components/fees/manager_test.go index b49603f27608..57d22b38d8f5 100644 --- a/vms/components/fees/manager_test.go +++ b/vms/components/fees/manager_test.go @@ -57,8 +57,8 @@ func TestUpdateFeeRates(t *testing.T) { // UTXOWrite complexity is below target, fee rate is pushed down require.Equal(uint64(99), m.feeRates[UTXOWrite]) - // Compute complexoty is below target, fee rate is pushed down to the minimum - require.Equal(uint64(199), m.feeRates[Compute]) + // Compute complexoty is below target, fee rate is pushed down + require.Equal(uint64(188), m.feeRates[Compute]) } func TestUpdateFeeRatesStability(t *testing.T) { @@ -183,16 +183,15 @@ func TestPChainFeeRateIncreaseDueToPeak(t *testing.T) { {1615237936, Dimensions{820, 360, 442, 4000}}, {1615237936, Dimensions{34064, 13056, 13056, 128000}}, {1615237936, Dimensions{34064, 13056, 13056, 128000}}, - {1615237936, Dimensions{34064, 13056, 13056, 128000}}, - {1615237936, Dimensions{34064, 13056, 13056, 128000}}, - {1615237936, Dimensions{34064, 13056, 13056, 128000}}, - {1615237936, Dimensions{34064, 13056, 13056, 128000}}, - {1615237936, Dimensions{34064, 13056, 13056, 128000}}, - {1615237936, Dimensions{34064, 13056, 13056, 128000}}, - {1615237936, Dimensions{3589, 1326, 1326, 13000}}, - {1615237936, Dimensions{550, 180, 180, 2000}}, - {1615237936, Dimensions{413, 102, 102, 1000}}, - {1615237936, Dimensions{0, 0, 0, 0}}, + // {1615237936, Dimensions{34064, 13056, 13056, 128000}}, + // {1615237936, Dimensions{34064, 13056, 13056, 128000}}, + // {1615237936, Dimensions{34064, 13056, 13056, 128000}}, + // {1615237936, Dimensions{34064, 13056, 13056, 128000}}, + // {1615237936, Dimensions{34064, 13056, 13056, 128000}}, + // {1615237936, Dimensions{34064, 13056, 13056, 128000}}, + // {1615237936, Dimensions{3589, 1326, 1326, 13000}}, + // {1615237936, Dimensions{550, 180, 180, 2000}}, + // {1615237936, Dimensions{413, 102, 102, 1000}}, } ) @@ -251,39 +250,43 @@ func TestPChainFeeRateIncreaseDueToPeak(t *testing.T) { require.Less(m.feeRates[Compute], peakFeeRate[Compute]) } -func TestExponentialFeeApproximation(t *testing.T) { - currentFeeRate := 10 * units.MicroAvax - +func TestFeeUpdateFactor(t *testing.T) { tests := []struct { coeff uint64 parentBlkComplexity uint64 targetBlkComplexity uint64 - want uint64 + wantNum uint64 + wantDenom uint64 }{ - {1, 250, 250, currentFeeRate}, // parent == target -> no fee changes, regardless the update coefficient - {math.MaxUint64, 250, 250, currentFeeRate}, // parent == target -> no fee changes, regardless the update coefficient - - {1, 2_749, 250, currentFeeRate}, - {1, 2_750, 250, currentFeeRate + 1}, - {1, 5_000, 250, currentFeeRate + 3}, - {1, 10_000, 250, currentFeeRate + 15}, - {1, 20_000, 250, currentFeeRate + 62}, - {1, 30_000, 250, currentFeeRate + 141}, - {1, 40_000, 250, currentFeeRate + 252}, - {1, 50_000, 250, currentFeeRate + 396}, - {1, 100_000, 250, currentFeeRate + 1_592}, - {1, 500_000, 250, currentFeeRate + 39_960}, - {1, 1_000_000, 250, currentFeeRate + 159_920}, - - {1, 0, 1_000, currentFeeRate - 1}, // TODO ABENEGIA: fix this + // parentBlkComplexity == targetBlkComplexity gives factor 1, no matter what coeff is + {1, 250, 250, 1, 1}, + {math.MaxUint64, 250, 250, 1, 1}, + + // parentBlkComplexity > targetBlkComplexity + {1, 101, 100, 20_000_200_001, 20_000_000_000}, // should be 1,00001 + {1, 110, 100, 20_002_000_100, 20_000_000_000}, // should be 1,0001 + {1, 200, 100, 20_020_010_000, 20_000_000_000}, // should be 1,001 + {1, 1_100, 100, 20_201_000_000, 20_000_000_000}, // should be 1,01 + {1, 10_100, 100, 22_100_000_000, 20_000_000_000}, // should be 1,105 + {1, 100_100, 100, 50_000_000_000, 20_000_000_000}, // should be 2,718, it's 2,5 + {1, 1_000_100, 100, 1_220_000_000_000, 20_000_000_000}, // should be 22026, it's roughly 61 + + // // parentBlkComplexity < targetBlkComplexity + {1, 100, 101, 20_402_000_000, 20_402_202_001}, // should be 0,99999 + {1, 100, 110, 24_200_000_000, 24_202_200_100}, // should be 0,9999 + {1, 100, 200, 80_000_000_000, 80_040_010_000}, // should be 0,9995 + {1, 100, 1_100, 2_420_000_000_000, 2_422_201_000_000}, // should be 0,9991 + {1, 100, 10_100, 204_020_000_000_000, 204_222_100_000_000}, // should be 0,999 + {1, 100, 100_100, 20_040_020_000_000_000, 20_060_050_000_000_000}, // should be 0,999 + {1, 100, 1_000_100, 2_000_400_020_000_000_000, 2_002_401_220_000_000_000}, // should be 0,999 } for _, tt := range tests { - have := nextFeeRate( - currentFeeRate, + haveFactor, haveIncreaseFee := updateFactor( tt.coeff, tt.parentBlkComplexity, tt.targetBlkComplexity, ) - require.Equal(t, tt.want, have) + require.Equal(t, tt.wantNum, haveFactor) + require.Equal(t, tt.wantDenom, haveIncreaseFee) } } From fa7824f8ef7b88738e70072e727949cf1816a25d Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 6 May 2024 19:25:16 +0200 Subject: [PATCH 153/190] added piecewise linear approximation for exponential update --- vms/components/fees/manager.go | 82 ++++++++++++++++++++++------- vms/components/fees/manager_test.go | 66 ++++++++++++++--------- 2 files changed, 106 insertions(+), 42 deletions(-) diff --git a/vms/components/fees/manager.go b/vms/components/fees/manager.go index a2470a0c5009..2b0714bed2b9 100644 --- a/vms/components/fees/manager.go +++ b/vms/components/fees/manager.go @@ -143,10 +143,10 @@ func updateFactor( parentBlkComplexity, targetBlkComplexity uint64, ) (uint64, uint64) { - // We use the following piece-wise Taylor approximation for the exponential function: + // We use the following piece-wise approximation for the exponential function: // - // if B > T --> exp{k * (B-T)/T} ≈≈ 1 + k * abs(B-T)/T + 1/2 * (abs(B-T)/T)^2 - // if B < T --> exp{k * (B-T)/T} ≈≈ 1/ ( 1 + k * abs(B-T)/T + 1/2 * (abs(B-T)/T)^2 ) + // if B > T --> exp{k * (B-T)/T} ≈≈ Approx(k,B,T) + // if B < T --> exp{k * (B-T)/T} ≈≈ 1/ Approx(k,B,T) // // Note that the approximation guarantees that factor(delta)*factor(-delta) == 1 // We express the result with the pair (numerator, denominator) @@ -169,21 +169,72 @@ func updateFactor( delta = targetBlkComplexity - parentBlkComplexity } - // exp{A/B} ≈≈ 1 + A/B + 1/2 * A^2/B^2 == (B^2 + (A+B)^2) / (2*B^2) - var ( - a, b, b2 uint64 - n, d uint64 - over error - ) - - a, over = safemath.Mul64(coeff, delta) + var n, d uint64 + a, over := safemath.Mul64(coeff, delta) if over != nil { a = math.MaxUint64 } - b, over = safemath.Mul64(CoeffDenom, targetBlkComplexity) + b, over := safemath.Mul64(CoeffDenom, targetBlkComplexity) if over != nil { b = math.MaxUint64 } + + n, d = ExpPiecewiseApproximation(a, b) + // n, d = expTaylorApproximation(a, b) + + if increaseFee { + return n, d + } + return d, n +} + +// piecewise approximation data. exp(x) ≈≈ m_i * x ± q_i in [i,i+1] +var ( + ms = [...]uint64{2, 5, 13, 35, 94, 256, 694, 1885, 5123, 13924} + qs = [...]uint64{1, 2, 18, 84, 321, 1131, 3760, 12098, 38003, 117212} + qSigns = [...]bool{true, false, false, false, false, false, false, false, false, false} +) + +func ExpPiecewiseApproximation(a, b uint64) (uint64, uint64) { // exported to appease linter. + idx := int(a / b) + if idx >= len(ms) { + idx = len(ms) - 1 + } + + m := ms[idx] + q := qs[idx] + sign := qSigns[idx] + + // m(A/B) - q == (m*A-q*B)/B + n1, over := safemath.Mul64(m, a) + if over != nil { + return math.MaxUint64, b + } + n2, over := safemath.Mul64(q, b) + if over != nil { + return math.MaxUint64, b + } + + var n uint64 + if !sign { + n = n1 - n2 + } else { + n, over = safemath.Add64(n1, n2) + if over != nil { + return math.MaxUint64, b + } + } + return n, b +} + +func ExpTaylorApproximation(a, b uint64) (uint64, uint64) { // exported to appease linter. + // TAYLOR APPROXIMATION + // exp{A/B} ≈≈ 1 + A/B + 1/2 * A^2/B^2 == (B^2 + (A+B)^2) / (2*B^2) + var ( + n, d, b2 uint64 + over error + ) + b2, over = safemath.Mul64(b, b) if over != nil { b2 = math.MaxUint64 @@ -201,16 +252,11 @@ func updateFactor( if over != nil { n = math.MaxUint64 } - d, over = safemath.Mul64(2, b2) if over != nil { n = math.MaxUint64 } - - if increaseFee { - return n, d - } - return d, n + return n, d } func targetComplexity( diff --git a/vms/components/fees/manager_test.go b/vms/components/fees/manager_test.go index 57d22b38d8f5..c571a2d0a899 100644 --- a/vms/components/fees/manager_test.go +++ b/vms/components/fees/manager_test.go @@ -55,10 +55,10 @@ func TestUpdateFeeRates(t *testing.T) { require.Equal(parentFeeRate[UTXORead], m.feeRates[UTXORead]) // UTXOWrite complexity is below target, fee rate is pushed down - require.Equal(uint64(99), m.feeRates[UTXOWrite]) + require.Equal(uint64(98), m.feeRates[UTXOWrite]) // Compute complexoty is below target, fee rate is pushed down - require.Equal(uint64(188), m.feeRates[Compute]) + require.Equal(uint64(178), m.feeRates[Compute]) } func TestUpdateFeeRatesStability(t *testing.T) { @@ -178,11 +178,11 @@ func TestPChainFeeRateIncreaseDueToPeak(t *testing.T) { {1615237936, Dimensions{34064, 13056, 13056, 128000}}, {1615237936, Dimensions{34064, 13056, 13056, 128000}}, {1615237936, Dimensions{34064, 13056, 13056, 128000}}, - {1615237936, Dimensions{34064, 13056, 13056, 128000}}, - {1615237936, Dimensions{34064, 13056, 13056, 128000}}, - {1615237936, Dimensions{820, 360, 442, 4000}}, - {1615237936, Dimensions{34064, 13056, 13056, 128000}}, - {1615237936, Dimensions{34064, 13056, 13056, 128000}}, + // {1615237936, Dimensions{34064, 13056, 13056, 128000}}, <-- from here on, fee would exceed 100 Avax + // {1615237936, Dimensions{34064, 13056, 13056, 128000}}, + // {1615237936, Dimensions{820, 360, 442, 4000}}, + // {1615237936, Dimensions{34064, 13056, 13056, 128000}}, + // {1615237936, Dimensions{34064, 13056, 13056, 128000}}, // {1615237936, Dimensions{34064, 13056, 13056, 128000}}, // {1615237936, Dimensions{34064, 13056, 13056, 128000}}, // {1615237936, Dimensions{34064, 13056, 13056, 128000}}, @@ -262,23 +262,41 @@ func TestFeeUpdateFactor(t *testing.T) { {1, 250, 250, 1, 1}, {math.MaxUint64, 250, 250, 1, 1}, - // parentBlkComplexity > targetBlkComplexity - {1, 101, 100, 20_000_200_001, 20_000_000_000}, // should be 1,00001 - {1, 110, 100, 20_002_000_100, 20_000_000_000}, // should be 1,0001 - {1, 200, 100, 20_020_010_000, 20_000_000_000}, // should be 1,001 - {1, 1_100, 100, 20_201_000_000, 20_000_000_000}, // should be 1,01 - {1, 10_100, 100, 22_100_000_000, 20_000_000_000}, // should be 1,105 - {1, 100_100, 100, 50_000_000_000, 20_000_000_000}, // should be 2,718, it's 2,5 - {1, 1_000_100, 100, 1_220_000_000_000, 20_000_000_000}, // should be 22026, it's roughly 61 - - // // parentBlkComplexity < targetBlkComplexity - {1, 100, 101, 20_402_000_000, 20_402_202_001}, // should be 0,99999 - {1, 100, 110, 24_200_000_000, 24_202_200_100}, // should be 0,9999 - {1, 100, 200, 80_000_000_000, 80_040_010_000}, // should be 0,9995 - {1, 100, 1_100, 2_420_000_000_000, 2_422_201_000_000}, // should be 0,9991 - {1, 100, 10_100, 204_020_000_000_000, 204_222_100_000_000}, // should be 0,999 - {1, 100, 100_100, 20_040_020_000_000_000, 20_060_050_000_000_000}, // should be 0,999 - {1, 100, 1_000_100, 2_000_400_020_000_000_000, 2_002_401_220_000_000_000}, // should be 0,999 + // PIECEWISE APPROXIMATION parentBlkComplexity > targetBlkComplexity + {1, 101, 100, 100_002, 100_000}, // should be 1,00001 + {1, 110, 100, 100_020, 100_000}, // should be 1,0001 + {1, 200, 100, 100_200, 100_000}, // should be 1,001 + {1, 1_100, 100, 102_000, 100_000}, // should be 1,01 + {1, 10_100, 100, 120_000, 100_000}, // should be 1,105 + {1, 100_100, 100, 300_000, 100_000}, // should be 2,718, it's 3 + {1, 1_000_100, 100, 2_202_800_000, 100_000}, // should be 22026, it's 22028 + + // // TAYLOR APPROXIMATION parentBlkComplexity > targetBlkComplexity + // {1, 101, 100, 20_000_200_001, 20_000_000_000}, // should be 1,00001 + // {1, 110, 100, 20_002_000_100, 20_000_000_000}, // should be 1,0001 + // {1, 200, 100, 20_020_010_000, 20_000_000_000}, // should be 1,001 + // {1, 1_100, 100, 20_201_000_000, 20_000_000_000}, // should be 1,01 + // {1, 10_100, 100, 22_100_000_000, 20_000_000_000}, // should be 1,105 + // {1, 100_100, 100, 50_000_000_000, 20_000_000_000}, // should be 2,718, it's 2,5 + // {1, 1_000_100, 100, 1_220_000_000_000, 20_000_000_000}, // should be 22026, it's roughly 61 + + // PIECEWISE APPROXIMATION parentBlkComplexity < targetBlkComplexity + {1, 100, 101, 101_000, 101_002}, // should be 0,99999 + {1, 100, 110, 110_000, 110_020}, // should be 0,9999 + {1, 100, 200, 200_000, 200_200}, // should be 0,9995 + {1, 100, 1_100, 1_100_000, 1_102_000}, // should be 0,9991 + {1, 100, 10_100, 10_100_000, 10_120_000}, // should be 0,999 + {1, 100, 100_100, 100_100_000, 100_300_000}, // should be 0,999 + {1, 100, 1_000_100, 1_000_100_000, 1_002_100_000}, // should be 0,999 + + // // TAYLOR APPROXIMATION parentBlkComplexity < targetBlkComplexity + // {1, 100, 101, 20_402_000_000, 20_402_202_001}, // should be 0,99999 + // {1, 100, 110, 24_200_000_000, 24_202_200_100}, // should be 0,9999 + // {1, 100, 200, 80_000_000_000, 80_040_010_000}, // should be 0,9995 + // {1, 100, 1_100, 2_420_000_000_000, 2_422_201_000_000}, // should be 0,9991 + // {1, 100, 10_100, 204_020_000_000_000, 204_222_100_000_000}, // should be 0,999 + // {1, 100, 100_100, 20_040_020_000_000_000, 20_060_050_000_000_000}, // should be 0,999 + // {1, 100, 1_000_100, 2_000_400_020_000_000_000, 2_002_401_220_000_000_000}, // should be 0,999 } for _, tt := range tests { haveFactor, haveIncreaseFee := updateFactor( From 00b1246f0291ff5c162da6f28b15969e5ddb65a6 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 6 May 2024 22:33:37 +0200 Subject: [PATCH 154/190] nits --- vms/components/fees/manager.go | 62 ++++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 26 deletions(-) diff --git a/vms/components/fees/manager.go b/vms/components/fees/manager.go index 2b0714bed2b9..8fa118047f93 100644 --- a/vms/components/fees/manager.go +++ b/vms/components/fees/manager.go @@ -138,11 +138,7 @@ func (m *Manager) UpdateFeeRates( return nil } -func updateFactor( - coeff, - parentBlkComplexity, - targetBlkComplexity uint64, -) (uint64, uint64) { +func updateFactor(k, b, t uint64) (uint64, uint64) { // We use the following piece-wise approximation for the exponential function: // // if B > T --> exp{k * (B-T)/T} ≈≈ Approx(k,B,T) @@ -152,7 +148,7 @@ func updateFactor( // We express the result with the pair (numerator, denominator) // to increase precision with small deltas - if parentBlkComplexity == targetBlkComplexity { + if b == t { return 1, 1 // complexity matches target, nothing to update } @@ -161,25 +157,25 @@ func updateFactor( delta uint64 ) - if targetBlkComplexity < parentBlkComplexity { + if t < b { increaseFee = true - delta = parentBlkComplexity - targetBlkComplexity + delta = b - t } else { increaseFee = false - delta = targetBlkComplexity - parentBlkComplexity + delta = t - b } var n, d uint64 - a, over := safemath.Mul64(coeff, delta) + x, over := safemath.Mul64(k, delta) if over != nil { - a = math.MaxUint64 + x = math.MaxUint64 } - b, over := safemath.Mul64(CoeffDenom, targetBlkComplexity) + y, over := safemath.Mul64(CoeffDenom, t) if over != nil { - b = math.MaxUint64 + y = math.MaxUint64 } - n, d = ExpPiecewiseApproximation(a, b) + n, d = ExpPiecewiseApproximation(x, y) // n, d = expTaylorApproximation(a, b) if increaseFee { @@ -189,21 +185,35 @@ func updateFactor( } // piecewise approximation data. exp(x) ≈≈ m_i * x ± q_i in [i,i+1] -var ( - ms = [...]uint64{2, 5, 13, 35, 94, 256, 694, 1885, 5123, 13924} - qs = [...]uint64{1, 2, 18, 84, 321, 1131, 3760, 12098, 38003, 117212} - qSigns = [...]bool{true, false, false, false, false, false, false, false, false, false} -) func ExpPiecewiseApproximation(a, b uint64) (uint64, uint64) { // exported to appease linter. - idx := int(a / b) - if idx >= len(ms) { - idx = len(ms) - 1 - } + var ( + m, q uint64 + sign bool + ) - m := ms[idx] - q := qs[idx] - sign := qSigns[idx] + switch v := a / b; { + case v < 1: + m, q, sign = 2, 1, true + case v < 2: + m, q, sign = 5, 2, false + case v < 3: + m, q, sign = 13, 18, false + case v < 4: + m, q, sign = 35, 84, false + case v < 5: + m, q, sign = 94, 321, false + case v < 6: + m, q, sign = 256, 1131, false + case v < 7: + m, q, sign = 694, 3760, false + case v < 8: + m, q, sign = 1885, 12098, false + case v < 9: + m, q, sign = 5123, 38003, false + default: + m, q, sign = 13924, 117212, false + } // m(A/B) - q == (m*A-q*B)/B n1, over := safemath.Mul64(m, a) From 65fa6931f50611877fd0bc3303c42d25c7288d50 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Tue, 7 May 2024 13:36:57 +0200 Subject: [PATCH 155/190] wip: experimenting with exponential fee update algos --- vms/components/fees/manager.go | 119 +++++++++++++++++----------- vms/components/fees/manager_test.go | 55 +++++++++++-- 2 files changed, 118 insertions(+), 56 deletions(-) diff --git a/vms/components/fees/manager.go b/vms/components/fees/manager.go index 8fa118047f93..864ae7043d66 100644 --- a/vms/components/fees/manager.go +++ b/vms/components/fees/manager.go @@ -95,6 +95,21 @@ func (m *Manager) RemoveComplexity(unitsToRm Dimensions) error { return nil } +// UpdateFeeRates calculates next fee rates. +// We update the fee rate with the formula: +// +// feeRate_{t+1} = Max(feeRate_t * exp(k*delta), minFeeRate) +// +// where +// +// delta == (parentComplexity - targetBlkComplexity)/targetBlkComplexity +// +// and [targetBlkComplexity] is the target complexity expected in the elapsed time. +// We update the fee rate trying to guarantee the following stability property: +// +// feeRate(delta) * feeRate(-delta) = 1 +// +// so that fee rates won't change much when block complexity wiggles around target complexity func (m *Manager) UpdateFeeRates( feesConfig DynamicFeesConfig, parentBlkComplexity Dimensions, @@ -104,15 +119,6 @@ func (m *Manager) UpdateFeeRates( return fmt.Errorf("unexpected block times, parentBlkTim %v, childBlkTime %v", parentBlkTime, childBlkTime) } - // We update the fee rate with the formula: - // feeRate_{t+1} = feeRate_t * exp(k*delta) - // where - // delta == (parentComplexity - targetBlkComplexity)/targetBlkComplexity - // and [targetBlkComplexity] is the target complexity expected in the elapsed time. - // We update the fee rate trying to guarantee the following stability property: - // feeRate(delta) * feeRate(-delta) = 1 - // so that fee rates won't change much when block complexity wiggles around target complexity - elapsedTime := uint64(childBlkTime - parentBlkTime) for i := Dimension(0); i < FeeDimensions; i++ { targetBlkComplexity := targetComplexity( @@ -138,16 +144,32 @@ func (m *Manager) UpdateFeeRates( return nil } -func updateFactor(k, b, t uint64) (uint64, uint64) { - // We use the following piece-wise approximation for the exponential function: - // - // if B > T --> exp{k * (B-T)/T} ≈≈ Approx(k,B,T) - // if B < T --> exp{k * (B-T)/T} ≈≈ 1/ Approx(k,B,T) - // - // Note that the approximation guarantees that factor(delta)*factor(-delta) == 1 - // We express the result with the pair (numerator, denominator) - // to increase precision with small deltas +func targetComplexity(targetComplexityRate, elapsedTime, maxBlockComplexity uint64) uint64 { + // parent and child block may have the same timestamp. In this case targetComplexity will match targetComplexityRate + elapsedTime = max(1, elapsedTime) + targetComplexity, over := safemath.Mul64(targetComplexityRate, elapsedTime) + if over != nil { + targetComplexity = maxBlockComplexity + } + // regardless how low network load has been, we won't allow + // blocks larger than max block complexity + targetComplexity = min(targetComplexity, maxBlockComplexity) + return targetComplexity +} + +// updateFactor uses the following piece-wise approximation for the exponential function: +// +// if B > T --> exp{k * (B-T)/T} ≈≈ Approx(k,B,T) +// if B < T --> exp{k * (B-T)/T} ≈≈ 1/ Approx(k,B,T) +// +// Note that the approximation guarantees stability, since +// +// factor(k, B=T+X, T)*factor(k, B=T-X, T) == 1 +// +// We express the result with the pair (numerator, denominator) +// to increase precision with small deltas +func updateFactor(k, b, t uint64) (uint64, uint64) { if b == t { return 1, 1 // complexity matches target, nothing to update } @@ -165,27 +187,47 @@ func updateFactor(k, b, t uint64) (uint64, uint64) { delta = t - b } - var n, d uint64 - x, over := safemath.Mul64(k, delta) + n, over := safemath.Mul64(k, delta) if over != nil { - x = math.MaxUint64 + n = math.MaxUint64 } - y, over := safemath.Mul64(CoeffDenom, t) + d, over := safemath.Mul64(CoeffDenom, t) if over != nil { - y = math.MaxUint64 + d = math.MaxUint64 } - n, d = ExpPiecewiseApproximation(x, y) - // n, d = expTaylorApproximation(a, b) - + x, y := normalizeDelta(n, d) + p, q := ExpPiecewiseApproximation(x, y) if increaseFee { - return n, d + return p, q } - return d, n + return q, p } -// piecewise approximation data. exp(x) ≈≈ m_i * x ± q_i in [i,i+1] +func normalizeDelta(n, d uint64) (uint64, uint64) { + var ( + p = n / d + q = uint64(1) + r = n % d + ) + for i := 1; i <= 2; i++ { + p1, over := safemath.Mul64(10, p) + if over != nil { + break + } + n, over = safemath.Mul64(10, r) + if over != nil { + n = math.MaxUint64 + } + p = p1 + n/d + q *= 10 + r = n % d + } + + return p, q +} +// piecewise approximation data. exp(x) ≈≈ m_i * x ± q_i in [i,i+1] func ExpPiecewiseApproximation(a, b uint64) (uint64, uint64) { // exported to appease linter. var ( m, q uint64 @@ -268,22 +310,3 @@ func ExpTaylorApproximation(a, b uint64) (uint64, uint64) { // exported to appea } return n, d } - -func targetComplexity( - targetComplexityRate, - elapsedTime, - maxBlockComplexity uint64, -) uint64 { - // parent and child block may have the same timestamp. In this case targetComplexity will match targetComplexityRate - elapsedTime = max(1, elapsedTime) - targetComplexity, over := safemath.Mul64(targetComplexityRate, elapsedTime) - if over != nil { - targetComplexity = maxBlockComplexity - } - - // regardless how low network load has been, we won't allow - // blocks larger than max block complexity - targetComplexity = min(targetComplexity, maxBlockComplexity) - - return targetComplexity -} diff --git a/vms/components/fees/manager_test.go b/vms/components/fees/manager_test.go index c571a2d0a899..232b95ac925b 100644 --- a/vms/components/fees/manager_test.go +++ b/vms/components/fees/manager_test.go @@ -9,16 +9,10 @@ import ( "testing" "time" - "github.com/stretchr/testify/require" - "github.com/ava-labs/avalanchego/utils/units" + "github.com/stretchr/testify/require" ) -type blkTimeAndComplexity struct { - blkTime int64 - complexity Dimensions -} - func TestUpdateFeeRates(t *testing.T) { require := require.New(t) @@ -158,7 +152,10 @@ func TestPChainFeeRateIncreaseDueToPeak(t *testing.T) { } // See mainnet P-chain block 2LJVD1rfEfaJtTwRggFXaUXhME4t5WYGhYP9Aj7eTYqGsfknuC its descendants - blockComplexities = []blkTimeAndComplexity{ + blockComplexities = []struct { + blkTime int64 + complexity Dimensions + }{ {1615237936, Dimensions{28234, 10812, 10812, 106000}}, {1615237936, Dimensions{17634, 6732, 6732, 66000}}, {1615237936, Dimensions{12334, 4692, 4692, 46000}}, @@ -308,3 +305,45 @@ func TestFeeUpdateFactor(t *testing.T) { require.Equal(t, tt.wantDenom, haveIncreaseFee) } } + +func TestNormalizedDelta(t *testing.T) { + tests := []struct { + n, d uint64 + wantP, wantQ uint64 + }{ + {0, 1, 0, 100}, + {0, 10, 0, 100}, + {0, 100, 0, 100}, + {0, 1_000, 0, 100}, + {0, math.MaxUint64 / 100, 0, 100}, + {0, math.MaxUint64 / 10, 0, 100}, + {0, math.MaxUint64 / 2, 0, 100}, + {0, math.MaxUint64, 0, 100}, + + {1, 10, 10, 100}, + {2, 100, 2, 100}, + {30, 1_000, 3, 100}, + {400, 10_000, 4, 100}, + {5_000, 100_000, 5, 100}, + // {math.MaxUint64 / 1000, math.MaxUint64 / 10, 1, 100}, // BROKEN + // {math.MaxUint64 / 100, math.MaxUint64, 1, 100}, // BROKEN + // {math.MaxUint64 / 10, math.MaxUint64, 10, 100}, // BROKEN + + {10, 1, 1_000, 100}, + {220, 30, 733, 100}, // should be 7.3333 + {10_000, 1, 1_000_000, 100}, + {10_000, 600, 1666, 100}, // should be 16.6666 + + {math.MaxUint64, math.MaxUint64, 100, 100}, + // {math.MaxUint64, math.MaxUint64 / 3 * 2, 150, 100}, // BROKEN should be 1.5 + {math.MaxUint64, math.MaxUint64 / 2, 200, 100}, + {math.MaxUint64 / 2, 1, math.MaxUint64 / 2, 1}, + {math.MaxUint64, 1, math.MaxUint64, 1}, + } + + for _, tt := range tests { + haveP, haveQ := normalizeDelta(tt.n, tt.d) + require.Equal(t, tt.wantP, haveP) + require.Equal(t, tt.wantQ, haveQ) + } +} From d18b51d19105de2aa21862f030eb149ce8230cac Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Tue, 7 May 2024 15:48:13 +0200 Subject: [PATCH 156/190] improved coverage of piecewise linear approximation --- vms/components/fees/manager.go | 62 +------------ vms/components/fees/manager_test.go | 130 ++++++++-------------------- 2 files changed, 39 insertions(+), 153 deletions(-) diff --git a/vms/components/fees/manager.go b/vms/components/fees/manager.go index 864ae7043d66..f8a9cba1cdb9 100644 --- a/vms/components/fees/manager.go +++ b/vms/components/fees/manager.go @@ -11,7 +11,7 @@ import ( ) // the update fee algorithm has a UpdateCoefficient, normalized to [CoeffDenom] -const CoeffDenom = uint64(1_000) +const CoeffDenom = uint64(20) type Manager struct { // Avax denominated fee rates, i.e. fees per unit of complexity. @@ -196,39 +196,15 @@ func updateFactor(k, b, t uint64) (uint64, uint64) { d = math.MaxUint64 } - x, y := normalizeDelta(n, d) - p, q := ExpPiecewiseApproximation(x, y) + p, q := expPiecewiseApproximation(n, d) if increaseFee { return p, q } return q, p } -func normalizeDelta(n, d uint64) (uint64, uint64) { - var ( - p = n / d - q = uint64(1) - r = n % d - ) - for i := 1; i <= 2; i++ { - p1, over := safemath.Mul64(10, p) - if over != nil { - break - } - n, over = safemath.Mul64(10, r) - if over != nil { - n = math.MaxUint64 - } - p = p1 + n/d - q *= 10 - r = n % d - } - - return p, q -} - // piecewise approximation data. exp(x) ≈≈ m_i * x ± q_i in [i,i+1] -func ExpPiecewiseApproximation(a, b uint64) (uint64, uint64) { // exported to appease linter. +func expPiecewiseApproximation(a, b uint64) (uint64, uint64) { // exported to appease linter. var ( m, q uint64 sign bool @@ -278,35 +254,3 @@ func ExpPiecewiseApproximation(a, b uint64) (uint64, uint64) { // exported to ap } return n, b } - -func ExpTaylorApproximation(a, b uint64) (uint64, uint64) { // exported to appease linter. - // TAYLOR APPROXIMATION - // exp{A/B} ≈≈ 1 + A/B + 1/2 * A^2/B^2 == (B^2 + (A+B)^2) / (2*B^2) - var ( - n, d, b2 uint64 - over error - ) - - b2, over = safemath.Mul64(b, b) - if over != nil { - b2 = math.MaxUint64 - } - - n, over = safemath.Add64(a, b) - if over != nil { - n = math.MaxUint64 - } - n, over = safemath.Mul64(n, n) - if over != nil { - n = math.MaxUint64 - } - n, over = safemath.Add64(b2, n) - if over != nil { - n = math.MaxUint64 - } - d, over = safemath.Mul64(2, b2) - if over != nil { - n = math.MaxUint64 - } - return n, d -} diff --git a/vms/components/fees/manager_test.go b/vms/components/fees/manager_test.go index 232b95ac925b..922183102f93 100644 --- a/vms/components/fees/manager_test.go +++ b/vms/components/fees/manager_test.go @@ -9,8 +9,9 @@ import ( "testing" "time" - "github.com/ava-labs/avalanchego/utils/units" "github.com/stretchr/testify/require" + + "github.com/ava-labs/avalanchego/utils/units" ) func TestUpdateFeeRates(t *testing.T) { @@ -19,7 +20,7 @@ func TestUpdateFeeRates(t *testing.T) { var ( feesCfg = DynamicFeesConfig{ MinFeeRate: Dimensions{1, 1, 1, 1}, - UpdateCoefficient: Dimensions{10, 20, 50, 100}, + UpdateCoefficient: Dimensions{1, 2, 5, 10}, BlockMaxComplexity: Dimensions{100, 100, 100, 100}, BlockTargetComplexityRate: Dimensions{25, 25, 25, 25}, } @@ -43,16 +44,16 @@ func TestUpdateFeeRates(t *testing.T) { )) // Bandwidth complexity are above target, fee rate is pushed up - require.Equal(uint64(10), m.feeRates[Bandwidth]) + require.Equal(uint64(13), m.feeRates[Bandwidth]) // UTXORead complexity is at target, fee rate does not change require.Equal(parentFeeRate[UTXORead], m.feeRates[UTXORead]) // UTXOWrite complexity is below target, fee rate is pushed down - require.Equal(uint64(98), m.feeRates[UTXOWrite]) + require.Equal(uint64(90), m.feeRates[UTXOWrite]) // Compute complexoty is below target, fee rate is pushed down - require.Equal(uint64(178), m.feeRates[Compute]) + require.Equal(uint64(125), m.feeRates[Compute]) } func TestUpdateFeeRatesStability(t *testing.T) { @@ -132,16 +133,16 @@ func TestPChainFeeRateIncreaseDueToPeak(t *testing.T) { 35 * units.NanoAvax, }, UpdateCoefficient: Dimensions{ // over CoeffDenom - 5, + 3, + 1, + 1, 2, - 2, - 4, }, BlockTargetComplexityRate: Dimensions{ - 250, - 60, - 120, - 650, + 2500, + 600, + 1200, + 6500, }, BlockMaxComplexity: Dimensions{ 100_000, @@ -170,11 +171,11 @@ func TestPChainFeeRateIncreaseDueToPeak(t *testing.T) { {1615237936, Dimensions{7034, 2652, 2652, 26000}}, {1615237936, Dimensions{7564, 2856, 2856, 28000}}, {1615237936, Dimensions{34064, 13056, 13056, 128000}}, - {1615237936, Dimensions{34064, 13056, 13056, 128000}}, - {1615237936, Dimensions{34064, 13056, 13056, 128000}}, - {1615237936, Dimensions{34064, 13056, 13056, 128000}}, - {1615237936, Dimensions{34064, 13056, 13056, 128000}}, - {1615237936, Dimensions{34064, 13056, 13056, 128000}}, + // {1615237936, Dimensions{34064, 13056, 13056, 128000}}, + // {1615237936, Dimensions{34064, 13056, 13056, 128000}}, + // {1615237936, Dimensions{34064, 13056, 13056, 128000}}, + // {1615237936, Dimensions{34064, 13056, 13056, 128000}}, + // {1615237936, Dimensions{34064, 13056, 13056, 128000}}, // {1615237936, Dimensions{34064, 13056, 13056, 128000}}, <-- from here on, fee would exceed 100 Avax // {1615237936, Dimensions{34064, 13056, 13056, 128000}}, // {1615237936, Dimensions{820, 360, 442, 4000}}, @@ -259,41 +260,24 @@ func TestFeeUpdateFactor(t *testing.T) { {1, 250, 250, 1, 1}, {math.MaxUint64, 250, 250, 1, 1}, - // PIECEWISE APPROXIMATION parentBlkComplexity > targetBlkComplexity - {1, 101, 100, 100_002, 100_000}, // should be 1,00001 - {1, 110, 100, 100_020, 100_000}, // should be 1,0001 - {1, 200, 100, 100_200, 100_000}, // should be 1,001 - {1, 1_100, 100, 102_000, 100_000}, // should be 1,01 - {1, 10_100, 100, 120_000, 100_000}, // should be 1,105 - {1, 100_100, 100, 300_000, 100_000}, // should be 2,718, it's 3 - {1, 1_000_100, 100, 2_202_800_000, 100_000}, // should be 22026, it's 22028 - - // // TAYLOR APPROXIMATION parentBlkComplexity > targetBlkComplexity - // {1, 101, 100, 20_000_200_001, 20_000_000_000}, // should be 1,00001 - // {1, 110, 100, 20_002_000_100, 20_000_000_000}, // should be 1,0001 - // {1, 200, 100, 20_020_010_000, 20_000_000_000}, // should be 1,001 - // {1, 1_100, 100, 20_201_000_000, 20_000_000_000}, // should be 1,01 - // {1, 10_100, 100, 22_100_000_000, 20_000_000_000}, // should be 1,105 - // {1, 100_100, 100, 50_000_000_000, 20_000_000_000}, // should be 2,718, it's 2,5 - // {1, 1_000_100, 100, 1_220_000_000_000, 20_000_000_000}, // should be 22026, it's roughly 61 - - // PIECEWISE APPROXIMATION parentBlkComplexity < targetBlkComplexity - {1, 100, 101, 101_000, 101_002}, // should be 0,99999 - {1, 100, 110, 110_000, 110_020}, // should be 0,9999 - {1, 100, 200, 200_000, 200_200}, // should be 0,9995 - {1, 100, 1_100, 1_100_000, 1_102_000}, // should be 0,9991 - {1, 100, 10_100, 10_100_000, 10_120_000}, // should be 0,999 - {1, 100, 100_100, 100_100_000, 100_300_000}, // should be 0,999 - {1, 100, 1_000_100, 1_000_100_000, 1_002_100_000}, // should be 0,999 - - // // TAYLOR APPROXIMATION parentBlkComplexity < targetBlkComplexity - // {1, 100, 101, 20_402_000_000, 20_402_202_001}, // should be 0,99999 - // {1, 100, 110, 24_200_000_000, 24_202_200_100}, // should be 0,9999 - // {1, 100, 200, 80_000_000_000, 80_040_010_000}, // should be 0,9995 - // {1, 100, 1_100, 2_420_000_000_000, 2_422_201_000_000}, // should be 0,9991 - // {1, 100, 10_100, 204_020_000_000_000, 204_222_100_000_000}, // should be 0,999 - // {1, 100, 100_100, 20_040_020_000_000_000, 20_060_050_000_000_000}, // should be 0,999 - // {1, 100, 1_000_100, 2_000_400_020_000_000_000, 2_002_401_220_000_000_000}, // should be 0,999 + // parentBlkComplexity > targetBlkComplexity + {1, 101, 100, 2_002, 2_000}, // should be 1.0005 + {1, 110, 100, 2_020, 2_000}, // should be 1.005 + {1, 200, 100, 2_200, 2_000}, // should be 1.05 + {1, 1_100, 100, 4_000, 2_000}, // should be 1.648 + {1, 2_100, 100, 6000, 2_000}, // should be 2,718 + {1, 3_100, 100, 11_000, 2_000}, // should be 4,48 + {1, 4_100, 100, 16_000, 2_000}, // should be 7,39 + {1, 7_100, 100, 77_000, 2_000}, // should be 33,12 + {1, 8_100, 100, 110_000, 2_000}, // should be 54,6 + {1, 10_100, 100, 298_000, 2_000}, // should be 148,4 + + // parentBlkComplexity < targetBlkComplexity + {1, 100, 101, 2_020, 2_022}, // should be 0,9995 + {1, 100, 110, 2_200, 2_220}, // should be 0,995 + {1, 100, 200, 4_000, 4_200}, // should be 0,975 + {1, 100, 1_100, 22_000, 24_000}, // should be 0,955 + {1, 100, 10_100, 202_000, 222_000}, // should be 0,952 } for _, tt := range tests { haveFactor, haveIncreaseFee := updateFactor( @@ -305,45 +289,3 @@ func TestFeeUpdateFactor(t *testing.T) { require.Equal(t, tt.wantDenom, haveIncreaseFee) } } - -func TestNormalizedDelta(t *testing.T) { - tests := []struct { - n, d uint64 - wantP, wantQ uint64 - }{ - {0, 1, 0, 100}, - {0, 10, 0, 100}, - {0, 100, 0, 100}, - {0, 1_000, 0, 100}, - {0, math.MaxUint64 / 100, 0, 100}, - {0, math.MaxUint64 / 10, 0, 100}, - {0, math.MaxUint64 / 2, 0, 100}, - {0, math.MaxUint64, 0, 100}, - - {1, 10, 10, 100}, - {2, 100, 2, 100}, - {30, 1_000, 3, 100}, - {400, 10_000, 4, 100}, - {5_000, 100_000, 5, 100}, - // {math.MaxUint64 / 1000, math.MaxUint64 / 10, 1, 100}, // BROKEN - // {math.MaxUint64 / 100, math.MaxUint64, 1, 100}, // BROKEN - // {math.MaxUint64 / 10, math.MaxUint64, 10, 100}, // BROKEN - - {10, 1, 1_000, 100}, - {220, 30, 733, 100}, // should be 7.3333 - {10_000, 1, 1_000_000, 100}, - {10_000, 600, 1666, 100}, // should be 16.6666 - - {math.MaxUint64, math.MaxUint64, 100, 100}, - // {math.MaxUint64, math.MaxUint64 / 3 * 2, 150, 100}, // BROKEN should be 1.5 - {math.MaxUint64, math.MaxUint64 / 2, 200, 100}, - {math.MaxUint64 / 2, 1, math.MaxUint64 / 2, 1}, - {math.MaxUint64, 1, math.MaxUint64, 1}, - } - - for _, tt := range tests { - haveP, haveQ := normalizeDelta(tt.n, tt.d) - require.Equal(t, tt.wantP, haveP) - require.Equal(t, tt.wantQ, haveQ) - } -} From cf0628e1a86edd44b718f9106c0c12729926d860 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 9 May 2024 11:47:55 +0200 Subject: [PATCH 157/190] nit --- vms/platformvm/vm_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vms/platformvm/vm_test.go b/vms/platformvm/vm_test.go index 935e35d61f09..11674b8dbcb2 100644 --- a/vms/platformvm/vm_test.go +++ b/vms/platformvm/vm_test.go @@ -2330,7 +2330,7 @@ func TestTransferSubnetOwnershipTx(t *testing.T) { func TestBaseTx(t *testing.T) { require := require.New(t) - vm, txBuilder, _, _ := defaultVM(t, latestFork) + vm, txBuilder, _, _ := defaultVM(t, durango) vm.ctx.Lock.Lock() defer vm.ctx.Lock.Unlock() From ca01838859e3b8491414b1c7005e62583390ac50 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 9 May 2024 19:35:23 +0200 Subject: [PATCH 158/190] fixed UT --- vms/platformvm/txs/fee/helpers.go | 9 -------- vms/platformvm/txs/txstest/builder.go | 31 ++++++++++++++------------- vms/platformvm/vm_test.go | 23 ++++---------------- 3 files changed, 20 insertions(+), 43 deletions(-) diff --git a/vms/platformvm/txs/fee/helpers.go b/vms/platformvm/txs/fee/helpers.go index 87c7e1f4ac4a..bec33f6468e8 100644 --- a/vms/platformvm/txs/fee/helpers.go +++ b/vms/platformvm/txs/fee/helpers.go @@ -67,15 +67,6 @@ func UpdatedFeeManager(feeRates, parentBlkComplexity fees.Dimensions, upgrades u feeCfg = GetDynamicConfig(isEActive) ) - // feeRates, err := state.GetFeeRates() - // if err != nil { - // return nil, fmt.Errorf("failed retrieving fee rates: %w", err) - // } - // parentBlkComplexity, err := state.GetLastBlockComplexity() - // if err != nil { - // return nil, fmt.Errorf("failed retrieving last block complexity: %w", err) - // } - feeManager := fees.NewManager(feeRates) if isEActive { if err := feeManager.UpdateFeeRates( diff --git a/vms/platformvm/txs/txstest/builder.go b/vms/platformvm/txs/txstest/builder.go index e7579086449a..e3ca79ed18cf 100644 --- a/vms/platformvm/txs/txstest/builder.go +++ b/vms/platformvm/txs/txstest/builder.go @@ -13,6 +13,7 @@ import ( "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" "github.com/ava-labs/avalanchego/utils/timer/mockable" "github.com/ava-labs/avalanchego/vms/components/avax" + "github.com/ava-labs/avalanchego/vms/components/verify" "github.com/ava-labs/avalanchego/vms/platformvm/config" "github.com/ava-labs/avalanchego/vms/platformvm/state" "github.com/ava-labs/avalanchego/vms/platformvm/txs" @@ -53,7 +54,7 @@ func (b *Builder) NewImportTx( options ...common.Option, ) (*txs.Tx, error) { pBuilder, pSigner := b.builders(keys) - feeCalc, err := b.feeCalculator() + feeCalc, err := b.FeeCalculator(nil) if err != nil { return nil, err } @@ -78,7 +79,7 @@ func (b *Builder) NewExportTx( options ...common.Option, ) (*txs.Tx, error) { pBuilder, pSigner := b.builders(keys) - feeCalc, err := b.feeCalculator() + feeCalc, err := b.FeeCalculator(nil) if err != nil { return nil, err } @@ -106,7 +107,7 @@ func (b *Builder) NewCreateChainTx( options ...common.Option, ) (*txs.Tx, error) { pBuilder, pSigner := b.builders(keys) - feeCalc, err := b.feeCalculator() + feeCalc, err := b.FeeCalculator(nil) if err != nil { return nil, err } @@ -133,7 +134,7 @@ func (b *Builder) NewCreateSubnetTx( options ...common.Option, ) (*txs.Tx, error) { pBuilder, pSigner := b.builders(keys) - feeCalc, err := b.feeCalculator() + feeCalc, err := b.FeeCalculator(nil) if err != nil { return nil, err } @@ -169,7 +170,7 @@ func (b *Builder) NewTransformSubnetTx( options ...common.Option, ) (*txs.Tx, error) { pBuilder, pSigner := b.builders(keys) - feeCalc, err := b.feeCalculator() + feeCalc, err := b.FeeCalculator(nil) if err != nil { return nil, err } @@ -207,7 +208,7 @@ func (b *Builder) NewAddValidatorTx( options ...common.Option, ) (*txs.Tx, error) { pBuilder, pSigner := b.builders(keys) - feeCalc, err := b.feeCalculator() + feeCalc, err := b.FeeCalculator(nil) if err != nil { return nil, err } @@ -237,7 +238,7 @@ func (b *Builder) NewAddPermissionlessValidatorTx( options ...common.Option, ) (*txs.Tx, error) { pBuilder, pSigner := b.builders(keys) - feeCalc, err := b.feeCalculator() + feeCalc, err := b.FeeCalculator(nil) if err != nil { return nil, err } @@ -266,7 +267,7 @@ func (b *Builder) NewAddDelegatorTx( options ...common.Option, ) (*txs.Tx, error) { pBuilder, pSigner := b.builders(keys) - feeCalc, err := b.feeCalculator() + feeCalc, err := b.FeeCalculator(nil) if err != nil { return nil, err } @@ -292,7 +293,7 @@ func (b *Builder) NewAddPermissionlessDelegatorTx( options ...common.Option, ) (*txs.Tx, error) { pBuilder, pSigner := b.builders(keys) - feeCalc, err := b.feeCalculator() + feeCalc, err := b.FeeCalculator(nil) if err != nil { return nil, err } @@ -317,7 +318,7 @@ func (b *Builder) NewAddSubnetValidatorTx( options ...common.Option, ) (*txs.Tx, error) { pBuilder, pSigner := b.builders(keys) - feeCalc, err := b.feeCalculator() + feeCalc, err := b.FeeCalculator(nil) if err != nil { return nil, err } @@ -341,7 +342,7 @@ func (b *Builder) NewRemoveSubnetValidatorTx( options ...common.Option, ) (*txs.Tx, error) { pBuilder, pSigner := b.builders(keys) - feeCalc, err := b.feeCalculator() + feeCalc, err := b.FeeCalculator(nil) if err != nil { return nil, err } @@ -366,7 +367,7 @@ func (b *Builder) NewTransferSubnetOwnershipTx( options ...common.Option, ) (*txs.Tx, error) { pBuilder, pSigner := b.builders(keys) - feeCalc, err := b.feeCalculator() + feeCalc, err := b.FeeCalculator(nil) if err != nil { return nil, err } @@ -390,7 +391,7 @@ func (b *Builder) NewBaseTx( options ...common.Option, ) (*txs.Tx, error) { pBuilder, pSigner := b.builders(keys) - feeCalc, err := b.feeCalculator() + feeCalc, err := b.FeeCalculator(nil) if err != nil { return nil, err } @@ -420,7 +421,7 @@ func (b *Builder) builders(keys []*secp256k1.PrivateKey) (builder.Builder, walle return builder, signer } -func (b *Builder) feeCalculator() (*fee.Calculator, error) { +func (b *Builder) FeeCalculator(creds []verify.Verifiable) (*fee.Calculator, error) { var ( staticFeeCfg = b.cfg.StaticFeeConfig upgrades = b.cfg.UpgradeConfig @@ -451,7 +452,7 @@ func (b *Builder) feeCalculator() (*fee.Calculator, error) { } feeCfg := fee.GetDynamicConfig(isEActive) - feeCalculator = fee.NewDynamicCalculator(staticFeeCfg, feeManager, feeCfg.BlockMaxComplexity, nil) + feeCalculator = fee.NewDynamicCalculator(staticFeeCfg, feeManager, feeCfg.BlockMaxComplexity, creds) } return feeCalculator, nil } diff --git a/vms/platformvm/vm_test.go b/vms/platformvm/vm_test.go index 11674b8dbcb2..ef07697c4a19 100644 --- a/vms/platformvm/vm_test.go +++ b/vms/platformvm/vm_test.go @@ -2330,11 +2330,11 @@ func TestTransferSubnetOwnershipTx(t *testing.T) { func TestBaseTx(t *testing.T) { require := require.New(t) - vm, txBuilder, _, _ := defaultVM(t, durango) + vm, txBuilder, _, _ := defaultVM(t, latestFork) vm.ctx.Lock.Lock() defer vm.ctx.Lock.Unlock() - sendAmt := uint64(100000) + sendAmt := uint64(100_000) changeAddr := ids.ShortEmpty baseTx, err := txBuilder.NewBaseTx( @@ -2394,23 +2394,8 @@ func TestBaseTx(t *testing.T) { } require.Equal(totalOutputAmt, key0OutputAmt+key1OutputAmt+changeAddrOutputAmt) - var ( - chainTime = vm.state.GetTimestamp() - staticFeeCfg = vm.Config.StaticFeeConfig - upgrades = vm.Config.UpgradeConfig - feeCalc *fee.Calculator - ) - - if !upgrades.IsEActivated(chainTime) { - feeCalc = fee.NewStaticCalculator(staticFeeCfg, upgrades, chainTime) - } else { - feeRates, err := vm.state.GetFeeRates() - require.NoError(err) - - feeCfg := fee.GetDynamicConfig(upgrades.IsEActivated(chainTime)) - feeMan := commonfees.NewManager(feeRates) - feeCalc = fee.NewDynamicCalculator(staticFeeCfg, feeMan, feeCfg.BlockMaxComplexity, baseTx.Creds) - } + feeCalc, err := txBuilder.FeeCalculator(baseTx.Creds) + require.NoError(err) fee, err := feeCalc.ComputeFee(baseTx.Unsigned) require.NoError(err) From fecda6cad084d0569b65e98da6982a13bf7645bf Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Fri, 10 May 2024 11:10:41 +0200 Subject: [PATCH 159/190] improved e2e test --- tests/e2e/p/dynamic_fees.go | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/tests/e2e/p/dynamic_fees.go b/tests/e2e/p/dynamic_fees.go index c29eae1a2325..6aa8e2e26c08 100644 --- a/tests/e2e/p/dynamic_fees.go +++ b/tests/e2e/p/dynamic_fees.go @@ -31,7 +31,7 @@ var _ = ginkgo.Describe("[Dynamic Fees]", func() { BlockMaxComplexity: commonfees.Dimensions{math.MaxUint64, math.MaxUint64, math.MaxUint64, math.MaxUint64}, // BlockUnitsTarget are set to cause an increase of fees while simple transactions are issued - BlockTargetComplexityRate: commonfees.Dimensions{250, 60, 120, 650}, + BlockTargetComplexityRate: commonfees.Dimensions{120, 30, 60, 300}, } ginkgo.By("creating a new private network to ensure isolation from other tests") @@ -132,7 +132,16 @@ var _ = ginkgo.Describe("[Dynamic Fees]", func() { _, currFeeRates, err = pChainClient.GetFeeRates(e2e.DefaultContext()) require.NoError(err) tests.Outf("{{blue}} next fee rates: %v {{/}}\n", currFeeRates) - return commonfees.Compare(initialFeeRates, currFeeRates) + + ratesStrictlyLower := false + for i := 0; i < len(initialFeeRates); i++ { + if currFeeRates[i] < initialFeeRates[i] { + ratesStrictlyLower = true + break + } + } + + return ratesStrictlyLower }, e2e.DefaultTimeout, e2e.DefaultPollingInterval, "failed to see gas price decrease before timeout") tests.Outf("\n{{blue}}fee rates have decreased to %v{{/}}\n", currFeeRates) }) From 7a38e497cf2c0b817381f489efca7355027999f6 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Wed, 22 May 2024 09:57:09 -0400 Subject: [PATCH 160/190] reduced diff --- tests/e2e/p/workflow.go | 4 +- vms/platformvm/service_test.go | 4 +- .../{stakers_helpers.go => block_helpers.go} | 0 .../txs/executor/staker_tx_verification.go | 24 ++--- .../txs/executor/standard_tx_executor.go | 24 ++--- vms/platformvm/txs/fee/calculator.go | 12 +-- vms/platformvm/txs/fee/calculator_test.go | 10 ++- vms/platformvm/txs/txstest/builder.go | 31 ++++--- vms/platformvm/txs/txstest/context.go | 4 +- vms/platformvm/vm_test.go | 8 +- wallet/chain/p/builder/builder.go | 26 +++--- wallet/chain/p/builder_test.go | 88 +++++++++---------- wallet/chain/p/wallet.go | 2 +- 13 files changed, 121 insertions(+), 116 deletions(-) rename vms/platformvm/state/{stakers_helpers.go => block_helpers.go} (100%) diff --git a/tests/e2e/p/workflow.go b/tests/e2e/p/workflow.go index 90f5755fefd0..aaec96e0b8f7 100644 --- a/tests/e2e/p/workflow.go +++ b/tests/e2e/p/workflow.go @@ -170,8 +170,8 @@ var _ = e2e.DescribePChain("[Workflow]", func() { // retrieve fees paid for the tx feeCfg := fee.GetDynamicConfig(true /*isEActive*/) - feeCalc := fee.NewDynamicCalculator(pChainStaticFees, commonfees.NewManager(nextFeeRates), feeCfg.BlockMaxComplexity, tx.Creds) - pChainExportFee, err = feeCalc.ComputeFee(tx.Unsigned) + feeCalc := fee.NewDynamicCalculator(pChainStaticFees, commonfees.NewManager(nextFeeRates), feeCfg.BlockMaxComplexity) + pChainExportFee, err = feeCalc.ComputeFee(tx.Unsigned, tx.Creds) require.NoError(err) }) diff --git a/vms/platformvm/service_test.go b/vms/platformvm/service_test.go index 24a4f0bf41bc..cc406a32818f 100644 --- a/vms/platformvm/service_test.go +++ b/vms/platformvm/service_test.go @@ -398,10 +398,10 @@ func TestGetBalance(t *testing.T) { feeCfg := fee.GetDynamicConfig(true) feeMan := commonfees.NewManager(feeRates) - feeCalc = fee.NewDynamicCalculator(staticFeeCfg, feeMan, feeCfg.BlockMaxComplexity, testSubnet1.Creds) + feeCalc = fee.NewDynamicCalculator(staticFeeCfg, feeMan, feeCfg.BlockMaxComplexity) } - fee, err := feeCalc.ComputeFee(testSubnet1.Unsigned) + fee, err := feeCalc.ComputeFee(testSubnet1.Unsigned, testSubnet1.Creds) require.NoError(err) balance = defaultBalance - fee } diff --git a/vms/platformvm/state/stakers_helpers.go b/vms/platformvm/state/block_helpers.go similarity index 100% rename from vms/platformvm/state/stakers_helpers.go rename to vms/platformvm/state/block_helpers.go diff --git a/vms/platformvm/txs/executor/staker_tx_verification.go b/vms/platformvm/txs/executor/staker_tx_verification.go index 00b296951d31..0d7ffcfbe9e1 100644 --- a/vms/platformvm/txs/executor/staker_tx_verification.go +++ b/vms/platformvm/txs/executor/staker_tx_verification.go @@ -170,7 +170,7 @@ func verifyAddValidatorTx( // Verify the flowcheck feeCalculator := fee.NewStaticCalculator(backend.Config.StaticFeeConfig, upgrades, currentTimestamp) - fee, err := feeCalculator.ComputeFee(tx) + fee, err := feeCalculator.ComputeFee(tx, sTx.Creds) if err != nil { return nil, err } @@ -274,10 +274,10 @@ func verifyAddSubnetValidatorTx( if !isEActive { feeCalculator = fee.NewStaticCalculator(staticFeesCfg, upgrades, currentTimestamp) } else { - feeCalculator = fee.NewDynamicCalculator(staticFeesCfg, feeManager, maxComplexity, sTx.Creds) + feeCalculator = fee.NewDynamicCalculator(staticFeesCfg, feeManager, maxComplexity) } - fee, err := feeCalculator.ComputeFee(tx) + fee, err := feeCalculator.ComputeFee(tx, sTx.Creds) if err != nil { return err } @@ -368,10 +368,10 @@ func verifyRemoveSubnetValidatorTx( if !isEActive { feeCalculator = fee.NewStaticCalculator(staticFeesCfg, upgrades, currentTimestamp) } else { - feeCalculator = fee.NewDynamicCalculator(staticFeesCfg, feeManager, maxComplexity, sTx.Creds) + feeCalculator = fee.NewDynamicCalculator(staticFeesCfg, feeManager, maxComplexity) } - fee, err := feeCalculator.ComputeFee(tx) + fee, err := feeCalculator.ComputeFee(tx, sTx.Creds) if err != nil { return nil, false, err } @@ -496,7 +496,7 @@ func verifyAddDelegatorTx( // Verify the flowcheck feeCalculator := fee.NewStaticCalculator(backend.Config.StaticFeeConfig, upgrades, currentTimestamp) - fee, err := feeCalculator.ComputeFee(tx) + fee, err := feeCalculator.ComputeFee(tx, sTx.Creds) if err != nil { return nil, err } @@ -629,10 +629,10 @@ func verifyAddPermissionlessValidatorTx( if !isEActive { feeCalculator = fee.NewStaticCalculator(staticFeesCfg, upgrades, currentTimestamp) } else { - feeCalculator = fee.NewDynamicCalculator(staticFeesCfg, feeManager, maxComplexity, sTx.Creds) + feeCalculator = fee.NewDynamicCalculator(staticFeesCfg, feeManager, maxComplexity) } - fee, err := feeCalculator.ComputeFee(tx) + fee, err := feeCalculator.ComputeFee(tx, sTx.Creds) if err != nil { return err } @@ -790,10 +790,10 @@ func verifyAddPermissionlessDelegatorTx( if !isEActive { feeCalculator = fee.NewStaticCalculator(staticFeesCfg, upgrades, currentTimestamp) } else { - feeCalculator = fee.NewDynamicCalculator(staticFeesCfg, feeManager, maxComplexity, sTx.Creds) + feeCalculator = fee.NewDynamicCalculator(staticFeesCfg, feeManager, maxComplexity) } - fee, err := feeCalculator.ComputeFee(tx) + fee, err := feeCalculator.ComputeFee(tx, sTx.Creds) if err != nil { return err } @@ -865,10 +865,10 @@ func verifyTransferSubnetOwnershipTx( if !isEActive { feeCalculator = fee.NewStaticCalculator(staticFeesCfg, upgrades, currentTimestamp) } else { - feeCalculator = fee.NewDynamicCalculator(staticFeesCfg, feeManager, maxComplexity, sTx.Creds) + feeCalculator = fee.NewDynamicCalculator(staticFeesCfg, feeManager, maxComplexity) } - fee, err := feeCalculator.ComputeFee(tx) + fee, err := feeCalculator.ComputeFee(tx, sTx.Creds) if err != nil { return err } diff --git a/vms/platformvm/txs/executor/standard_tx_executor.go b/vms/platformvm/txs/executor/standard_tx_executor.go index a90bdb802430..391001f2efad 100644 --- a/vms/platformvm/txs/executor/standard_tx_executor.go +++ b/vms/platformvm/txs/executor/standard_tx_executor.go @@ -82,10 +82,10 @@ func (e *StandardTxExecutor) CreateChainTx(tx *txs.CreateChainTx) error { if !isEActive { feeCalculator = fee.NewStaticCalculator(staticFeesCfg, upgrades, currentTimestamp) } else { - feeCalculator = fee.NewDynamicCalculator(staticFeesCfg, e.BlkFeeManager, e.BlockMaxComplexity, e.Tx.Creds) + feeCalculator = fee.NewDynamicCalculator(staticFeesCfg, e.BlkFeeManager, e.BlockMaxComplexity) } - fee, err := feeCalculator.ComputeFee(tx) + fee, err := feeCalculator.ComputeFee(tx, e.Tx.Creds) if err != nil { return err } @@ -144,10 +144,10 @@ func (e *StandardTxExecutor) CreateSubnetTx(tx *txs.CreateSubnetTx) error { if !isEActive { feeCalculator = fee.NewStaticCalculator(staticFeesCfg, upgrades, currentTimestamp) } else { - feeCalculator = fee.NewDynamicCalculator(staticFeesCfg, e.BlkFeeManager, e.BlockMaxComplexity, e.Tx.Creds) + feeCalculator = fee.NewDynamicCalculator(staticFeesCfg, e.BlkFeeManager, e.BlockMaxComplexity) } - fee, err := feeCalculator.ComputeFee(tx) + fee, err := feeCalculator.ComputeFee(tx, e.Tx.Creds) if err != nil { return err } @@ -241,10 +241,10 @@ func (e *StandardTxExecutor) ImportTx(tx *txs.ImportTx) error { if !isEActive { feeCalculator = fee.NewStaticCalculator(staticFeesCfg, upgrades, currentTimestamp) } else { - feeCalculator = fee.NewDynamicCalculator(staticFeesCfg, e.BlkFeeManager, e.BlockMaxComplexity, e.Tx.Creds) + feeCalculator = fee.NewDynamicCalculator(staticFeesCfg, e.BlkFeeManager, e.BlockMaxComplexity) } - fee, err := feeCalculator.ComputeFee(tx) + fee, err := feeCalculator.ComputeFee(tx, e.Tx.Creds) if err != nil { return err } @@ -310,10 +310,10 @@ func (e *StandardTxExecutor) ExportTx(tx *txs.ExportTx) error { if !isEActive { feeCalculator = fee.NewStaticCalculator(staticFeesCfg, upgrades, currentTimestamp) } else { - feeCalculator = fee.NewDynamicCalculator(staticFeesCfg, e.BlkFeeManager, e.BlockMaxComplexity, e.Tx.Creds) + feeCalculator = fee.NewDynamicCalculator(staticFeesCfg, e.BlkFeeManager, e.BlockMaxComplexity) } - fee, err := feeCalculator.ComputeFee(tx) + fee, err := feeCalculator.ComputeFee(tx, e.Tx.Creds) if err != nil { return err } @@ -518,10 +518,10 @@ func (e *StandardTxExecutor) TransformSubnetTx(tx *txs.TransformSubnetTx) error if !isEActive { feeCalculator = fee.NewStaticCalculator(staticFeesCfg, upgrades, currentTimestamp) } else { - feeCalculator = fee.NewDynamicCalculator(staticFeesCfg, e.BlkFeeManager, e.BlockMaxComplexity, e.Tx.Creds) + feeCalculator = fee.NewDynamicCalculator(staticFeesCfg, e.BlkFeeManager, e.BlockMaxComplexity) } - fee, err := feeCalculator.ComputeFee(tx) + fee, err := feeCalculator.ComputeFee(tx, e.Tx.Creds) if err != nil { return err } @@ -666,10 +666,10 @@ func (e *StandardTxExecutor) BaseTx(tx *txs.BaseTx) error { if !isEActive { feeCalculator = fee.NewStaticCalculator(staticFeesCfg, upgrades, currentTimestamp) } else { - feeCalculator = fee.NewDynamicCalculator(staticFeesCfg, e.BlkFeeManager, e.BlockMaxComplexity, e.Tx.Creds) + feeCalculator = fee.NewDynamicCalculator(staticFeesCfg, e.BlkFeeManager, e.BlockMaxComplexity) } - fee, err := feeCalculator.ComputeFee(tx) + fee, err := feeCalculator.ComputeFee(tx, e.Tx.Creds) if err != nil { return err } diff --git a/vms/platformvm/txs/fee/calculator.go b/vms/platformvm/txs/fee/calculator.go index 8a8c736ac00c..1be6d3de6f3d 100644 --- a/vms/platformvm/txs/fee/calculator.go +++ b/vms/platformvm/txs/fee/calculator.go @@ -26,11 +26,11 @@ var ( errFailedComplexityCumulation = errors.New("failed cumulating complexity") ) -func NewStaticCalculator(cfg StaticConfig, ut upgrade.Config, chainTime time.Time) *Calculator { +func NewStaticCalculator(config StaticConfig, upgradeTimes upgrade.Config, chainTime time.Time) *Calculator { return &Calculator{ c: &calculator{ - upgrades: ut, - staticCfg: cfg, + upgrades: upgradeTimes, + staticCfg: config, time: chainTime, }, } @@ -41,7 +41,6 @@ func NewDynamicCalculator( cfg StaticConfig, feeManager *fees.Manager, blockMaxComplexity fees.Dimensions, - creds []verify.Verifiable, ) *Calculator { return &Calculator{ c: &calculator{ @@ -49,7 +48,7 @@ func NewDynamicCalculator( staticCfg: cfg, feeManager: feeManager, blockMaxComplexity: blockMaxComplexity, - credentials: creds, + // credentials are set when CalculateFee is called }, } } @@ -66,7 +65,8 @@ func (c *Calculator) ResetFee(newFee uint64) { c.c.fee = newFee } -func (c *Calculator) ComputeFee(tx txs.UnsignedTx) (uint64, error) { +func (c *Calculator) ComputeFee(tx txs.UnsignedTx, creds []verify.Verifiable) (uint64, error) { + c.c.credentials = creds err := tx.Visit(c.c) return c.c.fee, err } diff --git a/vms/platformvm/txs/fee/calculator_test.go b/vms/platformvm/txs/fee/calculator_test.go index 9d4e28dbee64..6cd518a33ab4 100644 --- a/vms/platformvm/txs/fee/calculator_test.go +++ b/vms/platformvm/txs/fee/calculator_test.go @@ -18,6 +18,7 @@ import ( "github.com/ava-labs/avalanchego/utils/units" "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/components/fees" + "github.com/ava-labs/avalanchego/vms/components/verify" "github.com/ava-labs/avalanchego/vms/platformvm/reward" "github.com/ava-labs/avalanchego/vms/platformvm/signer" "github.com/ava-labs/avalanchego/vms/platformvm/stakeable" @@ -692,10 +693,15 @@ func TestTxFees(t *testing.T) { if !upgrades.IsEActivated(tt.chainTime) { fc = NewStaticCalculator(feeTestsDefaultCfg, upgrades, tt.chainTime) } else { - fc = NewDynamicCalculator(feeTestsDefaultCfg, fees.NewManager(testFeeRates), maxComplexity, sTx.Creds) + fc = NewDynamicCalculator(feeTestsDefaultCfg, fees.NewManager(testFeeRates), maxComplexity) } - _, _ = fc.ComputeFee(uTx) + var creds []verify.Verifiable + if sTx != nil { + // txs like RewardValidatorTx are not signed + creds = sTx.Creds + } + _, _ = fc.ComputeFee(uTx, creds) tt.checksF(t, fc.c) }) } diff --git a/vms/platformvm/txs/txstest/builder.go b/vms/platformvm/txs/txstest/builder.go index e3ca79ed18cf..135140d3594e 100644 --- a/vms/platformvm/txs/txstest/builder.go +++ b/vms/platformvm/txs/txstest/builder.go @@ -13,7 +13,6 @@ import ( "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" "github.com/ava-labs/avalanchego/utils/timer/mockable" "github.com/ava-labs/avalanchego/vms/components/avax" - "github.com/ava-labs/avalanchego/vms/components/verify" "github.com/ava-labs/avalanchego/vms/platformvm/config" "github.com/ava-labs/avalanchego/vms/platformvm/state" "github.com/ava-labs/avalanchego/vms/platformvm/txs" @@ -54,7 +53,7 @@ func (b *Builder) NewImportTx( options ...common.Option, ) (*txs.Tx, error) { pBuilder, pSigner := b.builders(keys) - feeCalc, err := b.FeeCalculator(nil) + feeCalc, err := b.FeeCalculator() if err != nil { return nil, err } @@ -79,7 +78,7 @@ func (b *Builder) NewExportTx( options ...common.Option, ) (*txs.Tx, error) { pBuilder, pSigner := b.builders(keys) - feeCalc, err := b.FeeCalculator(nil) + feeCalc, err := b.FeeCalculator() if err != nil { return nil, err } @@ -107,7 +106,7 @@ func (b *Builder) NewCreateChainTx( options ...common.Option, ) (*txs.Tx, error) { pBuilder, pSigner := b.builders(keys) - feeCalc, err := b.FeeCalculator(nil) + feeCalc, err := b.FeeCalculator() if err != nil { return nil, err } @@ -134,7 +133,7 @@ func (b *Builder) NewCreateSubnetTx( options ...common.Option, ) (*txs.Tx, error) { pBuilder, pSigner := b.builders(keys) - feeCalc, err := b.FeeCalculator(nil) + feeCalc, err := b.FeeCalculator() if err != nil { return nil, err } @@ -170,7 +169,7 @@ func (b *Builder) NewTransformSubnetTx( options ...common.Option, ) (*txs.Tx, error) { pBuilder, pSigner := b.builders(keys) - feeCalc, err := b.FeeCalculator(nil) + feeCalc, err := b.FeeCalculator() if err != nil { return nil, err } @@ -208,7 +207,7 @@ func (b *Builder) NewAddValidatorTx( options ...common.Option, ) (*txs.Tx, error) { pBuilder, pSigner := b.builders(keys) - feeCalc, err := b.FeeCalculator(nil) + feeCalc, err := b.FeeCalculator() if err != nil { return nil, err } @@ -238,7 +237,7 @@ func (b *Builder) NewAddPermissionlessValidatorTx( options ...common.Option, ) (*txs.Tx, error) { pBuilder, pSigner := b.builders(keys) - feeCalc, err := b.FeeCalculator(nil) + feeCalc, err := b.FeeCalculator() if err != nil { return nil, err } @@ -267,7 +266,7 @@ func (b *Builder) NewAddDelegatorTx( options ...common.Option, ) (*txs.Tx, error) { pBuilder, pSigner := b.builders(keys) - feeCalc, err := b.FeeCalculator(nil) + feeCalc, err := b.FeeCalculator() if err != nil { return nil, err } @@ -293,7 +292,7 @@ func (b *Builder) NewAddPermissionlessDelegatorTx( options ...common.Option, ) (*txs.Tx, error) { pBuilder, pSigner := b.builders(keys) - feeCalc, err := b.FeeCalculator(nil) + feeCalc, err := b.FeeCalculator() if err != nil { return nil, err } @@ -318,7 +317,7 @@ func (b *Builder) NewAddSubnetValidatorTx( options ...common.Option, ) (*txs.Tx, error) { pBuilder, pSigner := b.builders(keys) - feeCalc, err := b.FeeCalculator(nil) + feeCalc, err := b.FeeCalculator() if err != nil { return nil, err } @@ -342,7 +341,7 @@ func (b *Builder) NewRemoveSubnetValidatorTx( options ...common.Option, ) (*txs.Tx, error) { pBuilder, pSigner := b.builders(keys) - feeCalc, err := b.FeeCalculator(nil) + feeCalc, err := b.FeeCalculator() if err != nil { return nil, err } @@ -367,7 +366,7 @@ func (b *Builder) NewTransferSubnetOwnershipTx( options ...common.Option, ) (*txs.Tx, error) { pBuilder, pSigner := b.builders(keys) - feeCalc, err := b.FeeCalculator(nil) + feeCalc, err := b.FeeCalculator() if err != nil { return nil, err } @@ -391,7 +390,7 @@ func (b *Builder) NewBaseTx( options ...common.Option, ) (*txs.Tx, error) { pBuilder, pSigner := b.builders(keys) - feeCalc, err := b.FeeCalculator(nil) + feeCalc, err := b.FeeCalculator() if err != nil { return nil, err } @@ -421,7 +420,7 @@ func (b *Builder) builders(keys []*secp256k1.PrivateKey) (builder.Builder, walle return builder, signer } -func (b *Builder) FeeCalculator(creds []verify.Verifiable) (*fee.Calculator, error) { +func (b *Builder) FeeCalculator() (*fee.Calculator, error) { var ( staticFeeCfg = b.cfg.StaticFeeConfig upgrades = b.cfg.UpgradeConfig @@ -452,7 +451,7 @@ func (b *Builder) FeeCalculator(creds []verify.Verifiable) (*fee.Calculator, err } feeCfg := fee.GetDynamicConfig(isEActive) - feeCalculator = fee.NewDynamicCalculator(staticFeeCfg, feeManager, feeCfg.BlockMaxComplexity, creds) + feeCalculator = fee.NewDynamicCalculator(staticFeeCfg, feeManager, feeCfg.BlockMaxComplexity) } return feeCalculator, nil } diff --git a/vms/platformvm/txs/txstest/context.go b/vms/platformvm/txs/txstest/context.go index 975da7f7a793..88d51c0e89b3 100644 --- a/vms/platformvm/txs/txstest/context.go +++ b/vms/platformvm/txs/txstest/context.go @@ -20,8 +20,8 @@ func newContext( ) *builder.Context { var ( feeCalc = fee.NewStaticCalculator(cfg.StaticFeeConfig, cfg.UpgradeConfig, timestamp) - createSubnetFee, _ = feeCalc.ComputeFee(&txs.CreateSubnetTx{}) - createChainFee, _ = feeCalc.ComputeFee(&txs.CreateChainTx{}) + createSubnetFee, _ = feeCalc.ComputeFee(&txs.CreateSubnetTx{}, nil) + createChainFee, _ = feeCalc.ComputeFee(&txs.CreateChainTx{}, nil) ) return &builder.Context{ diff --git a/vms/platformvm/vm_test.go b/vms/platformvm/vm_test.go index ef07697c4a19..d7d07f944477 100644 --- a/vms/platformvm/vm_test.go +++ b/vms/platformvm/vm_test.go @@ -410,10 +410,10 @@ func TestGenesis(t *testing.T) { feeCfg := fee.GetDynamicConfig(upgrades.IsEActivated(chainTime)) feeMan := commonfees.NewManager(feeRates) - feeCalc = fee.NewDynamicCalculator(staticFeeCfg, feeMan, feeCfg.BlockMaxComplexity, testSubnet1.Creds) + feeCalc = fee.NewDynamicCalculator(staticFeeCfg, feeMan, feeCfg.BlockMaxComplexity) } - fee, err := feeCalc.ComputeFee(testSubnet1.Unsigned) + fee, err := feeCalc.ComputeFee(testSubnet1.Unsigned, testSubnet1.Creds) require.NoError(err) require.Equal(uint64(utxo.Amount)-fee, out.Amount()) } @@ -2394,10 +2394,10 @@ func TestBaseTx(t *testing.T) { } require.Equal(totalOutputAmt, key0OutputAmt+key1OutputAmt+changeAddrOutputAmt) - feeCalc, err := txBuilder.FeeCalculator(baseTx.Creds) + feeCalc, err := txBuilder.FeeCalculator() require.NoError(err) - fee, err := feeCalc.ComputeFee(baseTx.Unsigned) + fee, err := feeCalc.ComputeFee(baseTx.Unsigned, baseTx.Creds) require.NoError(err) require.Equal(fee, totalInputAmt-totalOutputAmt) require.Equal(sendAmt, key1OutputAmt) diff --git a/wallet/chain/p/builder/builder.go b/wallet/chain/p/builder/builder.go index 5467a04bf615..600b5d1c2eeb 100644 --- a/wallet/chain/p/builder/builder.go +++ b/wallet/chain/p/builder/builder.go @@ -351,7 +351,7 @@ func (b *builder) NewBaseTx( } // feesMan cumulates complexity. Let's init it with utx filled so far - if _, err := feeCalc.ComputeFee(utx); err != nil { + if _, err := feeCalc.ComputeFee(utx, nil); err != nil { return nil, err } @@ -396,7 +396,7 @@ func (b *builder) NewAddValidatorTx( toBurn := map[ids.ID]uint64{} // fees are calculated in financeTx // feesMan cumulates complexity. Let's init it with utx filled so far - if _, err := feeCalc.ComputeFee(utx); err != nil { + if _, err := feeCalc.ComputeFee(utx, nil); err != nil { return nil, err } @@ -444,7 +444,7 @@ func (b *builder) NewAddSubnetValidatorTx( } // feesMan cumulates complexity. Let's init it with utx filled so far - if _, err := feeCalc.ComputeFee(utx); err != nil { + if _, err := feeCalc.ComputeFee(utx, nil); err != nil { return nil, err } @@ -492,7 +492,7 @@ func (b *builder) NewRemoveSubnetValidatorTx( } // feesMan cumulates complexity. Let's init it with utx filled so far - if _, err := feeCalc.ComputeFee(utx); err != nil { + if _, err := feeCalc.ComputeFee(utx, nil); err != nil { return nil, err } @@ -533,7 +533,7 @@ func (b *builder) NewAddDelegatorTx( toBurn := map[ids.ID]uint64{} // fees are calculated in financeTx // feesMan cumulates complexity. Let's init it with utx filled so far - if _, err := feeCalc.ComputeFee(utx); err != nil { + if _, err := feeCalc.ComputeFee(utx, nil); err != nil { return nil, err } @@ -591,7 +591,7 @@ func (b *builder) NewCreateChainTx( } // feesMan cumulates complexity. Let's init it with utx filled so far - if _, err := feeCalc.ComputeFee(utx); err != nil { + if _, err := feeCalc.ComputeFee(utx, nil); err != nil { return nil, err } @@ -629,7 +629,7 @@ func (b *builder) NewCreateSubnetTx( toBurn := map[ids.ID]uint64{} // fees are calculated in financeTx // feesMan cumulates complexity. Let's init it with utx filled so far - if _, err := feeCalc.ComputeFee(utx); err != nil { + if _, err := feeCalc.ComputeFee(utx, nil); err != nil { return nil, err } @@ -679,7 +679,7 @@ func (b *builder) NewTransferSubnetOwnershipTx( } // feesMan cumulates complexity. Let's init it with utx filled so far - if _, err := feeCalc.ComputeFee(utx); err != nil { + if _, err := feeCalc.ComputeFee(utx, nil); err != nil { return nil, err } @@ -788,7 +788,7 @@ func (b *builder) NewImportTx( // 3. Finance fees as much as possible with imported, Avax-denominated UTXOs // feesMan cumulates complexity. Let's init it with utx filled so far - if _, err := feeCalc.ComputeFee(utx); err != nil { + if _, err := feeCalc.ComputeFee(utx, nil); err != nil { return nil, err } @@ -891,7 +891,7 @@ func (b *builder) NewExportTx( } // feesMan cumulates complexity. Let's init it with utx filled so far - if _, err := feeCalc.ComputeFee(utx); err != nil { + if _, err := feeCalc.ComputeFee(utx, nil); err != nil { return nil, err } @@ -967,7 +967,7 @@ func (b *builder) NewTransformSubnetTx( } // feesMan cumulates complexity. Let's init it with utx filled so far - if _, err := feeCalc.ComputeFee(utx); err != nil { + if _, err := feeCalc.ComputeFee(utx, nil); err != nil { return nil, err } @@ -1017,7 +1017,7 @@ func (b *builder) NewAddPermissionlessValidatorTx( toBurn := map[ids.ID]uint64{} // fees are calculated in financeTx // feesMan cumulates complexity. Let's init it with utx filled so far - if _, err := feeCalc.ComputeFee(utx); err != nil { + if _, err := feeCalc.ComputeFee(utx, nil); err != nil { return nil, err } @@ -1061,7 +1061,7 @@ func (b *builder) NewAddPermissionlessDelegatorTx( toBurn := map[ids.ID]uint64{} // fees are calculated in financeTx // feesMan cumulates complexity. Let's init it with utx filled so far - if _, err := feeCalc.ComputeFee(utx); err != nil { + if _, err := feeCalc.ComputeFee(utx, nil); err != nil { return nil, err } diff --git a/wallet/chain/p/builder_test.go b/wallet/chain/p/builder_test.go index f84aff75b5b4..0cea1cabda1e 100644 --- a/wallet/chain/p/builder_test.go +++ b/wallet/chain/p/builder_test.go @@ -100,7 +100,7 @@ func TestBaseTx(t *testing.T) { ) { // Post E-Upgrade - feeCalc := fee.NewDynamicCalculator(testStaticConfig, commonfees.NewManager(testFeeRates), testBlockMaxComplexity, nil) + feeCalc := fee.NewDynamicCalculator(testStaticConfig, commonfees.NewManager(testFeeRates), testBlockMaxComplexity) utx, err := builder.NewBaseTx( outputsToMove, feeCalc, @@ -110,8 +110,8 @@ func TestBaseTx(t *testing.T) { tx, err := signer.SignUnsigned(stdcontext.Background(), s, utx) require.NoError(err) - fc := fee.NewDynamicCalculator(testStaticConfig, commonfees.NewManager(testFeeRates), testBlockMaxComplexity, tx.Creds) - fee, err := fc.ComputeFee(utx) + fc := fee.NewDynamicCalculator(testStaticConfig, commonfees.NewManager(testFeeRates), testBlockMaxComplexity) + fee, err := fc.ComputeFee(utx, tx.Creds) require.NoError(err) require.Equal(9930*units.MicroAvax, fee) @@ -136,7 +136,7 @@ func TestBaseTx(t *testing.T) { require.NoError(err) fc := fee.NewStaticCalculator(testStaticConfig, upgrade.Config{}, time.Time{}) - fee, err := fc.ComputeFee(utx) + fee, err := fc.ComputeFee(utx, nil) require.NoError(err) require.Equal(testContext.BaseTxFee, fee) @@ -204,15 +204,15 @@ func TestAddSubnetValidatorTx(t *testing.T) { ) { // Post E-Upgrade - feeCalc := fee.NewDynamicCalculator(testStaticConfig, commonfees.NewManager(testFeeRates), testBlockMaxComplexity, nil) + feeCalc := fee.NewDynamicCalculator(testStaticConfig, commonfees.NewManager(testFeeRates), testBlockMaxComplexity) utx, err := builder.NewAddSubnetValidatorTx(subnetValidator, feeCalc) require.NoError(err) tx, err := signer.SignUnsigned(stdcontext.Background(), s, utx) require.NoError(err) - fc := fee.NewDynamicCalculator(testStaticConfig, commonfees.NewManager(testFeeRates), testBlockMaxComplexity, tx.Creds) - fee, err := fc.ComputeFee(utx) + fc := fee.NewDynamicCalculator(testStaticConfig, commonfees.NewManager(testFeeRates), testBlockMaxComplexity) + fee, err := fc.ComputeFee(utx, tx.Creds) require.NoError(err) require.Equal(9765*units.MicroAvax, fee) @@ -233,7 +233,7 @@ func TestAddSubnetValidatorTx(t *testing.T) { require.NoError(err) fc := fee.NewStaticCalculator(testStaticConfig, upgrade.Config{}, time.Time{}) - fee, err := fc.ComputeFee(utx) + fee, err := fc.ComputeFee(utx, nil) require.NoError(err) require.Equal(testContext.AddSubnetValidatorFee, fee) @@ -292,7 +292,7 @@ func TestRemoveSubnetValidatorTx(t *testing.T) { ) { // Post E-Upgrade - feeCalc := fee.NewDynamicCalculator(testStaticConfig, commonfees.NewManager(testFeeRates), testBlockMaxComplexity, nil) + feeCalc := fee.NewDynamicCalculator(testStaticConfig, commonfees.NewManager(testFeeRates), testBlockMaxComplexity) utx, err := builder.NewRemoveSubnetValidatorTx( ids.GenerateTestNodeID(), subnetID, @@ -303,8 +303,8 @@ func TestRemoveSubnetValidatorTx(t *testing.T) { tx, err := signer.SignUnsigned(stdcontext.Background(), s, utx) require.NoError(err) - fc := fee.NewDynamicCalculator(testStaticConfig, commonfees.NewManager(testFeeRates), testBlockMaxComplexity, tx.Creds) - fee, err := fc.ComputeFee(utx) + fc := fee.NewDynamicCalculator(testStaticConfig, commonfees.NewManager(testFeeRates), testBlockMaxComplexity) + fee, err := fc.ComputeFee(utx, tx.Creds) require.NoError(err) require.Equal(9741*units.MicroAvax, fee) @@ -329,7 +329,7 @@ func TestRemoveSubnetValidatorTx(t *testing.T) { require.NoError(err) fc := fee.NewStaticCalculator(testStaticConfig, upgrade.Config{}, time.Time{}) - fee, err := fc.ComputeFee(utx) + fee, err := fc.ComputeFee(utx, nil) require.NoError(err) require.Equal(testContext.BaseTxFee, fee) @@ -394,7 +394,7 @@ func TestCreateChainTx(t *testing.T) { ) { // Post E-Upgrade - feeCalc := fee.NewDynamicCalculator(testStaticConfig, commonfees.NewManager(testFeeRates), testBlockMaxComplexity, nil) + feeCalc := fee.NewDynamicCalculator(testStaticConfig, commonfees.NewManager(testFeeRates), testBlockMaxComplexity) utx, err := builder.NewCreateChainTx( subnetID, genesisBytes, @@ -408,8 +408,8 @@ func TestCreateChainTx(t *testing.T) { tx, err := signer.SignUnsigned(stdcontext.Background(), s, utx) require.NoError(err) - fc := fee.NewDynamicCalculator(testStaticConfig, commonfees.NewManager(testFeeRates), testBlockMaxComplexity, tx.Creds) - fee, err := fc.ComputeFee(utx) + fc := fee.NewDynamicCalculator(testStaticConfig, commonfees.NewManager(testFeeRates), testBlockMaxComplexity) + fee, err := fc.ComputeFee(utx, tx.Creds) require.NoError(err) require.Equal(9808*units.MicroAvax, fee) @@ -437,7 +437,7 @@ func TestCreateChainTx(t *testing.T) { require.NoError(err) fc := fee.NewStaticCalculator(testStaticConfig, upgrade.Config{}, time.Time{}) - fee, err := fc.ComputeFee(utx) + fee, err := fc.ComputeFee(utx, nil) require.NoError(err) require.Equal(testContext.CreateBlockchainTxFee, fee) @@ -496,7 +496,7 @@ func TestCreateSubnetTx(t *testing.T) { ) { // Post E-Upgrade - feeCalc := fee.NewDynamicCalculator(testStaticConfig, commonfees.NewManager(testFeeRates), testBlockMaxComplexity, nil) + feeCalc := fee.NewDynamicCalculator(testStaticConfig, commonfees.NewManager(testFeeRates), testBlockMaxComplexity) utx, err := builder.NewCreateSubnetTx( subnetOwner, feeCalc, @@ -506,8 +506,8 @@ func TestCreateSubnetTx(t *testing.T) { tx, err := signer.SignUnsigned(stdcontext.Background(), s, utx) require.NoError(err) - fc := fee.NewDynamicCalculator(testStaticConfig, commonfees.NewManager(testFeeRates), testBlockMaxComplexity, tx.Creds) - fee, err := fc.ComputeFee(utx) + fc := fee.NewDynamicCalculator(testStaticConfig, commonfees.NewManager(testFeeRates), testBlockMaxComplexity) + fee, err := fc.ComputeFee(utx, tx.Creds) require.NoError(err) require.Equal(9644*units.MicroAvax, fee) @@ -531,7 +531,7 @@ func TestCreateSubnetTx(t *testing.T) { require.NoError(err) fc := fee.NewStaticCalculator(testStaticConfig, upgrade.Config{}, time.Time{}) - fee, err := fc.ComputeFee(utx) + fee, err := fc.ComputeFee(utx, nil) require.NoError(err) require.Equal(testContext.CreateSubnetTxFee, fee) @@ -590,7 +590,7 @@ func TestTransferSubnetOwnershipTx(t *testing.T) { ) { // Post E-Upgrade - feeCalc := fee.NewDynamicCalculator(testStaticConfig, commonfees.NewManager(testFeeRates), testBlockMaxComplexity, nil) + feeCalc := fee.NewDynamicCalculator(testStaticConfig, commonfees.NewManager(testFeeRates), testBlockMaxComplexity) utx, err := builder.NewTransferSubnetOwnershipTx( subnetID, subnetOwner, @@ -601,8 +601,8 @@ func TestTransferSubnetOwnershipTx(t *testing.T) { tx, err := signer.SignUnsigned(stdcontext.Background(), s, utx) require.NoError(err) - fc := fee.NewDynamicCalculator(testStaticConfig, commonfees.NewManager(testFeeRates), testBlockMaxComplexity, tx.Creds) - fee, err := fc.ComputeFee(utx) + fc := fee.NewDynamicCalculator(testStaticConfig, commonfees.NewManager(testFeeRates), testBlockMaxComplexity) + fee, err := fc.ComputeFee(utx, tx.Creds) require.NoError(err) require.Equal(9761*units.MicroAvax, fee) @@ -627,7 +627,7 @@ func TestTransferSubnetOwnershipTx(t *testing.T) { require.NoError(err) fc := fee.NewStaticCalculator(testStaticConfig, upgrade.Config{}, time.Time{}) - fee, err := fc.ComputeFee(utx) + fee, err := fc.ComputeFee(utx, nil) require.NoError(err) require.Equal(testContext.BaseTxFee, fee) @@ -680,7 +680,7 @@ func TestImportTx(t *testing.T) { ) { // Post E-Upgrade - feeCalc := fee.NewDynamicCalculator(testStaticConfig, commonfees.NewManager(testFeeRates), testBlockMaxComplexity, nil) + feeCalc := fee.NewDynamicCalculator(testStaticConfig, commonfees.NewManager(testFeeRates), testBlockMaxComplexity) utx, err := builder.NewImportTx( sourceChainID, importTo, @@ -691,8 +691,8 @@ func TestImportTx(t *testing.T) { tx, err := signer.SignUnsigned(stdcontext.Background(), s, utx) require.NoError(err) - fc := fee.NewDynamicCalculator(testStaticConfig, commonfees.NewManager(testFeeRates), testBlockMaxComplexity, tx.Creds) - fee, err := fc.ComputeFee(utx) + fc := fee.NewDynamicCalculator(testStaticConfig, commonfees.NewManager(testFeeRates), testBlockMaxComplexity) + fee, err := fc.ComputeFee(utx, tx.Creds) require.NoError(err) require.Equal(14251*units.MicroAvax, fee) @@ -719,7 +719,7 @@ func TestImportTx(t *testing.T) { require.NoError(err) fc := fee.NewStaticCalculator(testStaticConfig, upgrade.Config{}, time.Time{}) - fee, err := fc.ComputeFee(utx) + fee, err := fc.ComputeFee(utx, nil) require.NoError(err) require.Equal(testContext.BaseTxFee, fee) @@ -770,7 +770,7 @@ func TestExportTx(t *testing.T) { ) { // Post E-Upgrade - feeCalc := fee.NewDynamicCalculator(testStaticConfig, commonfees.NewManager(testFeeRates), testBlockMaxComplexity, nil) + feeCalc := fee.NewDynamicCalculator(testStaticConfig, commonfees.NewManager(testFeeRates), testBlockMaxComplexity) utx, err := builder.NewExportTx( subnetID, exportedOutputs, @@ -781,8 +781,8 @@ func TestExportTx(t *testing.T) { tx, err := signer.SignUnsigned(stdcontext.Background(), s, utx) require.NoError(err) - fc := fee.NewDynamicCalculator(testStaticConfig, commonfees.NewManager(testFeeRates), testBlockMaxComplexity, tx.Creds) - fee, err := fc.ComputeFee(utx) + fc := fee.NewDynamicCalculator(testStaticConfig, commonfees.NewManager(testFeeRates), testBlockMaxComplexity) + fee, err := fc.ComputeFee(utx, tx.Creds) require.NoError(err) require.Equal(9966*units.MicroAvax, fee) @@ -808,7 +808,7 @@ func TestExportTx(t *testing.T) { require.NoError(err) fc := fee.NewStaticCalculator(testStaticConfig, upgrade.Config{}, time.Time{}) - fee, err := fc.ComputeFee(utx) + fee, err := fc.ComputeFee(utx, nil) require.NoError(err) require.Equal(testContext.BaseTxFee, fee) @@ -872,7 +872,7 @@ func TestTransformSubnetTx(t *testing.T) { ) { // Post E-Upgrade - feeCalc := fee.NewDynamicCalculator(testStaticConfig, commonfees.NewManager(testFeeRates), testBlockMaxComplexity, nil) + feeCalc := fee.NewDynamicCalculator(testStaticConfig, commonfees.NewManager(testFeeRates), testBlockMaxComplexity) utx, err := builder.NewTransformSubnetTx( subnetID, subnetAssetID, @@ -895,8 +895,8 @@ func TestTransformSubnetTx(t *testing.T) { tx, err := signer.SignUnsigned(stdcontext.Background(), s, utx) require.NoError(err) - fc := fee.NewDynamicCalculator(testStaticConfig, commonfees.NewManager(testFeeRates), testBlockMaxComplexity, tx.Creds) - fee, err := fc.ComputeFee(utx) + fc := fee.NewDynamicCalculator(testStaticConfig, commonfees.NewManager(testFeeRates), testBlockMaxComplexity) + fee, err := fc.ComputeFee(utx, tx.Creds) require.NoError(err) require.Equal(14763*units.MicroAvax, fee) @@ -936,7 +936,7 @@ func TestTransformSubnetTx(t *testing.T) { require.NoError(err) fc := fee.NewStaticCalculator(testStaticConfig, upgrade.Config{}, time.Time{}) - fee, err := fc.ComputeFee(utx) + fee, err := fc.ComputeFee(utx, nil) require.NoError(err) require.Equal(testContext.TransformSubnetTxFee, fee) @@ -994,7 +994,7 @@ func TestAddPermissionlessValidatorTx(t *testing.T) { require.NoError(err) { // Post E-Upgrade - feeCalc := fee.NewDynamicCalculator(testStaticConfig, commonfees.NewManager(testFeeRates), testBlockMaxComplexity, nil) + feeCalc := fee.NewDynamicCalculator(testStaticConfig, commonfees.NewManager(testFeeRates), testBlockMaxComplexity) utx, err := builder.NewAddPermissionlessValidatorTx( &txs.SubnetValidator{ Validator: txs.Validator{ @@ -1016,8 +1016,8 @@ func TestAddPermissionlessValidatorTx(t *testing.T) { tx, err := signer.SignUnsigned(stdcontext.Background(), s, utx) require.NoError(err) - fc := fee.NewDynamicCalculator(testStaticConfig, commonfees.NewManager(testFeeRates), testBlockMaxComplexity, tx.Creds) - fee, err := fc.ComputeFee(utx) + fc := fee.NewDynamicCalculator(testStaticConfig, commonfees.NewManager(testFeeRates), testBlockMaxComplexity) + fee, err := fc.ComputeFee(utx, tx.Creds) require.NoError(err) require.Equal(20404*units.MicroAvax, fee) @@ -1060,7 +1060,7 @@ func TestAddPermissionlessValidatorTx(t *testing.T) { require.NoError(err) fc := fee.NewStaticCalculator(testStaticConfig, upgrade.Config{}, time.Time{}) - fee, err := fc.ComputeFee(utx) + fee, err := fc.ComputeFee(utx, nil) require.NoError(err) require.Equal(testContext.AddPrimaryNetworkValidatorFee, fee) @@ -1113,7 +1113,7 @@ func TestAddPermissionlessDelegatorTx(t *testing.T) { ) { // Post E-Upgrade - feeCalc := fee.NewDynamicCalculator(testStaticConfig, commonfees.NewManager(testFeeRates), testBlockMaxComplexity, nil) + feeCalc := fee.NewDynamicCalculator(testStaticConfig, commonfees.NewManager(testFeeRates), testBlockMaxComplexity) utx, err := builder.NewAddPermissionlessDelegatorTx( &txs.SubnetValidator{ Validator: txs.Validator{ @@ -1132,8 +1132,8 @@ func TestAddPermissionlessDelegatorTx(t *testing.T) { tx, err := signer.SignUnsigned(stdcontext.Background(), s, utx) require.NoError(err) - fc := fee.NewDynamicCalculator(testStaticConfig, commonfees.NewManager(testFeeRates), testBlockMaxComplexity, tx.Creds) - fee, err := fc.ComputeFee(utx) + fc := fee.NewDynamicCalculator(testStaticConfig, commonfees.NewManager(testFeeRates), testBlockMaxComplexity) + fee, err := fc.ComputeFee(utx, tx.Creds) require.NoError(err) require.Equal(20212*units.MicroAvax, fee) @@ -1173,7 +1173,7 @@ func TestAddPermissionlessDelegatorTx(t *testing.T) { require.NoError(err) fc := fee.NewStaticCalculator(testStaticConfig, upgrade.Config{}, time.Time{}) - fee, err := fc.ComputeFee(utx) + fee, err := fc.ComputeFee(utx, nil) require.NoError(err) require.Equal(testContext.AddPrimaryNetworkDelegatorFee, fee) diff --git a/wallet/chain/p/wallet.go b/wallet/chain/p/wallet.go index 0c89a41ab792..15e03d315fa1 100644 --- a/wallet/chain/p/wallet.go +++ b/wallet/chain/p/wallet.go @@ -643,7 +643,7 @@ func (w *wallet) feeCalculator(ctx *builder.Context, options ...common.Option) ( } else { feeCfg := fee.GetDynamicConfig(w.isEForkActive) feeMan := commonfees.NewManager(w.nextFeeRates) - feeCalculator = fee.NewDynamicCalculator(w.staticFeesConfig, feeMan, feeCfg.BlockMaxComplexity, nil) + feeCalculator = fee.NewDynamicCalculator(w.staticFeesConfig, feeMan, feeCfg.BlockMaxComplexity) } return feeCalculator, nil } From e3a2fd38a77e35526c1f94f93a0890abb2d39adf Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Wed, 22 May 2024 10:38:04 -0400 Subject: [PATCH 161/190] moved UpdateFeeManager to state package --- vms/platformvm/block/builder/builder.go | 11 +--- vms/platformvm/block/executor/helpers_test.go | 15 +----- vms/platformvm/block/executor/manager.go | 11 +--- vms/platformvm/block/executor/verifier.go | 33 ++++-------- vms/platformvm/service.go | 13 ++--- vms/platformvm/state/block_helpers.go | 35 +++++++++++++ .../txs/executor/create_chain_test.go | 50 ++++++------------- vms/platformvm/txs/executor/helpers_test.go | 9 +--- vms/platformvm/txs/fee/helpers.go | 23 --------- vms/platformvm/txs/txstest/builder.go | 12 ++--- 10 files changed, 74 insertions(+), 138 deletions(-) diff --git a/vms/platformvm/block/builder/builder.go b/vms/platformvm/block/builder/builder.go index 4bd2b960d00a..a860342dd669 100644 --- a/vms/platformvm/block/builder/builder.go +++ b/vms/platformvm/block/builder/builder.go @@ -352,16 +352,7 @@ func packBlockTxs( feeMan := commonfees.NewManager(feeRates) if isEActivated { - feeRates, err := stateDiff.GetFeeRates() - if err != nil { - return nil, fmt.Errorf("failed retrieving fee rates: %w", err) - } - parentBlkComplexity, err := stateDiff.GetLastBlockComplexity() - if err != nil { - return nil, fmt.Errorf("failed retrieving last block complexity: %w", err) - } - - feeMan, err = fee.UpdatedFeeManager(feeRates, parentBlkComplexity, upgrades, parentBlkTime, timestamp) + feeMan, err = state.UpdatedFeeManager(stateDiff, upgrades, parentBlkTime) if err != nil { return nil, err } diff --git a/vms/platformvm/block/executor/helpers_test.go b/vms/platformvm/block/executor/helpers_test.go index 0efc1c7228e8..0de7ec6d07dc 100644 --- a/vms/platformvm/block/executor/helpers_test.go +++ b/vms/platformvm/block/executor/helpers_test.go @@ -303,20 +303,7 @@ func addSubnet(env *environment) { chainTime := env.state.GetTimestamp() upgrades := env.config.UpgradeConfig - nextChainTime, _, err := state.NextBlockTime(env.state, env.clk) - if err != nil { - panic(fmt.Errorf("failed calculating next block time: %w", err)) - } - feeRates, err := env.state.GetFeeRates() - if err != nil { - panic(fmt.Errorf("failed retrieving fee rates: %w", err)) - } - parentBlkComplexity, err := env.state.GetLastBlockComplexity() - if err != nil { - panic(fmt.Errorf("failed retrieving last block complexity: %w", err)) - } - - feeManager, err := fee.UpdatedFeeManager(feeRates, parentBlkComplexity, upgrades, chainTime, nextChainTime) + feeManager, err := state.UpdatedFeeManager(stateDiff, upgrades, chainTime) if err != nil { panic(err) } diff --git a/vms/platformvm/block/executor/manager.go b/vms/platformvm/block/executor/manager.go index d5f3f68c08b3..765238776627 100644 --- a/vms/platformvm/block/executor/manager.go +++ b/vms/platformvm/block/executor/manager.go @@ -5,7 +5,6 @@ package executor import ( "errors" - "fmt" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/snow/consensus/snowman" @@ -162,15 +161,7 @@ func (m *manager) VerifyTx(tx *txs.Tx) error { feeManager := commonfees.NewManager(feeRates) if isEActive { - feeRates, err := stateDiff.GetFeeRates() - if err != nil { - return fmt.Errorf("failed retrieving fee rates: %w", err) - } - parentBlkComplexity, err := stateDiff.GetLastBlockComplexity() - if err != nil { - return fmt.Errorf("failed retrieving last block complexity: %w", err) - } - feeManager, err = fee.UpdatedFeeManager(feeRates, parentBlkComplexity, upgrades, parentBlkTime, nextBlkTime) + feeManager, err = state.UpdatedFeeManager(stateDiff, upgrades, parentBlkTime) if err != nil { return err } diff --git a/vms/platformvm/block/executor/verifier.go b/vms/platformvm/block/executor/verifier.go index 0afb6df2e6c2..b3daaed60005 100644 --- a/vms/platformvm/block/executor/verifier.go +++ b/vms/platformvm/block/executor/verifier.go @@ -78,7 +78,6 @@ func (v *verifier) BanffProposalBlock(b *block.BanffProposalBlock) error { onDecisionState, b.Parent(), parentBlkTime, - b.Timestamp(), ) if err != nil { return err @@ -136,7 +135,7 @@ func (v *verifier) BanffStandardBlock(b *block.BanffStandardBlock) error { return errBanffStandardBlockWithoutChanges } - return v.standardBlock(&b.ApricotStandardBlock, parentBlkTime, b.Timestamp(), onAcceptState) + return v.standardBlock(&b.ApricotStandardBlock, parentBlkTime, onAcceptState) } func (v *verifier) ApricotAbortBlock(b *block.ApricotAbortBlock) error { @@ -182,7 +181,7 @@ func (v *verifier) ApricotStandardBlock(b *block.ApricotStandardBlock) error { return err } - return v.standardBlock(b, time.Time{}, time.Time{}, onAcceptState) + return v.standardBlock(b, time.Time{}, onAcceptState) } func (v *verifier) ApricotAtomicBlock(b *block.ApricotAtomicBlock) error { @@ -430,7 +429,6 @@ func (v *verifier) proposalBlock( func (v *verifier) standardBlock( b *block.ApricotStandardBlock, parentBlkTime time.Time, - blkTimestamp time.Time, onAcceptState state.Diff, ) error { inputs, feeMan, atomicRequests, onAcceptFunc, err := v.processStandardTxs( @@ -438,7 +436,6 @@ func (v *verifier) standardBlock( onAcceptState, b.Parent(), parentBlkTime, - blkTimestamp, ) if err != nil { return err @@ -463,9 +460,9 @@ func (v *verifier) standardBlock( func (v *verifier) processStandardTxs( txs []*txs.Tx, - state state.Diff, + chain state.Diff, parentID ids.ID, - parentBlkTime, blkTimestamp time.Time, + parentBlkTime time.Time, ) ( set.Set[ids.ID], *commonfees.Manager, @@ -473,14 +470,14 @@ func (v *verifier) processStandardTxs( func(), error, ) { - feeRates, err := state.GetFeeRates() + feeRates, err := chain.GetFeeRates() if err != nil { return nil, nil, nil, nil, err } var ( upgrades = v.txExecutorBackend.Config.UpgradeConfig - isEActive = upgrades.IsEActivated(state.GetTimestamp()) + isEActive = upgrades.IsEActivated(chain.GetTimestamp()) feesCfg = fee.GetDynamicConfig(isEActive) onAcceptFunc func() @@ -491,15 +488,7 @@ func (v *verifier) processStandardTxs( feeMan := commonfees.NewManager(feeRates) if isEActive { - feeRates, err := state.GetFeeRates() - if err != nil { - return nil, nil, nil, nil, fmt.Errorf("failed retrieving fee rates: %w", err) - } - parentBlkComplexity, err := state.GetLastBlockComplexity() - if err != nil { - return nil, nil, nil, nil, fmt.Errorf("failed retrieving last block complexity: %w", err) - } - feeMan, err = fee.UpdatedFeeManager(feeRates, parentBlkComplexity, upgrades, parentBlkTime, blkTimestamp) + feeMan, err = state.UpdatedFeeManager(chain, upgrades, parentBlkTime) if err != nil { return nil, nil, nil, nil, err } @@ -510,7 +499,7 @@ func (v *verifier) processStandardTxs( Backend: v.txExecutorBackend, BlkFeeManager: feeMan, BlockMaxComplexity: feesCfg.BlockMaxComplexity, - State: state, + State: chain, Tx: tx, } if err := tx.Unsigned.Visit(&txExecutor); err != nil { @@ -525,7 +514,7 @@ func (v *verifier) processStandardTxs( // Add UTXOs to batch inputs.Union(txExecutor.Inputs) - state.AddTx(tx, status.Committed) + chain.AddTx(tx, status.Committed) if txExecutor.OnAccept != nil { funcs = append(funcs, txExecutor.OnAccept) } @@ -548,8 +537,8 @@ func (v *verifier) processStandardTxs( } if isEActive { - state.SetFeeRates(feeMan.GetFeeRates()) - state.SetLastBlockComplexity(feeMan.GetCumulatedComplexity()) + chain.SetFeeRates(feeMan.GetFeeRates()) + chain.SetLastBlockComplexity(feeMan.GetCumulatedComplexity()) } if numFuncs := len(funcs); numFuncs == 1 { diff --git a/vms/platformvm/service.go b/vms/platformvm/service.go index 403a8f1832c7..0705e269e2f9 100644 --- a/vms/platformvm/service.go +++ b/vms/platformvm/service.go @@ -36,7 +36,6 @@ 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" @@ -1871,15 +1870,9 @@ func (s *Service) GetFeeRates(_ *http.Request, _ *struct{}, reply *GetFeeRatesRe ) if isEActivated { - feeRates, err := onAccept.GetFeeRates() - if err != nil { - return fmt.Errorf("failed retrieving fee rates: %w", err) - } - parentBlkComplexity, err := onAccept.GetLastBlockComplexity() - if err != nil { - return fmt.Errorf("failed retrieving last block complexity: %w", err) - } - feeManager, err = fee.UpdatedFeeManager(feeRates, parentBlkComplexity, upgrades, currentTimestamp, nextTimestamp) + // make sure the diff we update the fee manager from has timestamp duly set + onAccept.SetTimestamp(nextTimestamp) + feeManager, err = state.UpdatedFeeManager(onAccept, upgrades, currentTimestamp) if err != nil { return err } diff --git a/vms/platformvm/state/block_helpers.go b/vms/platformvm/state/block_helpers.go index 036eb168d73d..1b4cca25f1b9 100644 --- a/vms/platformvm/state/block_helpers.go +++ b/vms/platformvm/state/block_helpers.go @@ -9,6 +9,10 @@ import ( "github.com/ava-labs/avalanchego/database" "github.com/ava-labs/avalanchego/utils/timer/mockable" + "github.com/ava-labs/avalanchego/vms/platformvm/txs/fee" + "github.com/ava-labs/avalanchego/vms/platformvm/upgrade" + + commonfees "github.com/ava-labs/avalanchego/vms/components/fees" ) func NextBlockTime(state Chain, clk *mockable.Clock) (time.Time, bool, error) { @@ -68,3 +72,34 @@ func GetNextStakerChangeTime(state Chain) (time.Time, error) { return time.Time{}, database.ErrNotFound } } + +func UpdatedFeeManager(state Chain, upgrades upgrade.Config, parentBlkTime time.Time) (*commonfees.Manager, error) { + var ( + isEActive = upgrades.IsEActivated(parentBlkTime) + feeCfg = fee.GetDynamicConfig(isEActive) + ) + + feeRates, err := state.GetFeeRates() + if err != nil { + return nil, fmt.Errorf("failed retrieving fee rates: %w", err) + } + parentBlkComplexity, err := state.GetLastBlockComplexity() + if err != nil { + return nil, fmt.Errorf("failed retrieving last block complexity: %w", err) + } + childBlkTime := state.GetTimestamp() + + feeManager := commonfees.NewManager(feeRates) + if isEActive { + if err := feeManager.UpdateFeeRates( + feeCfg, + parentBlkComplexity, + parentBlkTime.Unix(), + childBlkTime.Unix(), + ); err != nil { + return nil, fmt.Errorf("failed updating fee rates, %w", err) + } + } + + return feeManager, nil +} diff --git a/vms/platformvm/txs/executor/create_chain_test.go b/vms/platformvm/txs/executor/create_chain_test.go index 87a56036ca3f..0f8541540ac3 100644 --- a/vms/platformvm/txs/executor/create_chain_test.go +++ b/vms/platformvm/txs/executor/create_chain_test.go @@ -51,18 +51,14 @@ func TestCreateChainTxInsufficientControlSigs(t *testing.T) { currentTime := stateDiff.GetTimestamp() upgrades := env.config.UpgradeConfig - nextBlkTime, _, err := state.NextBlockTime(stateDiff, env.clk) - require.NoError(err) - feeCfg := fee.GetDynamicConfig(upgrades.IsEActivated(currentTime)) - feeRates, err := stateDiff.GetFeeRates() + builderDiff, err := state.NewDiffOn(stateDiff) require.NoError(err) - - parentBlkComplexity, err := stateDiff.GetLastBlockComplexity() + nextBlkTime, _, err := state.NextBlockTime(stateDiff, env.clk) require.NoError(err) - - feeMan, err := fee.UpdatedFeeManager(feeRates, parentBlkComplexity, upgrades, currentTime, nextBlkTime) + builderDiff.SetTimestamp(nextBlkTime) + feeMan, err := state.UpdatedFeeManager(builderDiff, upgrades, currentTime) require.NoError(err) executor := StandardTxExecutor{ @@ -107,18 +103,14 @@ func TestCreateChainTxWrongControlSig(t *testing.T) { currentTime := stateDiff.GetTimestamp() upgrades := env.config.UpgradeConfig - nextBlkTime, _, err := state.NextBlockTime(stateDiff, env.clk) - require.NoError(err) - feeCfg := fee.GetDynamicConfig(upgrades.IsEActivated(currentTime)) - feeRates, err := stateDiff.GetFeeRates() + builderDiff, err := state.NewDiffOn(stateDiff) require.NoError(err) - - parentBlkComplexity, err := stateDiff.GetLastBlockComplexity() + nextBlkTime, _, err := state.NextBlockTime(stateDiff, env.clk) require.NoError(err) - - feeMan, err := fee.UpdatedFeeManager(feeRates, parentBlkComplexity, upgrades, currentTime, nextBlkTime) + builderDiff.SetTimestamp(nextBlkTime) + feeMan, err := state.UpdatedFeeManager(builderDiff, upgrades, currentTime) require.NoError(err) executor := StandardTxExecutor{ @@ -157,19 +149,14 @@ func TestCreateChainTxNoSuchSubnet(t *testing.T) { currentTime := stateDiff.GetTimestamp() upgrades := env.config.UpgradeConfig - - nextBlkTime, _, err := state.NextBlockTime(stateDiff, env.clk) - require.NoError(err) - feeCfg := fee.GetDynamicConfig(upgrades.IsEActivated(currentTime)) - feeRates, err := stateDiff.GetFeeRates() + builderDiff, err := state.NewDiffOn(stateDiff) require.NoError(err) - - parentBlkComplexity, err := stateDiff.GetLastBlockComplexity() + nextBlkTime, _, err := state.NextBlockTime(stateDiff, env.clk) require.NoError(err) - - feeMan, err := fee.UpdatedFeeManager(feeRates, parentBlkComplexity, upgrades, currentTime, nextBlkTime) + builderDiff.SetTimestamp(nextBlkTime) + feeMan, err := state.UpdatedFeeManager(builderDiff, upgrades, currentTime) require.NoError(err) executor := StandardTxExecutor{ @@ -205,19 +192,14 @@ func TestCreateChainTxValid(t *testing.T) { currentTime := stateDiff.GetTimestamp() upgrades := env.config.UpgradeConfig - - nextBlkTime, _, err := state.NextBlockTime(stateDiff, env.clk) - require.NoError(err) - feeCfg := fee.GetDynamicConfig(upgrades.IsEActivated(currentTime)) - feeRates, err := stateDiff.GetFeeRates() + builderDiff, err := state.NewDiffOn(stateDiff) require.NoError(err) - - parentBlkComplexity, err := stateDiff.GetLastBlockComplexity() + nextBlkTime, _, err := state.NextBlockTime(stateDiff, env.clk) require.NoError(err) - - feeMan, err := fee.UpdatedFeeManager(feeRates, parentBlkComplexity, upgrades, currentTime, nextBlkTime) + builderDiff.SetTimestamp(nextBlkTime) + feeMan, err := state.UpdatedFeeManager(builderDiff, upgrades, currentTime) require.NoError(err) executor := StandardTxExecutor{ diff --git a/vms/platformvm/txs/executor/helpers_test.go b/vms/platformvm/txs/executor/helpers_test.go index 5aa8a88b131e..7f4c1823487e 100644 --- a/vms/platformvm/txs/executor/helpers_test.go +++ b/vms/platformvm/txs/executor/helpers_test.go @@ -235,14 +235,7 @@ func addSubnet(t *testing.T, env *environment) { currentChainTime := env.state.GetTimestamp() upgrades := env.config.UpgradeConfig - - nextChainTime, _, err := state.NextBlockTime(stateDiff, env.clk) - require.NoError(err) - feeRates, err := stateDiff.GetFeeRates() - require.NoError(err) - parentBlkComplexity, err := stateDiff.GetLastBlockComplexity() - require.NoError(err) - feeManager, err := fee.UpdatedFeeManager(feeRates, parentBlkComplexity, upgrades, currentChainTime, nextChainTime) + feeManager, err := state.UpdatedFeeManager(stateDiff, upgrades, currentChainTime) require.NoError(err) feeCfg := fee.GetDynamicConfig(upgrades.IsEActivated(currentChainTime)) diff --git a/vms/platformvm/txs/fee/helpers.go b/vms/platformvm/txs/fee/helpers.go index bec33f6468e8..4148a79aae9b 100644 --- a/vms/platformvm/txs/fee/helpers.go +++ b/vms/platformvm/txs/fee/helpers.go @@ -5,12 +5,10 @@ package fee import ( "fmt" - "time" "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/components/fees" "github.com/ava-labs/avalanchego/vms/platformvm/txs" - "github.com/ava-labs/avalanchego/vms/platformvm/upgrade" ) func FinanceInput(feeCalc *Calculator, input *avax.TransferableInput) (uint64, error) { @@ -60,24 +58,3 @@ func FinanceCredential(feeCalc *Calculator, keysCount int) (uint64, error) { } return addedFees, nil } - -func UpdatedFeeManager(feeRates, parentBlkComplexity fees.Dimensions, upgrades upgrade.Config, parentBlkTime, nextBlkTime time.Time) (*fees.Manager, error) { - var ( - isEActive = upgrades.IsEActivated(parentBlkTime) - feeCfg = GetDynamicConfig(isEActive) - ) - - feeManager := fees.NewManager(feeRates) - if isEActive { - if err := feeManager.UpdateFeeRates( - feeCfg, - parentBlkComplexity, - parentBlkTime.Unix(), - nextBlkTime.Unix(), - ); err != nil { - return nil, fmt.Errorf("failed updating fee rates, %w", err) - } - } - - return feeManager, nil -} diff --git a/vms/platformvm/txs/txstest/builder.go b/vms/platformvm/txs/txstest/builder.go index 135140d3594e..aba2022e266b 100644 --- a/vms/platformvm/txs/txstest/builder.go +++ b/vms/platformvm/txs/txstest/builder.go @@ -436,16 +436,14 @@ func (b *Builder) FeeCalculator() (*fee.Calculator, error) { if err != nil { return nil, fmt.Errorf("failed calculating next block time: %w", err) } - feeRates, err := b.state.GetFeeRates() - if err != nil { - return nil, fmt.Errorf("failed retrieving fee rates: %w", err) - } - parentBlkComplexity, err := b.state.GetLastBlockComplexity() + + diff, err := state.NewDiffOn(b.state) if err != nil { - return nil, fmt.Errorf("failed retrieving last block complexity: %w", err) + return nil, fmt.Errorf("failed building diff: %w", err) } + diff.SetTimestamp(nextChainTime) - feeManager, err := fee.UpdatedFeeManager(feeRates, parentBlkComplexity, b.cfg.UpgradeConfig, chainTime, nextChainTime) + feeManager, err := state.UpdatedFeeManager(diff, b.cfg.UpgradeConfig, chainTime) if err != nil { return nil, err } From b9ca2b7b2d76cef26282ec8a817ca54a54a15d13 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Wed, 22 May 2024 15:12:48 -0400 Subject: [PATCH 162/190] nit --- vms/platformvm/state/block_helpers.go | 23 +++++++++++++++ vms/platformvm/txs/txstest/builder.go | 40 ++++++++------------------- 2 files changed, 34 insertions(+), 29 deletions(-) diff --git a/vms/platformvm/state/block_helpers.go b/vms/platformvm/state/block_helpers.go index 1b4cca25f1b9..d24c1636c85d 100644 --- a/vms/platformvm/state/block_helpers.go +++ b/vms/platformvm/state/block_helpers.go @@ -9,6 +9,7 @@ import ( "github.com/ava-labs/avalanchego/database" "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" "github.com/ava-labs/avalanchego/vms/platformvm/upgrade" @@ -103,3 +104,25 @@ func UpdatedFeeManager(state Chain, upgrades upgrade.Config, parentBlkTime time. return feeManager, nil } + +// helper to create either a static or a dynamic fee calculator, depending on the active upgrade +func PickFeeCalculator(cfg *config.Config, state Chain, parentBlkTime time.Time) (*fee.Calculator, error) { + var ( + childBlkTime = state.GetTimestamp() + isEActive = cfg.UpgradeConfig.IsEActivated(childBlkTime) + staticFeeCfg = cfg.StaticFeeConfig + feeCalculator *fee.Calculator + ) + + if !isEActive { + feeCalculator = fee.NewStaticCalculator(staticFeeCfg, cfg.UpgradeConfig, childBlkTime) + } else { + feesCfg := fee.GetDynamicConfig(isEActive) + feesMan, err := UpdatedFeeManager(state, cfg.UpgradeConfig, parentBlkTime) + if err != nil { + return nil, fmt.Errorf("failed updating fee manager: %w", err) + } + feeCalculator = fee.NewDynamicCalculator(staticFeeCfg, feesMan, feesCfg.BlockMaxComplexity) + } + return feeCalculator, nil +} diff --git a/vms/platformvm/txs/txstest/builder.go b/vms/platformvm/txs/txstest/builder.go index aba2022e266b..619863b7ae75 100644 --- a/vms/platformvm/txs/txstest/builder.go +++ b/vms/platformvm/txs/txstest/builder.go @@ -421,35 +421,17 @@ func (b *Builder) builders(keys []*secp256k1.PrivateKey) (builder.Builder, walle } func (b *Builder) FeeCalculator() (*fee.Calculator, error) { - var ( - staticFeeCfg = b.cfg.StaticFeeConfig - upgrades = b.cfg.UpgradeConfig - chainTime = b.state.GetTimestamp() - isEActive = upgrades.IsEActivated(chainTime) - ) + parentBlkTime := b.state.GetTimestamp() + nextBlkTime, _, err := state.NextBlockTime(b.state, b.clk) + if err != nil { + return nil, fmt.Errorf("failed calculating next block time: %w", err) + } - var feeCalculator *fee.Calculator - if !isEActive { - feeCalculator = fee.NewStaticCalculator(staticFeeCfg, upgrades, chainTime) - } else { - nextChainTime, _, err := state.NextBlockTime(b.state, b.clk) - if err != nil { - return nil, fmt.Errorf("failed calculating next block time: %w", err) - } - - diff, err := state.NewDiffOn(b.state) - if err != nil { - return nil, fmt.Errorf("failed building diff: %w", err) - } - diff.SetTimestamp(nextChainTime) - - feeManager, err := state.UpdatedFeeManager(diff, b.cfg.UpgradeConfig, chainTime) - if err != nil { - return nil, err - } - - feeCfg := fee.GetDynamicConfig(isEActive) - feeCalculator = fee.NewDynamicCalculator(staticFeeCfg, feeManager, feeCfg.BlockMaxComplexity) + diff, err := state.NewDiffOn(b.state) + if err != nil { + return nil, fmt.Errorf("failed building diff: %w", err) } - return feeCalculator, nil + diff.SetTimestamp(nextBlkTime) + + return state.PickFeeCalculator(b.cfg, diff, parentBlkTime) } From b007fa19486bde86f4973b552739ca3150b4867b Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 23 May 2024 13:42:54 -0400 Subject: [PATCH 163/190] nit --- vms/platformvm/service.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vms/platformvm/service.go b/vms/platformvm/service.go index b7de8a98d615..3093aefcad7a 100644 --- a/vms/platformvm/service.go +++ b/vms/platformvm/service.go @@ -1851,6 +1851,7 @@ func (s *Service) GetFeeRates(_ *http.Request, _ *struct{}, reply *GetFeeRatesRe } reply.CurrentFeeRates = currentFeeRate + 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) @@ -1862,7 +1863,7 @@ func (s *Service) GetFeeRates(_ *http.Request, _ *struct{}, reply *GetFeeRatesRe } stateDiff.SetTimestamp(nextTimestamp) - feeCalculator, err := state.PickFeeCalculator(&s.vm.Config, stateDiff, onAccept.GetTimestamp()) + feeCalculator, err := state.PickFeeCalculator(&s.vm.Config, stateDiff, currentChainTime) if err != nil { return err } From c73453589e19d257a66c17ed91442d23fe990871 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 23 May 2024 16:35:55 -0400 Subject: [PATCH 164/190] nit --- vms/platformvm/service_test.go | 42 ++++++++++++++++----------- vms/platformvm/state/block_helpers.go | 6 ++-- vms/platformvm/vm_test.go | 20 ++----------- 3 files changed, 30 insertions(+), 38 deletions(-) diff --git a/vms/platformvm/service_test.go b/vms/platformvm/service_test.go index cc406a32818f..011155977bf1 100644 --- a/vms/platformvm/service_test.go +++ b/vms/platformvm/service_test.go @@ -35,6 +35,7 @@ import ( "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/platformvm/block" "github.com/ava-labs/avalanchego/vms/platformvm/block/builder" + "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" @@ -76,6 +77,28 @@ var ( } ) +func testReplayFeeCalculator(cfg *config.Config, state state.Chain) (*fee.Calculator, error) { + var ( + blkTime = state.GetTimestamp() + isEActive = cfg.UpgradeConfig.IsEActivated(blkTime) + staticFeeCfg = cfg.StaticFeeConfig + feeCalculator *fee.Calculator + ) + + if !isEActive { + feeCalculator = fee.NewStaticCalculator(staticFeeCfg, cfg.UpgradeConfig, blkTime) + } else { + feesCfg := fee.GetDynamicConfig(isEActive) + feeRates, err := state.GetFeeRates() + if err != nil { + return nil, fmt.Errorf("failed retrieving fee rates: %w", err) + } + feesMan := commonfees.NewManager(feeRates) + feeCalculator = fee.NewDynamicCalculator(staticFeeCfg, feesMan, feesCfg.BlockMaxComplexity) + } + return feeCalculator, nil +} + func defaultService(t *testing.T) (*Service, *mutableSharedMemory, *txstest.Builder) { vm, txBuilder, _, mutableSharedMemory := defaultVM(t, latestFork) @@ -383,23 +406,8 @@ 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 - var ( - chainTime = service.vm.state.GetTimestamp() - staticFeeCfg = service.vm.Config.StaticFeeConfig - upgrades = service.vm.Config.UpgradeConfig - feeCalc *fee.Calculator - ) - - if !upgrades.IsEActivated(chainTime) { - feeCalc = fee.NewStaticCalculator(staticFeeCfg, upgrades, chainTime) - } else { - feeRates, err := service.vm.state.GetFeeRates() - require.NoError(err) - - feeCfg := fee.GetDynamicConfig(true) - feeMan := commonfees.NewManager(feeRates) - feeCalc = fee.NewDynamicCalculator(staticFeeCfg, feeMan, feeCfg.BlockMaxComplexity) - } + feeCalc, err := testReplayFeeCalculator(&service.vm.Config, service.vm.state) + require.NoError(err) fee, err := feeCalc.ComputeFee(testSubnet1.Unsigned, testSubnet1.Creds) require.NoError(err) diff --git a/vms/platformvm/state/block_helpers.go b/vms/platformvm/state/block_helpers.go index 583ef3c0060d..b89051313664 100644 --- a/vms/platformvm/state/block_helpers.go +++ b/vms/platformvm/state/block_helpers.go @@ -75,7 +75,7 @@ func GetNextStakerChangeTime(state Chain) (time.Time, error) { } // [PickFeeCalculator] creates either a static or a dynamic fee calculator, depending on the active upgrade -// [PickFeeCalculators] does not mnodify [state] +// [PickFeeCalculator] does not mnodify [state] func PickFeeCalculator(cfg *config.Config, state Chain, parentBlkTime time.Time) (*fee.Calculator, error) { var ( childBlkTime = state.GetTimestamp() @@ -88,7 +88,7 @@ func PickFeeCalculator(cfg *config.Config, state Chain, parentBlkTime time.Time) feeCalculator = fee.NewStaticCalculator(staticFeeCfg, cfg.UpgradeConfig, childBlkTime) } else { feesCfg := fee.GetDynamicConfig(isEActive) - feesMan, err := updatedFeeManager(state, cfg.UpgradeConfig, parentBlkTime) + feesMan, err := updatedFeeManager(cfg.UpgradeConfig, state, parentBlkTime) if err != nil { return nil, fmt.Errorf("failed updating fee manager: %w", err) } @@ -97,7 +97,7 @@ func PickFeeCalculator(cfg *config.Config, state Chain, parentBlkTime time.Time) return feeCalculator, nil } -func updatedFeeManager(state Chain, upgrades upgrade.Config, parentBlkTime time.Time) (*commonfees.Manager, error) { +func updatedFeeManager(upgrades upgrade.Config, state Chain, parentBlkTime time.Time) (*commonfees.Manager, error) { var ( isEActive = upgrades.IsEActivated(parentBlkTime) feeCfg = fee.GetDynamicConfig(isEActive) diff --git a/vms/platformvm/vm_test.go b/vms/platformvm/vm_test.go index 3f60e11dad19..8753f054a093 100644 --- a/vms/platformvm/vm_test.go +++ b/vms/platformvm/vm_test.go @@ -67,7 +67,6 @@ import ( smeng "github.com/ava-labs/avalanchego/snow/engine/snowman" snowgetter "github.com/ava-labs/avalanchego/snow/engine/snowman/getter" timetracker "github.com/ava-labs/avalanchego/snow/networking/tracker" - commonfees "github.com/ava-labs/avalanchego/vms/components/fees" blockbuilder "github.com/ava-labs/avalanchego/vms/platformvm/block/builder" blockexecutor "github.com/ava-labs/avalanchego/vms/platformvm/block/executor" txexecutor "github.com/ava-labs/avalanchego/vms/platformvm/txs/executor" @@ -395,23 +394,8 @@ 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 - var ( - chainTime = vm.state.GetTimestamp() - staticFeeCfg = vm.Config.StaticFeeConfig - upgrades = vm.Config.UpgradeConfig - feeCalc *fee.Calculator - ) - - if !upgrades.IsEActivated(chainTime) { - feeCalc = fee.NewStaticCalculator(staticFeeCfg, upgrades, chainTime) - } else { - feeRates, err := vm.state.GetFeeRates() - require.NoError(err) - - feeCfg := fee.GetDynamicConfig(upgrades.IsEActivated(chainTime)) - feeMan := commonfees.NewManager(feeRates) - feeCalc = fee.NewDynamicCalculator(staticFeeCfg, feeMan, feeCfg.BlockMaxComplexity) - } + feeCalc, err := testReplayFeeCalculator(&vm.Config, vm.state) + require.NoError(err) require.NoError(err) fee, err := feeCalc.ComputeFee(testSubnet1.Unsigned, testSubnet1.Creds) From 6073e0e9dbce6dccc4cc66b439335e2619676b59 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 3 Jun 2024 17:35:10 +0200 Subject: [PATCH 165/190] wip: removed block fee rates from state --- .../block/executor/standard_block_test.go | 2 - vms/platformvm/block/executor/verifier.go | 1 - vms/platformvm/service.go | 6 +- vms/platformvm/service_test.go | 59 +++++++------- vms/platformvm/state/block_helpers.go | 6 +- vms/platformvm/state/diff.go | 29 ------- vms/platformvm/state/mock_state.go | 81 ------------------- vms/platformvm/state/state.go | 37 --------- vms/platformvm/vm_test.go | 5 +- 9 files changed, 32 insertions(+), 194 deletions(-) diff --git a/vms/platformvm/block/executor/standard_block_test.go b/vms/platformvm/block/executor/standard_block_test.go index 828140515043..31ac99e2ccdb 100644 --- a/vms/platformvm/block/executor/standard_block_test.go +++ b/vms/platformvm/block/executor/standard_block_test.go @@ -57,7 +57,6 @@ 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().GetFeeRates().Return(commonfees.Empty, nil).AnyTimes() onParentAccept.EXPECT().GetLastBlockComplexity().Return(commonfees.Empty, nil).AnyTimes() // wrong height @@ -152,7 +151,6 @@ func TestBanffStandardBlockTimeVerification(t *testing.T) { } utxoID := utxo.InputID() onParentAccept.EXPECT().GetUTXO(utxoID).Return(utxo, nil).AnyTimes() - onParentAccept.EXPECT().GetFeeRates().Return(commonfees.Empty, nil).AnyTimes() onParentAccept.EXPECT().GetLastBlockComplexity().Return(commonfees.Empty, nil).AnyTimes() // Create the tx diff --git a/vms/platformvm/block/executor/verifier.go b/vms/platformvm/block/executor/verifier.go index 139d3cad3969..f9979d8d0bec 100644 --- a/vms/platformvm/block/executor/verifier.go +++ b/vms/platformvm/block/executor/verifier.go @@ -534,7 +534,6 @@ func (v *verifier) processStandardTxs( } if v.txExecutorBackend.Config.UpgradeConfig.IsEActivated(state.GetTimestamp()) { - state.SetFeeRates(feeCalculator.GetFeeRates()) state.SetLastBlockComplexity(feeCalculator.GetCumulatedComplexity()) } diff --git a/vms/platformvm/service.go b/vms/platformvm/service.go index 3093aefcad7a..550e720113cc 100644 --- a/vms/platformvm/service.go +++ b/vms/platformvm/service.go @@ -1845,11 +1845,7 @@ func (s *Service) GetFeeRates(_ *http.Request, _ *struct{}, reply *GetFeeRatesRe return fmt.Errorf("could not retrieve state for block %s", preferredID) } - currentFeeRate, err := onAccept.GetFeeRates() - if err != nil { - return err - } - reply.CurrentFeeRates = currentFeeRate + reply.CurrentFeeRates = commonfees.Empty // TODO ABENEGIA: fix this up once algo is changed currentChainTime := onAccept.GetTimestamp() nextTimestamp, _, err := state.NextBlockTime(onAccept, &s.vm.clock) diff --git a/vms/platformvm/service_test.go b/vms/platformvm/service_test.go index 011155977bf1..53af697b780f 100644 --- a/vms/platformvm/service_test.go +++ b/vms/platformvm/service_test.go @@ -77,7 +77,7 @@ var ( } ) -func testReplayFeeCalculator(cfg *config.Config, state state.Chain) (*fee.Calculator, error) { +func testReplayFeeCalculator(cfg *config.Config, state state.Chain) *fee.Calculator { var ( blkTime = state.GetTimestamp() isEActive = cfg.UpgradeConfig.IsEActivated(blkTime) @@ -89,14 +89,14 @@ func testReplayFeeCalculator(cfg *config.Config, state state.Chain) (*fee.Calcul feeCalculator = fee.NewStaticCalculator(staticFeeCfg, cfg.UpgradeConfig, blkTime) } else { feesCfg := fee.GetDynamicConfig(isEActive) - feeRates, err := state.GetFeeRates() - if err != nil { - return nil, fmt.Errorf("failed retrieving fee rates: %w", err) - } - feesMan := commonfees.NewManager(feeRates) + // feeRates, err := state.GetFeeRates() + // if err != nil { + // return nil, fmt.Errorf("failed retrieving fee rates: %w", err) + // } + feesMan := commonfees.NewManager(commonfees.Empty /*feeRates*/) // TODO ABENEGIA: fix once fee algo is fixed feeCalculator = fee.NewDynamicCalculator(staticFeeCfg, feesMan, feesCfg.BlockMaxComplexity) } - return feeCalculator, nil + return feeCalculator } func defaultService(t *testing.T) (*Service, *mutableSharedMemory, *txstest.Builder) { @@ -406,9 +406,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 := testReplayFeeCalculator(&service.vm.Config, service.vm.state) - require.NoError(err) - + feeCalc := testReplayFeeCalculator(&service.vm.Config, service.vm.state) fee, err := feeCalc.ComputeFee(testSubnet1.Unsigned, testSubnet1.Creds) require.NoError(err) balance = defaultBalance - fee @@ -1066,29 +1064,30 @@ func TestServiceGetBlockByHeight(t *testing.T) { } } -func TestGetFeeRates(t *testing.T) { - require := require.New(t) - service, _, _ := defaultService(t) +// TODO ABENEGIA: unlock once fee rate algo is being fixed +// func TestGetFeeRates(t *testing.T) { +// require := require.New(t) +// service, _, _ := defaultService(t) - reply := GetFeeRatesReply{} - require.NoError(service.GetFeeRates(nil, nil, &reply)) +// reply := GetFeeRatesReply{} +// require.NoError(service.GetFeeRates(nil, nil, &reply)) - service.vm.ctx.Lock.Lock() +// service.vm.ctx.Lock.Lock() - feeRates, err := service.vm.state.GetFeeRates() - require.NoError(err) - require.Equal(feeRates, reply.CurrentFeeRates) +// feeRates, err := service.vm.state.GetFeeRates() +// require.NoError(err) +// require.Equal(feeRates, reply.CurrentFeeRates) - updatedFeeRates := commonfees.Dimensions{ - 123, - 456, - 789, - 1011, - } - service.vm.state.SetFeeRates(updatedFeeRates) +// updatedFeeRates := commonfees.Dimensions{ +// 123, +// 456, +// 789, +// 1011, +// } +// service.vm.state.SetFeeRates(updatedFeeRates) - service.vm.ctx.Lock.Unlock() +// service.vm.ctx.Lock.Unlock() - require.NoError(service.GetFeeRates(nil, nil, &reply)) - require.Equal(updatedFeeRates, reply.CurrentFeeRates) -} +// require.NoError(service.GetFeeRates(nil, nil, &reply)) +// require.Equal(updatedFeeRates, reply.CurrentFeeRates) +// } diff --git a/vms/platformvm/state/block_helpers.go b/vms/platformvm/state/block_helpers.go index b89051313664..a9e35c5aa12d 100644 --- a/vms/platformvm/state/block_helpers.go +++ b/vms/platformvm/state/block_helpers.go @@ -103,17 +103,13 @@ func updatedFeeManager(upgrades upgrade.Config, state Chain, parentBlkTime time. feeCfg = fee.GetDynamicConfig(isEActive) ) - feeRates, err := state.GetFeeRates() - if err != nil { - return nil, fmt.Errorf("failed retrieving fee rates: %w", err) - } parentBlkComplexity, err := state.GetLastBlockComplexity() if err != nil { return nil, fmt.Errorf("failed retrieving last block complexity: %w", err) } childBlkTime := state.GetTimestamp() - feeManager := commonfees.NewManager(feeRates) + feeManager := commonfees.NewManager(commonfees.Empty) // Fee rate non needed anymore if isEActive { if err := feeManager.UpdateFeeRates( feeCfg, diff --git a/vms/platformvm/state/diff.go b/vms/platformvm/state/diff.go index 256ede8f9d1a..15258de8f674 100644 --- a/vms/platformvm/state/diff.go +++ b/vms/platformvm/state/diff.go @@ -37,7 +37,6 @@ type diff struct { timestamp time.Time - feeRates *commonfees.Dimensions lastBlkComplexity *commonfees.Dimensions // Subnet ID --> supply of native asset of the subnet @@ -94,31 +93,6 @@ func NewDiffOn(parentState Chain) (Diff, error) { }) } -func (d *diff) GetFeeRates() (commonfees.Dimensions, error) { - if d.feeRates == nil { - parentState, ok := d.stateVersions.GetState(d.parentID) - if !ok { - return commonfees.Empty, fmt.Errorf("%w: %s", ErrMissingParentState, d.parentID) - } - parentFeeRates, err := parentState.GetFeeRates() - if err != nil { - return commonfees.Empty, err - } - - d.feeRates = new(commonfees.Dimensions) - *d.feeRates = parentFeeRates - } - - return *d.feeRates, nil -} - -func (d *diff) SetFeeRates(uf commonfees.Dimensions) { - if d.feeRates == nil { - d.feeRates = new(commonfees.Dimensions) - } - *d.feeRates = uf -} - func (d *diff) GetLastBlockComplexity() (commonfees.Dimensions, error) { if d.lastBlkComplexity == nil { parentState, ok := d.stateVersions.GetState(d.parentID) @@ -456,9 +430,6 @@ func (d *diff) DeleteUTXO(utxoID ids.ID) { func (d *diff) Apply(baseState Chain) error { baseState.SetTimestamp(d.timestamp) - if d.feeRates != nil { - baseState.SetFeeRates(*d.feeRates) - } if d.lastBlkComplexity != nil { baseState.SetLastBlockComplexity(*d.lastBlkComplexity) } diff --git a/vms/platformvm/state/mock_state.go b/vms/platformvm/state/mock_state.go index c03d7cd47622..ff5f342ba42a 100644 --- a/vms/platformvm/state/mock_state.go +++ b/vms/platformvm/state/mock_state.go @@ -258,21 +258,6 @@ func (mr *MockChainMockRecorder) GetDelegateeReward(arg0, arg1 any) *gomock.Call return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDelegateeReward", reflect.TypeOf((*MockChain)(nil).GetDelegateeReward), arg0, arg1) } -// GetFeeRates mocks base method. -func (m *MockChain) GetFeeRates() (fees.Dimensions, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetFeeRates") - ret0, _ := ret[0].(fees.Dimensions) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetFeeRates indicates an expected call of GetFeeRates. -func (mr *MockChainMockRecorder) GetFeeRates() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFeeRates", reflect.TypeOf((*MockChain)(nil).GetFeeRates)) -} - // GetLastBlockComplexity mocks base method. func (m *MockChain) GetLastBlockComplexity() (fees.Dimensions, error) { m.ctrl.T.Helper() @@ -482,18 +467,6 @@ func (mr *MockChainMockRecorder) SetDelegateeReward(arg0, arg1, arg2 any) *gomoc return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetDelegateeReward", reflect.TypeOf((*MockChain)(nil).SetDelegateeReward), arg0, arg1, arg2) } -// SetFeeRates mocks base method. -func (m *MockChain) SetFeeRates(arg0 fees.Dimensions) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "SetFeeRates", arg0) -} - -// SetFeeRates indicates an expected call of SetFeeRates. -func (mr *MockChainMockRecorder) SetFeeRates(arg0 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetFeeRates", reflect.TypeOf((*MockChain)(nil).SetFeeRates), arg0) -} - // SetLastBlockComplexity mocks base method. func (m *MockChain) SetLastBlockComplexity(arg0 fees.Dimensions) { m.ctrl.T.Helper() @@ -774,21 +747,6 @@ func (mr *MockDiffMockRecorder) GetDelegateeReward(arg0, arg1 any) *gomock.Call return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDelegateeReward", reflect.TypeOf((*MockDiff)(nil).GetDelegateeReward), arg0, arg1) } -// GetFeeRates mocks base method. -func (m *MockDiff) GetFeeRates() (fees.Dimensions, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetFeeRates") - ret0, _ := ret[0].(fees.Dimensions) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetFeeRates indicates an expected call of GetFeeRates. -func (mr *MockDiffMockRecorder) GetFeeRates() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFeeRates", reflect.TypeOf((*MockDiff)(nil).GetFeeRates)) -} - // GetLastBlockComplexity mocks base method. func (m *MockDiff) GetLastBlockComplexity() (fees.Dimensions, error) { m.ctrl.T.Helper() @@ -998,18 +956,6 @@ func (mr *MockDiffMockRecorder) SetDelegateeReward(arg0, arg1, arg2 any) *gomock return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetDelegateeReward", reflect.TypeOf((*MockDiff)(nil).SetDelegateeReward), arg0, arg1, arg2) } -// SetFeeRates mocks base method. -func (m *MockDiff) SetFeeRates(arg0 fees.Dimensions) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "SetFeeRates", arg0) -} - -// SetFeeRates indicates an expected call of SetFeeRates. -func (mr *MockDiffMockRecorder) SetFeeRates(arg0 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetFeeRates", reflect.TypeOf((*MockDiff)(nil).SetFeeRates), arg0) -} - // SetLastBlockComplexity mocks base method. func (m *MockDiff) SetLastBlockComplexity(arg0 fees.Dimensions) { m.ctrl.T.Helper() @@ -1415,21 +1361,6 @@ func (mr *MockStateMockRecorder) GetDelegateeReward(arg0, arg1 any) *gomock.Call return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDelegateeReward", reflect.TypeOf((*MockState)(nil).GetDelegateeReward), arg0, arg1) } -// GetFeeRates mocks base method. -func (m *MockState) GetFeeRates() (fees.Dimensions, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetFeeRates") - ret0, _ := ret[0].(fees.Dimensions) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetFeeRates indicates an expected call of GetFeeRates. -func (mr *MockStateMockRecorder) GetFeeRates() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFeeRates", reflect.TypeOf((*MockState)(nil).GetFeeRates)) -} - // GetLastAccepted mocks base method. func (m *MockState) GetLastAccepted() ids.ID { m.ctrl.T.Helper() @@ -1743,18 +1674,6 @@ func (mr *MockStateMockRecorder) SetDelegateeReward(arg0, arg1, arg2 any) *gomoc return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetDelegateeReward", reflect.TypeOf((*MockState)(nil).SetDelegateeReward), arg0, arg1, arg2) } -// SetFeeRates mocks base method. -func (m *MockState) SetFeeRates(arg0 fees.Dimensions) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "SetFeeRates", arg0) -} - -// SetFeeRates indicates an expected call of SetFeeRates. -func (mr *MockStateMockRecorder) SetFeeRates(arg0 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetFeeRates", reflect.TypeOf((*MockState)(nil).SetFeeRates), arg0) -} - // SetHeight mocks base method. func (m *MockState) SetHeight(arg0 uint64) { m.ctrl.T.Helper() diff --git a/vms/platformvm/state/state.go b/vms/platformvm/state/state.go index e277ad8e6833..133bb9e22ae6 100644 --- a/vms/platformvm/state/state.go +++ b/vms/platformvm/state/state.go @@ -42,7 +42,6 @@ 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" commonfees "github.com/ava-labs/avalanchego/vms/components/fees" @@ -100,9 +99,6 @@ type Chain interface { avax.UTXOGetter avax.UTXODeleter - GetFeeRates() (commonfees.Dimensions, error) - SetFeeRates(uf commonfees.Dimensions) - GetLastBlockComplexity() (commonfees.Dimensions, error) SetLastBlockComplexity(windows commonfees.Dimensions) @@ -365,7 +361,6 @@ type state struct { // The persisted fields represent the current database value timestamp, persistedTimestamp time.Time - feeRate *commonfees.Dimensions // pointer, to allow customization for test networks lastBlkComplexity commonfees.Dimensions currentSupply, persistedCurrentSupply uint64 // [lastAccepted] is the most recently accepted block. @@ -1015,15 +1010,6 @@ func (s *state) GetStartTime(nodeID ids.NodeID, subnetID ids.ID) (time.Time, err return staker.StartTime, nil } -func (s *state) GetFeeRates() (commonfees.Dimensions, error) { - return *s.feeRate, nil -} - -func (s *state) SetFeeRates(uf commonfees.Dimensions) { - feeRates := uf - s.feeRate = &feeRates -} - func (s *state) GetLastBlockComplexity() (commonfees.Dimensions, error) { return s.lastBlkComplexity, nil } @@ -1322,24 +1308,6 @@ func (s *state) loadMetadata() error { s.persistedTimestamp = timestamp s.SetTimestamp(timestamp) - s.feeRate = new(commonfees.Dimensions) - switch feeRatesBytes, err := s.singletonDB.Get(FeeRatesKey); err { - case nil: - if err := s.feeRate.FromBytes(feeRatesBytes); err != nil { - return err - } - - case database.ErrNotFound: - // fork introducing dynamic fees may not be active yet, - // hence we may have never stored fee rates. Load from config - // TODO: remove once fork is active - isEActive := s.cfg.UpgradeConfig.IsEActivated(timestamp) - *s.feeRate = fee.GetDynamicConfig(isEActive).InitialFeeRate - - default: - return err - } - switch lastBlkComplexityBytes, err := s.singletonDB.Get(LastBlkComplexityKey); err { case nil: if err := s.lastBlkComplexity.FromBytes(lastBlkComplexityBytes); err != nil { @@ -2333,11 +2301,6 @@ func (s *state) writeMetadata() error { s.persistedTimestamp = s.timestamp } - if s.feeRate != nil { - if err := s.singletonDB.Put(FeeRatesKey, s.feeRate.Bytes()); err != nil { - return fmt.Errorf("failed to write fee rates: %w", err) - } - } if err := s.singletonDB.Put(LastBlkComplexityKey, s.lastBlkComplexity.Bytes()); err != nil { return fmt.Errorf("failed to write fee rates: %w", err) } diff --git a/vms/platformvm/vm_test.go b/vms/platformvm/vm_test.go index 8753f054a093..18bfaf9f25ad 100644 --- a/vms/platformvm/vm_test.go +++ b/vms/platformvm/vm_test.go @@ -394,10 +394,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 := testReplayFeeCalculator(&vm.Config, vm.state) - require.NoError(err) - - require.NoError(err) + feeCalc := testReplayFeeCalculator(&vm.Config, vm.state) fee, err := feeCalc.ComputeFee(testSubnet1.Unsigned, testSubnet1.Creds) require.NoError(err) require.Equal(uint64(utxo.Amount)-fee, out.Amount()) From 14941683e98c73980abb7f8fe77d2345d3681d26 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Tue, 4 Jun 2024 14:53:16 +0200 Subject: [PATCH 166/190] wip: changed update fee algo --- tests/e2e/p/dynamic_fees.go | 5 +- vms/components/fees/config.go | 26 +- vms/components/fees/manager.go | 235 +++++------------- vms/components/fees/manager_test.go | 183 +++++--------- vms/platformvm/block/builder/builder.go | 11 +- vms/platformvm/block/executor/acceptor.go | 8 +- vms/platformvm/block/executor/block_state.go | 8 +- .../block/executor/standard_block_test.go | 4 +- vms/platformvm/block/executor/verifier.go | 24 +- .../block/executor/verifier_test.go | 4 +- vms/platformvm/metrics/metrics.go | 6 +- vms/platformvm/metrics/no_op.go | 2 +- vms/platformvm/state/block_helpers.go | 28 ++- vms/platformvm/state/diff.go | 26 +- vms/platformvm/state/mock_state.go | 102 ++++---- vms/platformvm/state/state.go | 40 +-- vms/platformvm/txs/fee/calculator.go | 10 +- vms/platformvm/txs/fee/calculator_test.go | 34 +-- vms/platformvm/txs/fee/dynamic_config.go | 17 +- 19 files changed, 301 insertions(+), 472 deletions(-) diff --git a/tests/e2e/p/dynamic_fees.go b/tests/e2e/p/dynamic_fees.go index 6aa8e2e26c08..0b5425a7b4d6 100644 --- a/tests/e2e/p/dynamic_fees.go +++ b/tests/e2e/p/dynamic_fees.go @@ -25,9 +25,8 @@ var _ = ginkgo.Describe("[Dynamic Fees]", func() { ginkgo.It("should ensure that the dynamic multifees are affected by load", func() { customDynamicFeesConfig := commonfees.DynamicFeesConfig{ - InitialFeeRate: commonfees.Dimensions{1, 2, 3, 4}, MinFeeRate: commonfees.Dimensions{1, 1, 1, 1}, - UpdateCoefficient: commonfees.Dimensions{5, 2, 2, 3}, + UpdateDenominators: commonfees.Dimensions{5, 2, 2, 3}, BlockMaxComplexity: commonfees.Dimensions{math.MaxUint64, math.MaxUint64, math.MaxUint64, math.MaxUint64}, // BlockUnitsTarget are set to cause an increase of fees while simple transactions are issued @@ -68,7 +67,7 @@ var _ = ginkgo.Describe("[Dynamic Fees]", func() { ginkgo.By("checking that initial fee values match with configured ones", func() { currFeeRates, _, err := pChainClient.GetFeeRates(e2e.DefaultContext()) require.NoError(err) - require.Equal(customDynamicFeesConfig.InitialFeeRate, currFeeRates) + require.Equal(customDynamicFeesConfig.MinFeeRate, currFeeRates) }) ginkgo.By("issue expensive transactions so to increase the fee rates to be paid for accepting the transactons", diff --git a/vms/components/fees/config.go b/vms/components/fees/config.go index eb9b4af12d9a..576babbf14de 100644 --- a/vms/components/fees/config.go +++ b/vms/components/fees/config.go @@ -6,21 +6,15 @@ package fees import "fmt" type DynamicFeesConfig struct { - // InitialFeeRate contains, per each fee dimension, the - // fee rate, i.e. the fee per unit of complexity. Fee rates are - // valid as soon as fork introducing dynamic fees activates. - // Fee rates will be then updated by the dynamic fees algo. - InitialFeeRate Dimensions `json:"initial-fee-rate"` - // MinFeeRate contains, per each fee dimension, the // minimal fee rate, i.e. the fee per unit of complexity, // enforced by the dynamic fees algo. MinFeeRate Dimensions `json:"minimal-fee-rate"` - // UpdateCoefficient contains, per each fee dimension, the + // UpdateDenominators contains, per each fee dimension, the // exponential update coefficient. Setting an entry to 0 makes // the corresponding fee rate constant. - UpdateCoefficient Dimensions `json:"update-coefficient"` + UpdateDenominators Dimensions `json:"update-denominator"` // BlockTargetComplexityRate contains, per each fee dimension, the // preferred block complexity that the dynamic fee algo @@ -34,16 +28,6 @@ type DynamicFeesConfig struct { func (c *DynamicFeesConfig) Validate() error { for i := Dimension(0); i < FeeDimensions; i++ { - // MinFeeRate can be zero, but that is a bit dangerous. If a fee rate ever becomes - // zero, the update mechanism will keep them to zero. - if c.InitialFeeRate[i] < c.MinFeeRate[i] { - return fmt.Errorf("dimension %d, initial fee rate %d smaller than minimal fee rate %d", - i, - c.InitialFeeRate[i], - c.MinFeeRate[i], - ) - } - if c.BlockTargetComplexityRate[i] > c.BlockMaxComplexity[i] { return fmt.Errorf("dimension %d, block target complexity rate %d larger than block max complexity rate %d", i, @@ -51,12 +35,6 @@ func (c *DynamicFeesConfig) Validate() error { c.BlockMaxComplexity[i], ) } - - // The update algorithm normalizes complexity delta by [BlockTargetComplexityRate]. - // So we enforce [BlockTargetComplexityRate] to be non-zero. - if c.BlockTargetComplexityRate[i] == 0 { - return fmt.Errorf("dimension %d, block target complexity rate set to zero", i) - } } return nil diff --git a/vms/components/fees/manager.go b/vms/components/fees/manager.go index f8a9cba1cdb9..717ca768d3aa 100644 --- a/vms/components/fees/manager.go +++ b/vms/components/fees/manager.go @@ -6,20 +6,16 @@ package fees import ( "fmt" "math" + "math/big" safemath "github.com/ava-labs/avalanchego/utils/math" ) -// the update fee algorithm has a UpdateCoefficient, normalized to [CoeffDenom] -const CoeffDenom = uint64(20) - type Manager struct { // Avax denominated fee rates, i.e. fees per unit of complexity. feeRates Dimensions - // cumulatedComplexity helps aggregating the units of complexity consumed - // by a block so that we can verify it's not too big/build it properly. - cumulatedComplexity Dimensions + currentExcessComplexity Dimensions } func NewManager(feeRate Dimensions) *Manager { @@ -28,12 +24,55 @@ func NewManager(feeRate Dimensions) *Manager { } } +func NewUpdatedManager( + feesConfig DynamicFeesConfig, + excessComplexity Dimensions, + parentBlkTime, childBlkTime int64, +) (*Manager, error) { + res := &Manager{ + currentExcessComplexity: excessComplexity, + } + + targetBlkComplexity, err := TargetBlockComplexity(feesConfig, parentBlkTime, childBlkTime) + if err != nil { + return nil, fmt.Errorf("failed calculating target block complexity: %w", err) + } + for i := Dimension(0); i < FeeDimensions; i++ { + if excessComplexity[i] > targetBlkComplexity[i] { + excessComplexity[i] -= targetBlkComplexity[i] + } else { + excessComplexity[i] = 0 + } + + res.feeRates[i] = fakeExponential(feesConfig.MinFeeRate[i], excessComplexity[i], feesConfig.UpdateDenominators[i]) + } + return res, nil +} + +func TargetBlockComplexity(feesConfig DynamicFeesConfig, parentBlkTime, childBlkTime int64) (Dimensions, error) { + res := Empty + + if childBlkTime < parentBlkTime { + return Empty, fmt.Errorf("unexpected block times, parentBlkTim %v, childBlkTime %v", parentBlkTime, childBlkTime) + } + + elapsedTime := uint64(childBlkTime - parentBlkTime) + for i := Dimension(0); i < FeeDimensions; i++ { + targetComplexity, over := safemath.Mul64(feesConfig.BlockTargetComplexityRate[i], elapsedTime) + if over != nil { + targetComplexity = math.MaxUint64 + } + res[i] = targetComplexity + } + return res, nil +} + func (m *Manager) GetFeeRates() Dimensions { return m.feeRates } -func (m *Manager) GetCumulatedComplexity() Dimensions { - return m.cumulatedComplexity +func (m *Manager) GetCurrentExcessComplexity() Dimensions { + return m.currentExcessComplexity } // CalculateFee must be a stateless method @@ -59,7 +98,7 @@ func (m *Manager) CalculateFee(units Dimensions) (uint64, error) { func (m *Manager) CumulateComplexity(units, bounds Dimensions) (bool, Dimension) { // Ensure we can consume (don't want partial update of values) for i := Dimension(0); i < FeeDimensions; i++ { - consumed, err := safemath.Add64(m.cumulatedComplexity[i], units[i]) + consumed, err := safemath.Add64(m.currentExcessComplexity[i], units[i]) if err != nil { return true, i } @@ -70,11 +109,11 @@ func (m *Manager) CumulateComplexity(units, bounds Dimensions) (bool, Dimension) // Commit to consumption for i := Dimension(0); i < FeeDimensions; i++ { - consumed, err := safemath.Add64(m.cumulatedComplexity[i], units[i]) + consumed, err := safemath.Add64(m.currentExcessComplexity[i], units[i]) if err != nil { return true, i } - m.cumulatedComplexity[i] = consumed + m.currentExcessComplexity[i] = consumed } return false, 0 } @@ -84,173 +123,37 @@ func (m *Manager) CumulateComplexity(units, bounds Dimensions) (bool, Dimension) func (m *Manager) RemoveComplexity(unitsToRm Dimensions) error { var revertedUnits Dimensions for i := Dimension(0); i < FeeDimensions; i++ { - prev, err := safemath.Sub(m.cumulatedComplexity[i], unitsToRm[i]) + prev, err := safemath.Sub(m.currentExcessComplexity[i], unitsToRm[i]) if err != nil { return fmt.Errorf("%w: dimension %d", err, i) } revertedUnits[i] = prev } - m.cumulatedComplexity = revertedUnits + m.currentExcessComplexity = revertedUnits return nil } -// UpdateFeeRates calculates next fee rates. -// We update the fee rate with the formula: -// -// feeRate_{t+1} = Max(feeRate_t * exp(k*delta), minFeeRate) -// -// where -// -// delta == (parentComplexity - targetBlkComplexity)/targetBlkComplexity -// -// and [targetBlkComplexity] is the target complexity expected in the elapsed time. -// We update the fee rate trying to guarantee the following stability property: -// -// feeRate(delta) * feeRate(-delta) = 1 -// -// so that fee rates won't change much when block complexity wiggles around target complexity -func (m *Manager) UpdateFeeRates( - feesConfig DynamicFeesConfig, - parentBlkComplexity Dimensions, - parentBlkTime, childBlkTime int64, -) error { - if childBlkTime < parentBlkTime { - return fmt.Errorf("unexpected block times, parentBlkTim %v, childBlkTime %v", parentBlkTime, childBlkTime) - } - - elapsedTime := uint64(childBlkTime - parentBlkTime) - for i := Dimension(0); i < FeeDimensions; i++ { - targetBlkComplexity := targetComplexity( - feesConfig.BlockTargetComplexityRate[i], - elapsedTime, - feesConfig.BlockMaxComplexity[i], - ) - - factorNum, factorDenom := updateFactor( - feesConfig.UpdateCoefficient[i], - parentBlkComplexity[i], - targetBlkComplexity, - ) - nextFeeRates, over := safemath.Mul64(m.feeRates[i], factorNum) - if over != nil { - nextFeeRates = math.MaxUint64 - } - nextFeeRates /= factorDenom - - nextFeeRates = max(nextFeeRates, feesConfig.MinFeeRate[i]) - m.feeRates[i] = nextFeeRates - } - return nil -} - -func targetComplexity(targetComplexityRate, elapsedTime, maxBlockComplexity uint64) uint64 { - // parent and child block may have the same timestamp. In this case targetComplexity will match targetComplexityRate - elapsedTime = max(1, elapsedTime) - targetComplexity, over := safemath.Mul64(targetComplexityRate, elapsedTime) - if over != nil { - targetComplexity = maxBlockComplexity - } - - // regardless how low network load has been, we won't allow - // blocks larger than max block complexity - targetComplexity = min(targetComplexity, maxBlockComplexity) - return targetComplexity -} - -// updateFactor uses the following piece-wise approximation for the exponential function: -// -// if B > T --> exp{k * (B-T)/T} ≈≈ Approx(k,B,T) -// if B < T --> exp{k * (B-T)/T} ≈≈ 1/ Approx(k,B,T) -// -// Note that the approximation guarantees stability, since -// -// factor(k, B=T+X, T)*factor(k, B=T-X, T) == 1 -// -// We express the result with the pair (numerator, denominator) -// to increase precision with small deltas -func updateFactor(k, b, t uint64) (uint64, uint64) { - if b == t { - return 1, 1 // complexity matches target, nothing to update - } - - var ( - increaseFee bool - delta uint64 - ) - - if t < b { - increaseFee = true - delta = b - t - } else { - increaseFee = false - delta = t - b - } - - n, over := safemath.Mul64(k, delta) - if over != nil { - n = math.MaxUint64 - } - d, over := safemath.Mul64(CoeffDenom, t) - if over != nil { - d = math.MaxUint64 - } - - p, q := expPiecewiseApproximation(n, d) - if increaseFee { - return p, q - } - return q, p -} - -// piecewise approximation data. exp(x) ≈≈ m_i * x ± q_i in [i,i+1] -func expPiecewiseApproximation(a, b uint64) (uint64, uint64) { // exported to appease linter. +// fakeExponential approximates factor * e ** (numerator / denominator) using +// Taylor expansion. +func fakeExponential(f, n, d uint64) uint64 { var ( - m, q uint64 - sign bool + factor = new(big.Int).SetUint64(f) + numerator = new(big.Int).SetUint64(n) + denominator = new(big.Int).SetUint64(d) + output = new(big.Int) + accum = new(big.Int).Mul(factor, denominator) ) + for i := 1; accum.Sign() > 0; i++ { + output.Add(output, accum) - switch v := a / b; { - case v < 1: - m, q, sign = 2, 1, true - case v < 2: - m, q, sign = 5, 2, false - case v < 3: - m, q, sign = 13, 18, false - case v < 4: - m, q, sign = 35, 84, false - case v < 5: - m, q, sign = 94, 321, false - case v < 6: - m, q, sign = 256, 1131, false - case v < 7: - m, q, sign = 694, 3760, false - case v < 8: - m, q, sign = 1885, 12098, false - case v < 9: - m, q, sign = 5123, 38003, false - default: - m, q, sign = 13924, 117212, false - } - - // m(A/B) - q == (m*A-q*B)/B - n1, over := safemath.Mul64(m, a) - if over != nil { - return math.MaxUint64, b - } - n2, over := safemath.Mul64(q, b) - if over != nil { - return math.MaxUint64, b + accum.Mul(accum, numerator) + accum.Div(accum, denominator) + accum.Div(accum, big.NewInt(int64(i))) } - - var n uint64 - if !sign { - n = n1 - n2 - } else { - n, over = safemath.Add64(n1, n2) - if over != nil { - return math.MaxUint64, b - } + output = output.Div(output, denominator) + if !output.IsUint64() { + return math.MaxUint64 } - return n, b + return output.Uint64() } diff --git a/vms/components/fees/manager_test.go b/vms/components/fees/manager_test.go index 922183102f93..56e89901dfa2 100644 --- a/vms/components/fees/manager_test.go +++ b/vms/components/fees/manager_test.go @@ -5,7 +5,6 @@ package fees import ( "fmt" - "math" "testing" "time" @@ -20,7 +19,7 @@ func TestUpdateFeeRates(t *testing.T) { var ( feesCfg = DynamicFeesConfig{ MinFeeRate: Dimensions{1, 1, 1, 1}, - UpdateCoefficient: Dimensions{1, 2, 5, 10}, + UpdateDenominators: Dimensions{100, 200, 500, 1_000}, BlockMaxComplexity: Dimensions{100, 100, 100, 100}, BlockTargetComplexityRate: Dimensions{25, 25, 25, 25}, } @@ -32,91 +31,73 @@ func TestUpdateFeeRates(t *testing.T) { childBlkTime = parentBlkTime.Add(elapsedTime) ) - m := &Manager{ - feeRates: parentFeeRate, - } - - require.NoError(m.UpdateFeeRates( + m, err := NewUpdatedManager( feesCfg, parentComplexity, parentBlkTime.Unix(), childBlkTime.Unix(), - )) + ) + require.NoError(err) // Bandwidth complexity are above target, fee rate is pushed up - require.Equal(uint64(13), m.feeRates[Bandwidth]) + require.Equal(uint64(420), m.feeRates[Bandwidth]) // UTXORead complexity is at target, fee rate does not change require.Equal(parentFeeRate[UTXORead], m.feeRates[UTXORead]) // UTXOWrite complexity is below target, fee rate is pushed down - require.Equal(uint64(90), m.feeRates[UTXOWrite]) + require.Equal(uint64(33), m.feeRates[UTXOWrite]) // Compute complexoty is below target, fee rate is pushed down - require.Equal(uint64(125), m.feeRates[Compute]) + require.Equal(uint64(1), m.feeRates[Compute]) } -func TestUpdateFeeRatesStability(t *testing.T) { - // The advantage of using an exponential fee update scheme - // (vs e.g. the EIP-1559 scheme we use in the C-chain) is that - // it is more stable against dithering. - // We prove here that if complexity oscillates around the target - // fee rates are unchanged (discounting for some numerical errors) - - require := require.New(t) - - var ( - feesCfg = DynamicFeesConfig{ - MinFeeRate: Dimensions{0, 0, 0, 0}, - UpdateCoefficient: Dimensions{2, 4, 5, 10}, - BlockMaxComplexity: Dimensions{100_000, 100_000, 100_000, 100_000}, - BlockTargetComplexityRate: Dimensions{200, 60, 80, 600}, - } - initialFeeRate = Dimensions{ - 60 * units.NanoAvax, - 8 * units.NanoAvax, - 10 * units.NanoAvax, - 35 * units.NanoAvax, - } - - elapsedTime = time.Second - parentComplexity = Dimensions{50, 45, 70, 500} // less than target complexity rate * elapsedTime - childComplexity = Dimensions{350, 75, 90, 700} // more than target complexity rate * elapsedTime - - parentBlkTime = time.Now().Truncate(time.Second) - childBlkTime = parentBlkTime.Add(elapsedTime) - granChildBlkTime = childBlkTime.Add(elapsedTime) - ) - - // step1: parent complexity is below target. Fee rates will decrease - m1 := &Manager{feeRates: initialFeeRate} - require.NoError(m1.UpdateFeeRates( - feesCfg, - parentComplexity, - parentBlkTime.Unix(), - childBlkTime.Unix(), - )) - - require.Less(m1.feeRates[Bandwidth], initialFeeRate[Bandwidth]) - require.Less(m1.feeRates[UTXORead], initialFeeRate[UTXORead]) - require.Less(m1.feeRates[UTXOWrite], initialFeeRate[UTXOWrite]) - require.Less(m1.feeRates[Compute], initialFeeRate[Compute]) - - // step2: child complexity goes above target, so that average complexity is at target. - // Fee rates go back to the original value - m2 := &Manager{feeRates: m1.feeRates} - require.NoError(m2.UpdateFeeRates( - feesCfg, - childComplexity, - childBlkTime.Unix(), - granChildBlkTime.Unix(), - )) - - require.LessOrEqual(initialFeeRate[Bandwidth]-m2.feeRates[Bandwidth], uint64(1)) - require.LessOrEqual(initialFeeRate[UTXORead]-m2.feeRates[UTXORead], uint64(1)) - require.LessOrEqual(initialFeeRate[UTXOWrite]-m2.feeRates[UTXOWrite], uint64(1)) - require.LessOrEqual(initialFeeRate[Compute]-m2.feeRates[Compute], uint64(1)) -} +// func TestFeeUpdateFactor(t *testing.T) { +// tests := []struct { +// coeff uint64 +// parentBlkComplexity uint64 +// targetBlkComplexity uint64 +// want uint64 +// wantIncreaseFee bool +// }{ +// // parentBlkComplexity == targetBlkComplexity gives factor 1, no matter what coeff is +// {1, 250, 250, 1, false}, +// {math.MaxUint64, 250, 250, 1, false}, + +// // parentBlkComplexity > targetBlkComplexity +// {1, 101, 100, 1, true}, // should be 1.0005 +// {1, 110, 100, 1, true}, // should be 1.005 +// {1, 200, 100, 1, true}, // should be 1.05 +// {1, 1_100, 100, 1, true}, // should be 1.648 +// {1, 2_100, 100, 2, true}, // should be 2,718 +// {1, 3_100, 100, 4, true}, // should be 4,48 +// {1, 4_100, 100, 7, true}, // should be 7,39 +// {1, 7_100, 100, 33, true}, // should be 33,12 +// {1, 8_100, 100, 54, true}, // should be 54,6 +// {1, 10_100, 100, 148, true}, // should be 148,4 + +// // parentBlkComplexity < targetBlkComplexity +// {1, 100, 101, 1, false}, +// {1, 100, 110, 1, false}, +// {1, 100, 200, 1, false}, +// {1, 100, 1_100, 1, false}, +// {1, 100, 2_100, 2, false}, +// {1, 100, 3_100, 4, false}, +// {1, 100, 4_100, 7, false}, +// {1, 100, 7_100, 33, false}, +// {1, 100, 8_100, 54, false}, +// {1, 100, 10_100, 148, false}, +// } +// for _, tt := range tests { +// haveFactor, haveIncreaseFee := updateFactor( +// tt.coeff, +// tt.parentBlkComplexity, +// tt.targetBlkComplexity, +// ) +// require.Equal(t, tt.want, haveFactor) +// require.Equal(t, tt.wantIncreaseFee, haveIncreaseFee) +// } +// } func TestPChainFeeRateIncreaseDueToPeak(t *testing.T) { // Complexity values comes from the mainnet historical peak as measured @@ -132,11 +113,11 @@ func TestPChainFeeRateIncreaseDueToPeak(t *testing.T) { 10 * units.NanoAvax, 35 * units.NanoAvax, }, - UpdateCoefficient: Dimensions{ // over CoeffDenom - 3, + UpdateDenominators: Dimensions{ // over CoeffDenom + 1, + 1, 1, 1, - 2, }, BlockTargetComplexityRate: Dimensions{ 2500, @@ -202,12 +183,13 @@ func TestPChainFeeRateIncreaseDueToPeak(t *testing.T) { for i := 1; i < len(blockComplexities); i++ { parentBlkData := blockComplexities[i-1] childBlkData := blockComplexities[i] - require.NoError(m.UpdateFeeRates( + m, err := NewUpdatedManager( feesCfg, parentBlkData.complexity, parentBlkData.blkTime, childBlkData.blkTime, - )) + ) + require.NoError(err) // check that fee rates are strictly above minimal require.False( @@ -234,12 +216,13 @@ func TestPChainFeeRateIncreaseDueToPeak(t *testing.T) { parentBlkTime := time.Now().Truncate(time.Second) childBlkTime := parentBlkTime.Add(elapsedTime) - require.NoError(m.UpdateFeeRates( + m, err := NewUpdatedManager( feesCfg, offPeakBlkComplexity, parentBlkTime.Unix(), childBlkTime.Unix(), - )) + ) + require.NoError(err) // check that fee rates decrease off peak require.Less(m.feeRates[Bandwidth], peakFeeRate[Bandwidth]) @@ -247,45 +230,3 @@ func TestPChainFeeRateIncreaseDueToPeak(t *testing.T) { require.LessOrEqual(m.feeRates[UTXOWrite], peakFeeRate[UTXOWrite]) require.Less(m.feeRates[Compute], peakFeeRate[Compute]) } - -func TestFeeUpdateFactor(t *testing.T) { - tests := []struct { - coeff uint64 - parentBlkComplexity uint64 - targetBlkComplexity uint64 - wantNum uint64 - wantDenom uint64 - }{ - // parentBlkComplexity == targetBlkComplexity gives factor 1, no matter what coeff is - {1, 250, 250, 1, 1}, - {math.MaxUint64, 250, 250, 1, 1}, - - // parentBlkComplexity > targetBlkComplexity - {1, 101, 100, 2_002, 2_000}, // should be 1.0005 - {1, 110, 100, 2_020, 2_000}, // should be 1.005 - {1, 200, 100, 2_200, 2_000}, // should be 1.05 - {1, 1_100, 100, 4_000, 2_000}, // should be 1.648 - {1, 2_100, 100, 6000, 2_000}, // should be 2,718 - {1, 3_100, 100, 11_000, 2_000}, // should be 4,48 - {1, 4_100, 100, 16_000, 2_000}, // should be 7,39 - {1, 7_100, 100, 77_000, 2_000}, // should be 33,12 - {1, 8_100, 100, 110_000, 2_000}, // should be 54,6 - {1, 10_100, 100, 298_000, 2_000}, // should be 148,4 - - // parentBlkComplexity < targetBlkComplexity - {1, 100, 101, 2_020, 2_022}, // should be 0,9995 - {1, 100, 110, 2_200, 2_220}, // should be 0,995 - {1, 100, 200, 4_000, 4_200}, // should be 0,975 - {1, 100, 1_100, 22_000, 24_000}, // should be 0,955 - {1, 100, 10_100, 202_000, 222_000}, // should be 0,952 - } - for _, tt := range tests { - haveFactor, haveIncreaseFee := updateFactor( - tt.coeff, - tt.parentBlkComplexity, - tt.targetBlkComplexity, - ) - require.Equal(t, tt.wantNum, haveFactor) - require.Equal(t, tt.wantDenom, haveIncreaseFee) - } -} diff --git a/vms/platformvm/block/builder/builder.go b/vms/platformvm/block/builder/builder.go index 364f72cf1a08..b51153fd10b0 100644 --- a/vms/platformvm/block/builder/builder.go +++ b/vms/platformvm/block/builder/builder.go @@ -350,6 +350,15 @@ func packBlockTxs( return nil, fmt.Errorf("failed picking fee calculator: %w", err) } + targetBlkComplexity, err := commonfees.TargetBlockComplexity(feeCfg, parentBlkTime.Unix(), timestamp.Unix()) + if err != nil { + return nil, fmt.Errorf("failed calculating target block complexity: %w", err) + } + targetExcessComplexity, err := commonfees.Add(targetBlkComplexity, feeCalculator.GetCurrentExcessComplexity()) + if err != nil { + return nil, fmt.Errorf("failed calculating target excess complexity: %w", err) + } + for { tx, exists := mempool.Peek() if !exists { @@ -361,7 +370,7 @@ 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 complexity targetSizeReached := (!isEActivated && txSize > remainingSize) || - (isEActivated && !commonfees.Compare(feeCalculator.GetCumulatedComplexity(), feeCfg.BlockTargetComplexityRate)) + (isEActivated && !commonfees.Compare(feeCalculator.GetCurrentExcessComplexity(), targetExcessComplexity)) if targetSizeReached { break } diff --git a/vms/platformvm/block/executor/acceptor.go b/vms/platformvm/block/executor/acceptor.go index 0cca4435f257..28702cb1c988 100644 --- a/vms/platformvm/block/executor/acceptor.go +++ b/vms/platformvm/block/executor/acceptor.go @@ -79,7 +79,7 @@ func (a *acceptor) ApricotAtomicBlock(b *block.ApricotAtomicBlock) error { return fmt.Errorf("%w %s", errMissingBlockState, blkID) } - a.metrics.SetBlockComplexity(blkState.blockComplexity) + a.metrics.SetExcessComplexity(blkState.excessComplexity) // Update the state to reflect the changes made in [onAcceptState]. if err := blkState.onAcceptState.Apply(a.state); err != nil { @@ -138,7 +138,7 @@ func (a *acceptor) optionBlock(b block.Block, blockType string) error { return err } - a.metrics.SetBlockComplexity(parentState.blockComplexity) + a.metrics.SetExcessComplexity(parentState.excessComplexity) if err := a.commonAccept(b); err != nil { return err @@ -156,7 +156,7 @@ func (a *acceptor) optionBlock(b block.Block, blockType string) error { } // we set option complexity at its parent block's one. - a.metrics.SetBlockComplexity(parentState.blockComplexity) + a.metrics.SetExcessComplexity(parentState.excessComplexity) if err := blkState.onAcceptState.Apply(a.state); err != nil { return err @@ -236,7 +236,7 @@ func (a *acceptor) standardBlock(b block.Block, blockType string) error { return fmt.Errorf("%w %s", errMissingBlockState, blkID) } - a.metrics.SetBlockComplexity(blkState.blockComplexity) + a.metrics.SetExcessComplexity(blkState.excessComplexity) // Update the state to reflect the changes made in [onAcceptState]. if err := blkState.onAcceptState.Apply(a.state); err != nil { diff --git a/vms/platformvm/block/executor/block_state.go b/vms/platformvm/block/executor/block_state.go index f0e3989a7856..8e38b4da2ce4 100644 --- a/vms/platformvm/block/executor/block_state.go +++ b/vms/platformvm/block/executor/block_state.go @@ -30,8 +30,8 @@ type blockState struct { onAcceptState state.Diff onAcceptFunc func() - inputs set.Set[ids.ID] - timestamp time.Time - blockComplexity commonfees.Dimensions - atomicRequests map[ids.ID]*atomic.Requests + inputs set.Set[ids.ID] + timestamp time.Time + excessComplexity commonfees.Dimensions + atomicRequests map[ids.ID]*atomic.Requests } diff --git a/vms/platformvm/block/executor/standard_block_test.go b/vms/platformvm/block/executor/standard_block_test.go index 31ac99e2ccdb..259f6ab311c3 100644 --- a/vms/platformvm/block/executor/standard_block_test.go +++ b/vms/platformvm/block/executor/standard_block_test.go @@ -57,7 +57,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().GetLastBlockComplexity().Return(commonfees.Empty, nil).AnyTimes() + onParentAccept.EXPECT().GetExcessComplexity().Return(commonfees.Empty, nil).AnyTimes() // wrong height apricotChildBlk, err := block.NewApricotStandardBlock( @@ -151,7 +151,7 @@ func TestBanffStandardBlockTimeVerification(t *testing.T) { } utxoID := utxo.InputID() onParentAccept.EXPECT().GetUTXO(utxoID).Return(utxo, nil).AnyTimes() - onParentAccept.EXPECT().GetLastBlockComplexity().Return(commonfees.Empty, nil).AnyTimes() + onParentAccept.EXPECT().GetExcessComplexity().Return(commonfees.Empty, 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 f9979d8d0bec..5c52908838b5 100644 --- a/vms/platformvm/block/executor/verifier.go +++ b/vms/platformvm/block/executor/verifier.go @@ -250,10 +250,10 @@ func (v *verifier) ApricotAtomicBlock(b *block.ApricotAtomicBlock) error { onAcceptState: atomicExecutor.OnAccept, - inputs: atomicExecutor.Inputs, - timestamp: atomicExecutor.OnAccept.GetTimestamp(), - blockComplexity: commonfees.Empty, - atomicRequests: atomicExecutor.AtomicRequests, + inputs: atomicExecutor.Inputs, + timestamp: atomicExecutor.OnAccept.GetTimestamp(), + excessComplexity: commonfees.Empty, + atomicRequests: atomicExecutor.AtomicRequests, } return nil } @@ -439,9 +439,9 @@ func (v *verifier) proposalBlock( // It is safe to use [b.onAbortState] here because the timestamp will // never be modified by an Apricot Abort block and the timestamp will // always be the same as the Banff Proposal Block. - timestamp: onAbortState.GetTimestamp(), - blockComplexity: feeCalculator.GetCumulatedComplexity(), - atomicRequests: atomicRequests, + timestamp: onAbortState.GetTimestamp(), + excessComplexity: feeCalculator.GetCurrentExcessComplexity(), + atomicRequests: atomicRequests, } return nil } @@ -466,10 +466,10 @@ func (v *verifier) standardBlock( onAcceptState: onAcceptState, onAcceptFunc: onAcceptFunc, - timestamp: onAcceptState.GetTimestamp(), - blockComplexity: feeCalculator.GetCumulatedComplexity(), - inputs: inputs, - atomicRequests: atomicRequests, + timestamp: onAcceptState.GetTimestamp(), + excessComplexity: feeCalculator.GetCurrentExcessComplexity(), + inputs: inputs, + atomicRequests: atomicRequests, } return nil } @@ -534,7 +534,7 @@ func (v *verifier) processStandardTxs( } if v.txExecutorBackend.Config.UpgradeConfig.IsEActivated(state.GetTimestamp()) { - state.SetLastBlockComplexity(feeCalculator.GetCumulatedComplexity()) + state.SetExcessComplexity(feeCalculator.GetCurrentExcessComplexity()) } if numFuncs := len(funcs); numFuncs == 1 { diff --git a/vms/platformvm/block/executor/verifier_test.go b/vms/platformvm/block/executor/verifier_test.go index e66c63ee8e52..3baa32c5f469 100644 --- a/vms/platformvm/block/executor/verifier_test.go +++ b/vms/platformvm/block/executor/verifier_test.go @@ -407,9 +407,9 @@ func TestStandardBlockComplexity(t *testing.T) { require.True(found) if dynamicFeesActive { - require.NotEqual(commonfees.Empty, blkState.blockComplexity) + require.NotEqual(commonfees.Empty, blkState.excessComplexity) } else { - require.Equal(commonfees.Empty, blkState.blockComplexity) + require.Equal(commonfees.Empty, blkState.excessComplexity) } }) } diff --git a/vms/platformvm/metrics/metrics.go b/vms/platformvm/metrics/metrics.go index 45d3b45b1b74..ca10df74618b 100644 --- a/vms/platformvm/metrics/metrics.go +++ b/vms/platformvm/metrics/metrics.go @@ -41,8 +41,8 @@ type Metrics interface { // Mark when this node will unstake from a subnet. SetTimeUntilSubnetUnstake(subnetID ids.ID, timeUntilUnstake time.Duration) - // Mark cumulated complexity of the latest accepted block - SetBlockComplexity(commonfees.Dimensions) + // Mark cumulated excess complexity + SetExcessComplexity(commonfees.Dimensions) } func New( @@ -198,7 +198,7 @@ func (m *metrics) SetTimeUntilSubnetUnstake(subnetID ids.ID, timeUntilUnstake ti m.timeUntilSubnetUnstake.WithLabelValues(subnetID.String()).Set(float64(timeUntilUnstake)) } -func (m *metrics) SetBlockComplexity(units commonfees.Dimensions) { +func (m *metrics) SetExcessComplexity(units commonfees.Dimensions) { m.blockBandwitdhComplexity.Set(float64(units[commonfees.Bandwidth])) m.blockUTXOsReadComplexity.Set(float64(units[commonfees.UTXORead])) m.blockUTXOsWriteComplexity.Set(float64(units[commonfees.UTXOWrite])) diff --git a/vms/platformvm/metrics/no_op.go b/vms/platformvm/metrics/no_op.go index 22cc5defc8ad..71bf872a953e 100644 --- a/vms/platformvm/metrics/no_op.go +++ b/vms/platformvm/metrics/no_op.go @@ -53,4 +53,4 @@ func (noopMetrics) SetSubnetPercentConnected(ids.ID, float64) {} func (noopMetrics) SetPercentConnected(float64) {} -func (noopMetrics) SetBlockComplexity(commonfees.Dimensions) {} +func (noopMetrics) SetExcessComplexity(commonfees.Dimensions) {} diff --git a/vms/platformvm/state/block_helpers.go b/vms/platformvm/state/block_helpers.go index a9e35c5aa12d..b39e658af551 100644 --- a/vms/platformvm/state/block_helpers.go +++ b/vms/platformvm/state/block_helpers.go @@ -99,27 +99,29 @@ func PickFeeCalculator(cfg *config.Config, state Chain, parentBlkTime time.Time) func updatedFeeManager(upgrades upgrade.Config, state Chain, parentBlkTime time.Time) (*commonfees.Manager, error) { var ( - isEActive = upgrades.IsEActivated(parentBlkTime) - feeCfg = fee.GetDynamicConfig(isEActive) + isEActive = upgrades.IsEActivated(parentBlkTime) + feeCfg = fee.GetDynamicConfig(isEActive) + feeManager *commonfees.Manager ) - parentBlkComplexity, err := state.GetLastBlockComplexity() - if err != nil { - return nil, fmt.Errorf("failed retrieving last block complexity: %w", err) - } - childBlkTime := state.GetTimestamp() - - feeManager := commonfees.NewManager(commonfees.Empty) // Fee rate non needed anymore if isEActive { - if err := feeManager.UpdateFeeRates( + excessComplexity, err := state.GetExcessComplexity() + if err != nil { + return nil, fmt.Errorf("failed retrieving excess complexity: %w", err) + } + childBlkTime := state.GetTimestamp() + + feeManager, err = commonfees.NewUpdatedManager( feeCfg, - parentBlkComplexity, + excessComplexity, parentBlkTime.Unix(), childBlkTime.Unix(), - ); err != nil { + ) + if err != nil { return nil, fmt.Errorf("failed updating fee rates, %w", err) } + } else { + feeManager = commonfees.NewManager(commonfees.Empty) } - return feeManager, nil } diff --git a/vms/platformvm/state/diff.go b/vms/platformvm/state/diff.go index 15258de8f674..a0d86be6a7df 100644 --- a/vms/platformvm/state/diff.go +++ b/vms/platformvm/state/diff.go @@ -37,7 +37,7 @@ type diff struct { timestamp time.Time - lastBlkComplexity *commonfees.Dimensions + excessComplexity *commonfees.Dimensions // Subnet ID --> supply of native asset of the subnet currentSupply map[ids.ID]uint64 @@ -93,29 +93,29 @@ func NewDiffOn(parentState Chain) (Diff, error) { }) } -func (d *diff) GetLastBlockComplexity() (commonfees.Dimensions, error) { - if d.lastBlkComplexity == nil { +func (d *diff) GetExcessComplexity() (commonfees.Dimensions, error) { + if d.excessComplexity == nil { parentState, ok := d.stateVersions.GetState(d.parentID) if !ok { return commonfees.Empty, fmt.Errorf("%w: %s", ErrMissingParentState, d.parentID) } - parentLastComplexity, err := parentState.GetLastBlockComplexity() + parentExcessComplexity, err := parentState.GetExcessComplexity() if err != nil { return commonfees.Empty, err } - d.lastBlkComplexity = new(commonfees.Dimensions) - *d.lastBlkComplexity = parentLastComplexity + d.excessComplexity = new(commonfees.Dimensions) + *d.excessComplexity = parentExcessComplexity } - return *d.lastBlkComplexity, nil + return *d.excessComplexity, nil } -func (d *diff) SetLastBlockComplexity(complexity commonfees.Dimensions) { - if d.lastBlkComplexity == nil { - d.lastBlkComplexity = new(commonfees.Dimensions) +func (d *diff) SetExcessComplexity(complexity commonfees.Dimensions) { + if d.excessComplexity == nil { + d.excessComplexity = new(commonfees.Dimensions) } - *d.lastBlkComplexity = complexity + *d.excessComplexity = complexity } func (d *diff) GetTimestamp() time.Time { @@ -430,8 +430,8 @@ func (d *diff) DeleteUTXO(utxoID ids.ID) { func (d *diff) Apply(baseState Chain) error { baseState.SetTimestamp(d.timestamp) - if d.lastBlkComplexity != nil { - baseState.SetLastBlockComplexity(*d.lastBlkComplexity) + if d.excessComplexity != nil { + baseState.SetExcessComplexity(*d.excessComplexity) } 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 ff5f342ba42a..3a3b39f450b3 100644 --- a/vms/platformvm/state/mock_state.go +++ b/vms/platformvm/state/mock_state.go @@ -258,19 +258,19 @@ func (mr *MockChainMockRecorder) GetDelegateeReward(arg0, arg1 any) *gomock.Call return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDelegateeReward", reflect.TypeOf((*MockChain)(nil).GetDelegateeReward), arg0, arg1) } -// GetLastBlockComplexity mocks base method. -func (m *MockChain) GetLastBlockComplexity() (fees.Dimensions, error) { +// GetExcessComplexity mocks base method. +func (m *MockChain) GetExcessComplexity() (fees.Dimensions, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetLastBlockComplexity") + ret := m.ctrl.Call(m, "GetExcessComplexity") ret0, _ := ret[0].(fees.Dimensions) ret1, _ := ret[1].(error) return ret0, ret1 } -// GetLastBlockComplexity indicates an expected call of GetLastBlockComplexity. -func (mr *MockChainMockRecorder) GetLastBlockComplexity() *gomock.Call { +// GetExcessComplexity indicates an expected call of GetExcessComplexity. +func (mr *MockChainMockRecorder) GetExcessComplexity() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLastBlockComplexity", reflect.TypeOf((*MockChain)(nil).GetLastBlockComplexity)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetExcessComplexity", reflect.TypeOf((*MockChain)(nil).GetExcessComplexity)) } // GetPendingDelegatorIterator mocks base method. @@ -467,16 +467,16 @@ func (mr *MockChainMockRecorder) SetDelegateeReward(arg0, arg1, arg2 any) *gomoc return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetDelegateeReward", reflect.TypeOf((*MockChain)(nil).SetDelegateeReward), arg0, arg1, arg2) } -// SetLastBlockComplexity mocks base method. -func (m *MockChain) SetLastBlockComplexity(arg0 fees.Dimensions) { +// SetExcessComplexity mocks base method. +func (m *MockChain) SetExcessComplexity(arg0 fees.Dimensions) { m.ctrl.T.Helper() - m.ctrl.Call(m, "SetLastBlockComplexity", arg0) + m.ctrl.Call(m, "SetExcessComplexity", arg0) } -// SetLastBlockComplexity indicates an expected call of SetLastBlockComplexity. -func (mr *MockChainMockRecorder) SetLastBlockComplexity(arg0 any) *gomock.Call { +// SetExcessComplexity indicates an expected call of SetExcessComplexity. +func (mr *MockChainMockRecorder) SetExcessComplexity(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetLastBlockComplexity", reflect.TypeOf((*MockChain)(nil).SetLastBlockComplexity), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetExcessComplexity", reflect.TypeOf((*MockChain)(nil).SetExcessComplexity), arg0) } // SetSubnetOwner mocks base method. @@ -747,19 +747,19 @@ func (mr *MockDiffMockRecorder) GetDelegateeReward(arg0, arg1 any) *gomock.Call return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDelegateeReward", reflect.TypeOf((*MockDiff)(nil).GetDelegateeReward), arg0, arg1) } -// GetLastBlockComplexity mocks base method. -func (m *MockDiff) GetLastBlockComplexity() (fees.Dimensions, error) { +// GetExcessComplexity mocks base method. +func (m *MockDiff) GetExcessComplexity() (fees.Dimensions, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetLastBlockComplexity") + ret := m.ctrl.Call(m, "GetExcessComplexity") ret0, _ := ret[0].(fees.Dimensions) ret1, _ := ret[1].(error) return ret0, ret1 } -// GetLastBlockComplexity indicates an expected call of GetLastBlockComplexity. -func (mr *MockDiffMockRecorder) GetLastBlockComplexity() *gomock.Call { +// GetExcessComplexity indicates an expected call of GetExcessComplexity. +func (mr *MockDiffMockRecorder) GetExcessComplexity() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLastBlockComplexity", reflect.TypeOf((*MockDiff)(nil).GetLastBlockComplexity)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetExcessComplexity", reflect.TypeOf((*MockDiff)(nil).GetExcessComplexity)) } // GetPendingDelegatorIterator mocks base method. @@ -956,16 +956,16 @@ func (mr *MockDiffMockRecorder) SetDelegateeReward(arg0, arg1, arg2 any) *gomock return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetDelegateeReward", reflect.TypeOf((*MockDiff)(nil).SetDelegateeReward), arg0, arg1, arg2) } -// SetLastBlockComplexity mocks base method. -func (m *MockDiff) SetLastBlockComplexity(arg0 fees.Dimensions) { +// SetExcessComplexity mocks base method. +func (m *MockDiff) SetExcessComplexity(arg0 fees.Dimensions) { m.ctrl.T.Helper() - m.ctrl.Call(m, "SetLastBlockComplexity", arg0) + m.ctrl.Call(m, "SetExcessComplexity", arg0) } -// SetLastBlockComplexity indicates an expected call of SetLastBlockComplexity. -func (mr *MockDiffMockRecorder) SetLastBlockComplexity(arg0 any) *gomock.Call { +// SetExcessComplexity indicates an expected call of SetExcessComplexity. +func (mr *MockDiffMockRecorder) SetExcessComplexity(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetLastBlockComplexity", reflect.TypeOf((*MockDiff)(nil).SetLastBlockComplexity), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetExcessComplexity", reflect.TypeOf((*MockDiff)(nil).SetExcessComplexity), arg0) } // SetSubnetOwner mocks base method. @@ -1361,6 +1361,21 @@ func (mr *MockStateMockRecorder) GetDelegateeReward(arg0, arg1 any) *gomock.Call return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDelegateeReward", reflect.TypeOf((*MockState)(nil).GetDelegateeReward), arg0, arg1) } +// GetExcessComplexity mocks base method. +func (m *MockState) GetExcessComplexity() (fees.Dimensions, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetExcessComplexity") + ret0, _ := ret[0].(fees.Dimensions) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetExcessComplexity indicates an expected call of GetExcessComplexity. +func (mr *MockStateMockRecorder) GetExcessComplexity() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetExcessComplexity", reflect.TypeOf((*MockState)(nil).GetExcessComplexity)) +} + // GetLastAccepted mocks base method. func (m *MockState) GetLastAccepted() ids.ID { m.ctrl.T.Helper() @@ -1375,21 +1390,6 @@ func (mr *MockStateMockRecorder) GetLastAccepted() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLastAccepted", reflect.TypeOf((*MockState)(nil).GetLastAccepted)) } -// GetLastBlockComplexity mocks base method. -func (m *MockState) GetLastBlockComplexity() (fees.Dimensions, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetLastBlockComplexity") - ret0, _ := ret[0].(fees.Dimensions) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetLastBlockComplexity indicates an expected call of GetLastBlockComplexity. -func (mr *MockStateMockRecorder) GetLastBlockComplexity() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLastBlockComplexity", reflect.TypeOf((*MockState)(nil).GetLastBlockComplexity)) -} - // GetPendingDelegatorIterator mocks base method. func (m *MockState) GetPendingDelegatorIterator(arg0 ids.ID, arg1 ids.NodeID) (StakerIterator, error) { m.ctrl.T.Helper() @@ -1674,6 +1674,18 @@ func (mr *MockStateMockRecorder) SetDelegateeReward(arg0, arg1, arg2 any) *gomoc return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetDelegateeReward", reflect.TypeOf((*MockState)(nil).SetDelegateeReward), arg0, arg1, arg2) } +// SetExcessComplexity mocks base method. +func (m *MockState) SetExcessComplexity(arg0 fees.Dimensions) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetExcessComplexity", arg0) +} + +// SetExcessComplexity indicates an expected call of SetExcessComplexity. +func (mr *MockStateMockRecorder) SetExcessComplexity(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetExcessComplexity", reflect.TypeOf((*MockState)(nil).SetExcessComplexity), arg0) +} + // SetHeight mocks base method. func (m *MockState) SetHeight(arg0 uint64) { m.ctrl.T.Helper() @@ -1698,18 +1710,6 @@ func (mr *MockStateMockRecorder) SetLastAccepted(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetLastAccepted", reflect.TypeOf((*MockState)(nil).SetLastAccepted), arg0) } -// SetLastBlockComplexity mocks base method. -func (m *MockState) SetLastBlockComplexity(arg0 fees.Dimensions) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "SetLastBlockComplexity", arg0) -} - -// SetLastBlockComplexity indicates an expected call of SetLastBlockComplexity. -func (mr *MockStateMockRecorder) SetLastBlockComplexity(arg0 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetLastBlockComplexity", reflect.TypeOf((*MockState)(nil).SetLastBlockComplexity), arg0) -} - // SetSubnetOwner mocks base method. func (m *MockState) SetSubnetOwner(arg0 ids.ID, arg1 fx.Owner) { m.ctrl.T.Helper() diff --git a/vms/platformvm/state/state.go b/vms/platformvm/state/state.go index 133bb9e22ae6..ebf69f06eccb 100644 --- a/vms/platformvm/state/state.go +++ b/vms/platformvm/state/state.go @@ -81,14 +81,14 @@ var ( ChainPrefix = []byte("chain") SingletonPrefix = []byte("singleton") - TimestampKey = []byte("timestamp") - CurrentSupplyKey = []byte("current supply") - LastAcceptedKey = []byte("last accepted") - HeightsIndexedKey = []byte("heights indexed") - FeeRatesKey = []byte("fee rates") - LastBlkComplexityKey = []byte("last complexity") - InitializedKey = []byte("initialized") - BlocksReindexedKey = []byte("blocks reindexed") + TimestampKey = []byte("timestamp") + CurrentSupplyKey = []byte("current supply") + LastAcceptedKey = []byte("last accepted") + HeightsIndexedKey = []byte("heights indexed") + FeeRatesKey = []byte("fee rates") + ExcessComplexityKey = []byte("last complexity") + InitializedKey = []byte("initialized") + BlocksReindexedKey = []byte("blocks reindexed") ) // Chain collects all methods to manage the state of the chain for block @@ -99,8 +99,8 @@ type Chain interface { avax.UTXOGetter avax.UTXODeleter - GetLastBlockComplexity() (commonfees.Dimensions, error) - SetLastBlockComplexity(windows commonfees.Dimensions) + GetExcessComplexity() (commonfees.Dimensions, error) + SetExcessComplexity(commonfees.Dimensions) GetTimestamp() time.Time SetTimestamp(tm time.Time) @@ -361,7 +361,7 @@ type state struct { // The persisted fields represent the current database value timestamp, persistedTimestamp time.Time - lastBlkComplexity commonfees.Dimensions + excessComplexity commonfees.Dimensions currentSupply, persistedCurrentSupply uint64 // [lastAccepted] is the most recently accepted block. lastAccepted, persistedLastAccepted ids.ID @@ -1010,12 +1010,12 @@ func (s *state) GetStartTime(nodeID ids.NodeID, subnetID ids.ID) (time.Time, err return staker.StartTime, nil } -func (s *state) GetLastBlockComplexity() (commonfees.Dimensions, error) { - return s.lastBlkComplexity, nil +func (s *state) GetExcessComplexity() (commonfees.Dimensions, error) { + return s.excessComplexity, nil } -func (s *state) SetLastBlockComplexity(complexity commonfees.Dimensions) { - s.lastBlkComplexity = complexity +func (s *state) SetExcessComplexity(complexity commonfees.Dimensions) { + s.excessComplexity = complexity } func (s *state) GetTimestamp() time.Time { @@ -1308,9 +1308,9 @@ func (s *state) loadMetadata() error { s.persistedTimestamp = timestamp s.SetTimestamp(timestamp) - switch lastBlkComplexityBytes, err := s.singletonDB.Get(LastBlkComplexityKey); err { + switch excessComplexityBytes, err := s.singletonDB.Get(ExcessComplexityKey); err { case nil: - if err := s.lastBlkComplexity.FromBytes(lastBlkComplexityBytes); err != nil { + if err := s.excessComplexity.FromBytes(excessComplexityBytes); err != nil { return err } @@ -1318,7 +1318,7 @@ func (s *state) loadMetadata() error { // 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 - s.lastBlkComplexity = commonfees.Empty + s.excessComplexity = commonfees.Empty default: return err @@ -2301,8 +2301,8 @@ func (s *state) writeMetadata() error { s.persistedTimestamp = s.timestamp } - if err := s.singletonDB.Put(LastBlkComplexityKey, s.lastBlkComplexity.Bytes()); err != nil { - return fmt.Errorf("failed to write fee rates: %w", err) + if err := s.singletonDB.Put(ExcessComplexityKey, s.excessComplexity.Bytes()); err != nil { + return fmt.Errorf("failed to write excess complexity: %w", err) } if s.persistedCurrentSupply != s.currentSupply { if err := database.PutUInt64(s.singletonDB, CurrentSupplyKey, s.currentSupply); err != nil { diff --git a/vms/platformvm/txs/fee/calculator.go b/vms/platformvm/txs/fee/calculator.go index 9ba16a82bf0d..e56decb57caa 100644 --- a/vms/platformvm/txs/fee/calculator.go +++ b/vms/platformvm/txs/fee/calculator.go @@ -26,7 +26,11 @@ var ( errFailedComplexityCumulation = errors.New("failed cumulating complexity") ) -func NewStaticCalculator(config StaticConfig, upgradeTimes upgrade.Config, chainTime time.Time) *Calculator { +func NewStaticCalculator( + config StaticConfig, + upgradeTimes upgrade.Config, + chainTime time.Time, +) *Calculator { return &Calculator{ c: &calculator{ upgrades: upgradeTimes, @@ -87,9 +91,9 @@ func (c *Calculator) GetFeeRates() fees.Dimensions { return fees.Empty } -func (c *Calculator) GetCumulatedComplexity() fees.Dimensions { +func (c *Calculator) GetCurrentExcessComplexity() fees.Dimensions { if c.c.feeManager != nil { - return c.c.feeManager.GetCumulatedComplexity() + return c.c.feeManager.GetCurrentExcessComplexity() } return fees.Empty } diff --git a/vms/platformvm/txs/fee/calculator_test.go b/vms/platformvm/txs/fee/calculator_test.go index 6cd518a33ab4..13ad71978988 100644 --- a/vms/platformvm/txs/fee/calculator_test.go +++ b/vms/platformvm/txs/fee/calculator_test.go @@ -64,25 +64,25 @@ func TestAddAndRemoveFees(t *testing.T) { feeDelta, err := fc.AddFeesFor(units) r.NoError(err) - r.Equal(units, fc.c.feeManager.GetCumulatedComplexity()) + r.Equal(units, fc.c.feeManager.GetCurrentExcessComplexity()) r.NotZero(feeDelta) r.Equal(feeDelta, fc.c.fee) feeDelta2, err := fc.AddFeesFor(units) r.NoError(err) - r.Equal(doubleUnits, fc.c.feeManager.GetCumulatedComplexity()) + r.Equal(doubleUnits, fc.c.feeManager.GetCurrentExcessComplexity()) r.Equal(feeDelta, feeDelta2) r.Equal(feeDelta+feeDelta2, fc.c.fee) feeDelta3, err := fc.RemoveFeesFor(units) r.NoError(err) - r.Equal(units, fc.c.feeManager.GetCumulatedComplexity()) + r.Equal(units, fc.c.feeManager.GetCurrentExcessComplexity()) r.Equal(feeDelta, feeDelta3) r.Equal(feeDelta, fc.c.fee) feeDelta4, err := fc.RemoveFeesFor(units) r.NoError(err) - r.Zero(fc.c.feeManager.GetCumulatedComplexity()) + r.Zero(fc.c.feeManager.GetCurrentExcessComplexity()) r.Equal(feeDelta, feeDelta4) r.Zero(fc.c.fee) } @@ -153,7 +153,7 @@ func TestTxFees(t *testing.T) { 172, 1000, }, - fc.feeManager.GetCumulatedComplexity(), + fc.feeManager.GetCurrentExcessComplexity(), ) }, }, @@ -207,7 +207,7 @@ func TestTxFees(t *testing.T) { 172, 1000, }, - fc.feeManager.GetCumulatedComplexity(), + fc.feeManager.GetCurrentExcessComplexity(), ) }, }, @@ -253,7 +253,7 @@ func TestTxFees(t *testing.T) { 172, 1000, }, - fc.feeManager.GetCumulatedComplexity(), + fc.feeManager.GetCurrentExcessComplexity(), ) }, }, @@ -291,7 +291,7 @@ func TestTxFees(t *testing.T) { 172, 1000, }, - fc.feeManager.GetCumulatedComplexity(), + fc.feeManager.GetCurrentExcessComplexity(), ) }, }, @@ -329,7 +329,7 @@ func TestTxFees(t *testing.T) { 172, 1000, }, - fc.feeManager.GetCumulatedComplexity(), + fc.feeManager.GetCurrentExcessComplexity(), ) }, }, @@ -367,7 +367,7 @@ func TestTxFees(t *testing.T) { 172, 1000, }, - fc.feeManager.GetCumulatedComplexity(), + fc.feeManager.GetCurrentExcessComplexity(), ) }, }, @@ -421,7 +421,7 @@ func TestTxFees(t *testing.T) { 266, 1000, }, - fc.feeManager.GetCumulatedComplexity(), + fc.feeManager.GetCurrentExcessComplexity(), ) }, }, @@ -443,7 +443,7 @@ func TestTxFees(t *testing.T) { 266, 1000, }, - fc.feeManager.GetCumulatedComplexity(), + fc.feeManager.GetCurrentExcessComplexity(), ) }, }, @@ -500,7 +500,7 @@ func TestTxFees(t *testing.T) { 266, 1000, }, - fc.feeManager.GetCumulatedComplexity(), + fc.feeManager.GetCurrentExcessComplexity(), ) }, }, @@ -520,7 +520,7 @@ func TestTxFees(t *testing.T) { 266, 1000, }, - fc.feeManager.GetCumulatedComplexity(), + fc.feeManager.GetCurrentExcessComplexity(), ) }, }, @@ -562,7 +562,7 @@ func TestTxFees(t *testing.T) { 172, 1000, }, - fc.feeManager.GetCumulatedComplexity(), + fc.feeManager.GetCurrentExcessComplexity(), ) }, }, @@ -600,7 +600,7 @@ func TestTxFees(t *testing.T) { 262, 2000, }, - fc.feeManager.GetCumulatedComplexity(), + fc.feeManager.GetCurrentExcessComplexity(), ) }, }, @@ -638,7 +638,7 @@ func TestTxFees(t *testing.T) { 266, 1000, }, - fc.feeManager.GetCumulatedComplexity(), + fc.feeManager.GetCurrentExcessComplexity(), ) }, }, diff --git a/vms/platformvm/txs/fee/dynamic_config.go b/vms/platformvm/txs/fee/dynamic_config.go index 1120263df11d..c9b59e29ad61 100644 --- a/vms/platformvm/txs/fee/dynamic_config.go +++ b/vms/platformvm/txs/fee/dynamic_config.go @@ -27,23 +27,17 @@ func init() { var ( eUpgradeDynamicFeesConfig = commonfees.DynamicFeesConfig{ - InitialFeeRate: commonfees.Dimensions{ - 80 * units.NanoAvax, - 10 * units.NanoAvax, - 15 * units.NanoAvax, - 50 * units.NanoAvax, - }, MinFeeRate: commonfees.Dimensions{ // 3/4 of InitialFees 60 * units.NanoAvax, 8 * units.NanoAvax, 10 * units.NanoAvax, 35 * units.NanoAvax, }, - UpdateCoefficient: commonfees.Dimensions{ // over fees.CoeffDenom - 3, - 2, - 2, - 3, + UpdateDenominators: commonfees.Dimensions{ // over fees.CoeffDenom + 50_000, + 50_000, + 50_000, + 500_000, }, BlockMaxComplexity: commonfees.Dimensions{ 10_000, @@ -61,7 +55,6 @@ var ( // TODO ABENEGIA: decide if and how to validate preEUpgradeDynamicFeesConfig preEUpgradeDynamicFeesConfig = commonfees.DynamicFeesConfig{ - InitialFeeRate: commonfees.Empty, BlockMaxComplexity: commonfees.Max, } From 50181f39f0fc9fe2adf36bed913196b931350ea6 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Fri, 7 Jun 2024 15:23:39 +0200 Subject: [PATCH 167/190] wip: fixing UTs --- vms/components/fees/manager.go | 2 +- vms/components/fees/manager_test.go | 229 +++++++++-------------- vms/platformvm/service_test.go | 21 ++- vms/platformvm/txs/fee/dynamic_config.go | 4 +- vms/platformvm/vm_test.go | 5 +- 5 files changed, 111 insertions(+), 150 deletions(-) diff --git a/vms/components/fees/manager.go b/vms/components/fees/manager.go index 717ca768d3aa..064bdad24750 100644 --- a/vms/components/fees/manager.go +++ b/vms/components/fees/manager.go @@ -53,7 +53,7 @@ func TargetBlockComplexity(feesConfig DynamicFeesConfig, parentBlkTime, childBlk res := Empty if childBlkTime < parentBlkTime { - return Empty, fmt.Errorf("unexpected block times, parentBlkTim %v, childBlkTime %v", parentBlkTime, childBlkTime) + return res, fmt.Errorf("unexpected block times, parentBlkTim %v, childBlkTime %v", parentBlkTime, childBlkTime) } elapsedTime := uint64(childBlkTime - parentBlkTime) diff --git a/vms/components/fees/manager_test.go b/vms/components/fees/manager_test.go index 56e89901dfa2..890b9f2148c7 100644 --- a/vms/components/fees/manager_test.go +++ b/vms/components/fees/manager_test.go @@ -13,18 +13,19 @@ import ( "github.com/ava-labs/avalanchego/utils/units" ) +var testDynamicFeeCfg = DynamicFeesConfig{ + MinFeeRate: Dimensions{60 * units.NanoAvax, 8 * units.NanoAvax, 10 * units.NanoAvax, 35 * units.NanoAvax}, + UpdateDenominators: Dimensions{50_000, 50_000, 50_000, 500_000}, + BlockMaxComplexity: Dimensions{10_000, 6_000, 8_000, 60_000}, + BlockTargetComplexityRate: Dimensions{250, 60, 120, 650}, +} + func TestUpdateFeeRates(t *testing.T) { require := require.New(t) var ( - feesCfg = DynamicFeesConfig{ - MinFeeRate: Dimensions{1, 1, 1, 1}, - UpdateDenominators: Dimensions{100, 200, 500, 1_000}, - BlockMaxComplexity: Dimensions{100, 100, 100, 100}, - BlockTargetComplexityRate: Dimensions{25, 25, 25, 25}, - } - parentFeeRate = Dimensions{10, 20, 100, 200} - parentComplexity = Dimensions{100, 25, 20, 10} + parentFeeRate = Dimensions{10, 20, 100, 200} + cumulatedComplexity = Dimensions{300, 60, 119, 100} elapsedTime = time.Second parentBlkTime = time.Now().Truncate(time.Second) @@ -32,72 +33,55 @@ func TestUpdateFeeRates(t *testing.T) { ) m, err := NewUpdatedManager( - feesCfg, - parentComplexity, + testDynamicFeeCfg, + cumulatedComplexity, parentBlkTime.Unix(), childBlkTime.Unix(), ) require.NoError(err) - // Bandwidth complexity are above target, fee rate is pushed up - require.Equal(uint64(420), m.feeRates[Bandwidth]) + // Bandwidth cumulated complexity are above target, fee rate is pushed up + require.Greater(m.feeRates[Bandwidth], parentFeeRate[Bandwidth]) - // UTXORead complexity is at target, fee rate does not change - require.Equal(parentFeeRate[UTXORead], m.feeRates[UTXORead]) + // UTXORead cumulated complexity is at target, fee rate is at the minimum + require.Equal(testDynamicFeeCfg.MinFeeRate[UTXORead], m.feeRates[UTXORead]) - // UTXOWrite complexity is below target, fee rate is pushed down - require.Equal(uint64(33), m.feeRates[UTXOWrite]) + // UTXOWrite cumulated complexity is below target, fee rate is at the minimum + require.Equal(testDynamicFeeCfg.MinFeeRate[UTXOWrite], m.feeRates[UTXOWrite]) - // Compute complexoty is below target, fee rate is pushed down - require.Equal(uint64(1), m.feeRates[Compute]) + // Compute cumulated complexity is below target, fee rate is at the minimum + require.Equal(testDynamicFeeCfg.MinFeeRate[Compute], m.feeRates[Compute]) } -// func TestFeeUpdateFactor(t *testing.T) { -// tests := []struct { -// coeff uint64 -// parentBlkComplexity uint64 -// targetBlkComplexity uint64 -// want uint64 -// wantIncreaseFee bool -// }{ -// // parentBlkComplexity == targetBlkComplexity gives factor 1, no matter what coeff is -// {1, 250, 250, 1, false}, -// {math.MaxUint64, 250, 250, 1, false}, - -// // parentBlkComplexity > targetBlkComplexity -// {1, 101, 100, 1, true}, // should be 1.0005 -// {1, 110, 100, 1, true}, // should be 1.005 -// {1, 200, 100, 1, true}, // should be 1.05 -// {1, 1_100, 100, 1, true}, // should be 1.648 -// {1, 2_100, 100, 2, true}, // should be 2,718 -// {1, 3_100, 100, 4, true}, // should be 4,48 -// {1, 4_100, 100, 7, true}, // should be 7,39 -// {1, 7_100, 100, 33, true}, // should be 33,12 -// {1, 8_100, 100, 54, true}, // should be 54,6 -// {1, 10_100, 100, 148, true}, // should be 148,4 - -// // parentBlkComplexity < targetBlkComplexity -// {1, 100, 101, 1, false}, -// {1, 100, 110, 1, false}, -// {1, 100, 200, 1, false}, -// {1, 100, 1_100, 1, false}, -// {1, 100, 2_100, 2, false}, -// {1, 100, 3_100, 4, false}, -// {1, 100, 4_100, 7, false}, -// {1, 100, 7_100, 33, false}, -// {1, 100, 8_100, 54, false}, -// {1, 100, 10_100, 148, false}, -// } -// for _, tt := range tests { -// haveFactor, haveIncreaseFee := updateFactor( -// tt.coeff, -// tt.parentBlkComplexity, -// tt.targetBlkComplexity, -// ) -// require.Equal(t, tt.want, haveFactor) -// require.Equal(t, tt.wantIncreaseFee, haveIncreaseFee) -// } -// } +func TestFakeExponential(t *testing.T) { + tests := []struct { + factor uint64 + numerator uint64 + denominator uint64 + want uint64 + }{ + // When numerator == 0 the return value should always equal the value of factor + {1, 0, 1, 1}, + {38493, 0, 1000, 38493}, + {0, 1234, 2345, 0}, // should be 0 + {1, 2, 1, 6}, // approximate 7.389 + {1, 4, 2, 6}, + {1, 3, 1, 16}, // approximate 20.09 + {1, 6, 2, 18}, + {1, 4, 1, 49}, // approximate 54.60 + {1, 8, 2, 50}, + {10, 8, 2, 542}, // approximate 540.598 + {11, 8, 2, 596}, // approximate 600.58 + {1, 5, 1, 136}, // approximate 148.4 + {1, 5, 2, 11}, // approximate 12.18 + {2, 5, 2, 23}, // approximate 24.36 + {1, 50000000, 2225652, 5709098764}, + } + for _, tt := range tests { + have := fakeExponential(tt.factor, tt.numerator, tt.denominator) + require.Equal(t, tt.want, have) + } +} func TestPChainFeeRateIncreaseDueToPeak(t *testing.T) { // Complexity values comes from the mainnet historical peak as measured @@ -105,86 +89,57 @@ func TestPChainFeeRateIncreaseDueToPeak(t *testing.T) { require := require.New(t) - var ( - feesCfg = DynamicFeesConfig{ - MinFeeRate: Dimensions{ - 60 * units.NanoAvax, - 8 * units.NanoAvax, - 10 * units.NanoAvax, - 35 * units.NanoAvax, - }, - UpdateDenominators: Dimensions{ // over CoeffDenom - 1, - 1, - 1, - 1, - }, - BlockTargetComplexityRate: Dimensions{ - 2500, - 600, - 1200, - 6500, - }, - BlockMaxComplexity: Dimensions{ - 100_000, - 60_000, - 60_000, - 600_000, - }, - } - - // See mainnet P-chain block 2LJVD1rfEfaJtTwRggFXaUXhME4t5WYGhYP9Aj7eTYqGsfknuC its descendants - blockComplexities = []struct { - blkTime int64 - complexity Dimensions - }{ - {1615237936, Dimensions{28234, 10812, 10812, 106000}}, - {1615237936, Dimensions{17634, 6732, 6732, 66000}}, - {1615237936, Dimensions{12334, 4692, 4692, 46000}}, - {1615237936, Dimensions{5709, 2142, 2142, 21000}}, - {1615237936, Dimensions{15514, 5916, 5916, 58000}}, - {1615237936, Dimensions{12069, 4590, 4590, 45000}}, - {1615237936, Dimensions{8359, 3162, 3162, 31000}}, - {1615237936, Dimensions{5444, 2040, 2040, 20000}}, - {1615237936, Dimensions{1734, 612, 612, 6000}}, - {1615237936, Dimensions{5974, 2244, 2244, 22000}}, - {1615237936, Dimensions{3059, 1122, 1122, 11000}}, - {1615237936, Dimensions{7034, 2652, 2652, 26000}}, - {1615237936, Dimensions{7564, 2856, 2856, 28000}}, - {1615237936, Dimensions{34064, 13056, 13056, 128000}}, - // {1615237936, Dimensions{34064, 13056, 13056, 128000}}, - // {1615237936, Dimensions{34064, 13056, 13056, 128000}}, - // {1615237936, Dimensions{34064, 13056, 13056, 128000}}, - // {1615237936, Dimensions{34064, 13056, 13056, 128000}}, - // {1615237936, Dimensions{34064, 13056, 13056, 128000}}, - // {1615237936, Dimensions{34064, 13056, 13056, 128000}}, <-- from here on, fee would exceed 100 Avax - // {1615237936, Dimensions{34064, 13056, 13056, 128000}}, - // {1615237936, Dimensions{820, 360, 442, 4000}}, - // {1615237936, Dimensions{34064, 13056, 13056, 128000}}, - // {1615237936, Dimensions{34064, 13056, 13056, 128000}}, - // {1615237936, Dimensions{34064, 13056, 13056, 128000}}, - // {1615237936, Dimensions{34064, 13056, 13056, 128000}}, - // {1615237936, Dimensions{34064, 13056, 13056, 128000}}, - // {1615237936, Dimensions{34064, 13056, 13056, 128000}}, - // {1615237936, Dimensions{34064, 13056, 13056, 128000}}, - // {1615237936, Dimensions{34064, 13056, 13056, 128000}}, - // {1615237936, Dimensions{3589, 1326, 1326, 13000}}, - // {1615237936, Dimensions{550, 180, 180, 2000}}, - // {1615237936, Dimensions{413, 102, 102, 1000}}, - } - ) + // See mainnet P-chain block 2LJVD1rfEfaJtTwRggFXaUXhME4t5WYGhYP9Aj7eTYqGsfknuC its descendants + blockComplexities := []struct { + blkTime int64 + complexity Dimensions + }{ + {1615237936, Dimensions{28234, 10812, 10812, 106000}}, + {1615237936, Dimensions{17634, 6732, 6732, 66000}}, + {1615237936, Dimensions{12334, 4692, 4692, 46000}}, + {1615237936, Dimensions{5709, 2142, 2142, 21000}}, + {1615237936, Dimensions{15514, 5916, 5916, 58000}}, + {1615237936, Dimensions{12069, 4590, 4590, 45000}}, + {1615237936, Dimensions{8359, 3162, 3162, 31000}}, + {1615237936, Dimensions{5444, 2040, 2040, 20000}}, + {1615237936, Dimensions{1734, 612, 612, 6000}}, + {1615237936, Dimensions{5974, 2244, 2244, 22000}}, + {1615237936, Dimensions{3059, 1122, 1122, 11000}}, + {1615237936, Dimensions{7034, 2652, 2652, 26000}}, + {1615237936, Dimensions{7564, 2856, 2856, 28000}}, + {1615237936, Dimensions{34064, 13056, 13056, 128000}}, + {1615237936, Dimensions{34064, 13056, 13056, 128000}}, + {1615237936, Dimensions{34064, 13056, 13056, 128000}}, + {1615237936, Dimensions{34064, 13056, 13056, 128000}}, + {1615237936, Dimensions{34064, 13056, 13056, 128000}}, + {1615237936, Dimensions{34064, 13056, 13056, 128000}}, + {1615237936, Dimensions{34064, 13056, 13056, 128000}}, + {1615237936, Dimensions{34064, 13056, 13056, 128000}}, + // {1615237936, Dimensions{820, 360, 442, 4000}}, + // {1615237936, Dimensions{34064, 13056, 13056, 128000}}, + // {1615237936, Dimensions{34064, 13056, 13056, 128000}}, + // {1615237936, Dimensions{34064, 13056, 13056, 128000}}, + // {1615237936, Dimensions{34064, 13056, 13056, 128000}}, + // {1615237936, Dimensions{34064, 13056, 13056, 128000}}, + // {1615237936, Dimensions{34064, 13056, 13056, 128000}}, + // {1615237936, Dimensions{34064, 13056, 13056, 128000}}, + // {1615237936, Dimensions{34064, 13056, 13056, 128000}}, + // {1615237936, Dimensions{3589, 1326, 1326, 13000}}, + // {1615237936, Dimensions{550, 180, 180, 2000}}, + // {1615237936, Dimensions{413, 102, 102, 1000}}, + } m := &Manager{ - feeRates: feesCfg.MinFeeRate, + feeRates: testDynamicFeeCfg.MinFeeRate, } // PEAK INCOMING - peakFeeRate := feesCfg.MinFeeRate + peakFeeRate := testDynamicFeeCfg.MinFeeRate for i := 1; i < len(blockComplexities); i++ { parentBlkData := blockComplexities[i-1] childBlkData := blockComplexities[i] m, err := NewUpdatedManager( - feesCfg, + testDynamicFeeCfg, parentBlkData.complexity, parentBlkData.blkTime, childBlkData.blkTime, @@ -193,7 +148,7 @@ func TestPChainFeeRateIncreaseDueToPeak(t *testing.T) { // check that fee rates are strictly above minimal require.False( - Compare(m.feeRates, feesCfg.MinFeeRate), + Compare(m.feeRates, testDynamicFeeCfg.MinFeeRate), fmt.Sprintf("failed at %d of %d iteration, \n curr fees %v \n next fees %v", i, len(blockComplexities), @@ -217,7 +172,7 @@ func TestPChainFeeRateIncreaseDueToPeak(t *testing.T) { childBlkTime := parentBlkTime.Add(elapsedTime) m, err := NewUpdatedManager( - feesCfg, + testDynamicFeeCfg, offPeakBlkComplexity, parentBlkTime.Unix(), childBlkTime.Unix(), diff --git a/vms/platformvm/service_test.go b/vms/platformvm/service_test.go index 53af697b780f..cd89b0b9f442 100644 --- a/vms/platformvm/service_test.go +++ b/vms/platformvm/service_test.go @@ -77,7 +77,7 @@ var ( } ) -func testReplayFeeCalculator(cfg *config.Config, state state.Chain) *fee.Calculator { +func testReplayFeeCalculator(cfg *config.Config, parentBlkTime time.Time, state state.Chain) (*fee.Calculator, error) { var ( blkTime = state.GetTimestamp() isEActive = cfg.UpgradeConfig.IsEActivated(blkTime) @@ -89,14 +89,18 @@ func testReplayFeeCalculator(cfg *config.Config, state state.Chain) *fee.Calcula feeCalculator = fee.NewStaticCalculator(staticFeeCfg, cfg.UpgradeConfig, blkTime) } else { feesCfg := fee.GetDynamicConfig(isEActive) - // feeRates, err := state.GetFeeRates() - // if err != nil { - // return nil, fmt.Errorf("failed retrieving fee rates: %w", err) - // } - feesMan := commonfees.NewManager(commonfees.Empty /*feeRates*/) // TODO ABENEGIA: fix once fee algo is fixed + excessComplexity, err := state.GetExcessComplexity() + if err != nil { + return nil, fmt.Errorf("failed retrieving excess complexity: %w", err) + } + feeCfg := fee.GetDynamicConfig(isEActive) + feesMan, err := commonfees.NewUpdatedManager(feeCfg, excessComplexity, parentBlkTime.Unix(), blkTime.Unix()) + if err != nil { + return nil, fmt.Errorf("failed updating fee manager: %w", err) + } feeCalculator = fee.NewDynamicCalculator(staticFeeCfg, feesMan, feesCfg.BlockMaxComplexity) } - return feeCalculator + return feeCalculator, nil } func defaultService(t *testing.T) (*Service, *mutableSharedMemory, *txstest.Builder) { @@ -406,7 +410,8 @@ 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 := testReplayFeeCalculator(&service.vm.Config, service.vm.state) + feeCalc, err := testReplayFeeCalculator(&service.vm.Config, defaultGenesisTime, service.vm.state) + require.NoError(err) fee, err := feeCalc.ComputeFee(testSubnet1.Unsigned, testSubnet1.Creds) require.NoError(err) balance = defaultBalance - fee diff --git a/vms/platformvm/txs/fee/dynamic_config.go b/vms/platformvm/txs/fee/dynamic_config.go index c9b59e29ad61..2e546b07948b 100644 --- a/vms/platformvm/txs/fee/dynamic_config.go +++ b/vms/platformvm/txs/fee/dynamic_config.go @@ -27,13 +27,13 @@ func init() { var ( eUpgradeDynamicFeesConfig = commonfees.DynamicFeesConfig{ - MinFeeRate: commonfees.Dimensions{ // 3/4 of InitialFees + MinFeeRate: commonfees.Dimensions{ 60 * units.NanoAvax, 8 * units.NanoAvax, 10 * units.NanoAvax, 35 * units.NanoAvax, }, - UpdateDenominators: commonfees.Dimensions{ // over fees.CoeffDenom + UpdateDenominators: commonfees.Dimensions{ 50_000, 50_000, 50_000, diff --git a/vms/platformvm/vm_test.go b/vms/platformvm/vm_test.go index 18bfaf9f25ad..6c24d9cdb959 100644 --- a/vms/platformvm/vm_test.go +++ b/vms/platformvm/vm_test.go @@ -358,7 +358,7 @@ func defaultVM(t *testing.T, f fork) (*VM, *txstest.Builder, database.Database, // 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() @@ -394,7 +394,8 @@ 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 := testReplayFeeCalculator(&vm.Config, vm.state) + feeCalc, err := testReplayFeeCalculator(&vm.Config, defaultGenesisTime, vm.state) + require.NoError(err) fee, err := feeCalc.ComputeFee(testSubnet1.Unsigned, testSubnet1.Creds) require.NoError(err) require.Equal(uint64(utxo.Amount)-fee, out.Amount()) From 72b76eb10cd814c49828b10256edde71f6544421 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Fri, 7 Jun 2024 16:01:59 +0200 Subject: [PATCH 168/190] fixed dynamic fees config validation --- vms/components/fees/config.go | 4 ++++ vms/platformvm/txs/fee/dynamic_config.go | 3 +++ 2 files changed, 7 insertions(+) diff --git a/vms/components/fees/config.go b/vms/components/fees/config.go index 576babbf14de..60deaad3b4b8 100644 --- a/vms/components/fees/config.go +++ b/vms/components/fees/config.go @@ -35,6 +35,10 @@ func (c *DynamicFeesConfig) Validate() error { c.BlockMaxComplexity[i], ) } + + if c.UpdateDenominators[i] == 0 { + return fmt.Errorf("dimension %d, update denominator cannot be zero", i) + } } return nil diff --git a/vms/platformvm/txs/fee/dynamic_config.go b/vms/platformvm/txs/fee/dynamic_config.go index 2e546b07948b..55edd6357d72 100644 --- a/vms/platformvm/txs/fee/dynamic_config.go +++ b/vms/platformvm/txs/fee/dynamic_config.go @@ -79,6 +79,9 @@ func ResetDynamicConfig(ctx *snow.Context, customFeesConfig *commonfees.DynamicF if ctx.NetworkID == constants.MainnetID || ctx.NetworkID == constants.FujiID { return fmt.Errorf("forbidden resetting dynamic fee rates config for network %s", constants.NetworkName(ctx.NetworkID)) } + if err := customFeesConfig.Validate(); err != nil { + return fmt.Errorf("custom fee config fails validation: %w", err) + } customDynamicFeesConfig = customFeesConfig return nil From 5acb8dde5ec412f38a785b22428df66b8e15fd21 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Fri, 7 Jun 2024 16:46:46 +0200 Subject: [PATCH 169/190] fixed GetNextFeeRates APIs --- tests/e2e/p/dynamic_fees.go | 26 ++++++++-------- tests/e2e/p/workflow.go | 2 +- vms/platformvm/client.go | 9 +++--- vms/platformvm/service.go | 11 +++---- vms/platformvm/service_test.go | 55 +++++++++++++++++++++------------- wallet/chain/p/wallet.go | 2 +- 6 files changed, 57 insertions(+), 48 deletions(-) diff --git a/tests/e2e/p/dynamic_fees.go b/tests/e2e/p/dynamic_fees.go index 0b5425a7b4d6..86ea0a413d4a 100644 --- a/tests/e2e/p/dynamic_fees.go +++ b/tests/e2e/p/dynamic_fees.go @@ -65,9 +65,9 @@ var _ = ginkgo.Describe("[Dynamic Fees]", func() { tests.Outf("{{blue}} P-chain balance before P->X export: %d {{/}}\n", pStartBalance) ginkgo.By("checking that initial fee values match with configured ones", func() { - currFeeRates, _, err := pChainClient.GetFeeRates(e2e.DefaultContext()) + nextFeeRates, err := pChainClient.GetNextFeeRates(e2e.DefaultContext()) require.NoError(err) - require.Equal(customDynamicFeesConfig.MinFeeRate, currFeeRates) + require.Equal(customDynamicFeesConfig.MinFeeRate, nextFeeRates) }) ginkgo.By("issue expensive transactions so to increase the fee rates to be paid for accepting the transactons", @@ -90,9 +90,9 @@ var _ = ginkgo.Describe("[Dynamic Fees]", func() { subnetID = subnetTx.ID() }) - currFeeRates, _, err := pChainClient.GetFeeRates(e2e.DefaultContext()) + nextFeeRates, err := pChainClient.GetNextFeeRates(e2e.DefaultContext()) require.NoError(err) - tests.Outf("{{blue}} current fee rates: %v {{/}}\n", currFeeRates) + tests.Outf("{{blue}} next fee rates: %v {{/}}\n", nextFeeRates) ginkgo.By("repeatedly change the permissioned subnet owner to increase fee rates", func() { txsCount := 10 @@ -111,30 +111,30 @@ var _ = ginkgo.Describe("[Dynamic Fees]", func() { ) require.NoError(err) - updatedFeeRates, _, err := pChainClient.GetFeeRates(e2e.DefaultContext()) + updatedFeeRates, err := pChainClient.GetNextFeeRates(e2e.DefaultContext()) require.NoError(err) tests.Outf("{{blue}} current fee rates: %v {{/}}\n", updatedFeeRates) ginkgo.By("check that fee rates components have increased") require.True( - commonfees.Compare(currFeeRates, updatedFeeRates), - fmt.Sprintf("previous fee rates %v, current fee rates %v", currFeeRates, updatedFeeRates), + commonfees.Compare(nextFeeRates, updatedFeeRates), + fmt.Sprintf("previous fee rates %v, current fee rates %v", nextFeeRates, updatedFeeRates), ) - currFeeRates = updatedFeeRates + nextFeeRates = updatedFeeRates } }) ginkgo.By("wait for the fee rates to decrease", func() { - initialFeeRates := currFeeRates + initialFeeRates := nextFeeRates e2e.Eventually(func() bool { var err error - _, currFeeRates, err = pChainClient.GetFeeRates(e2e.DefaultContext()) + nextFeeRates, err = pChainClient.GetNextFeeRates(e2e.DefaultContext()) require.NoError(err) - tests.Outf("{{blue}} next fee rates: %v {{/}}\n", currFeeRates) + tests.Outf("{{blue}} next fee rates: %v {{/}}\n", nextFeeRates) ratesStrictlyLower := false for i := 0; i < len(initialFeeRates); i++ { - if currFeeRates[i] < initialFeeRates[i] { + if nextFeeRates[i] < initialFeeRates[i] { ratesStrictlyLower = true break } @@ -142,7 +142,7 @@ var _ = ginkgo.Describe("[Dynamic Fees]", func() { return ratesStrictlyLower }, e2e.DefaultTimeout, e2e.DefaultPollingInterval, "failed to see gas price decrease before timeout") - tests.Outf("\n{{blue}}fee rates have decreased to %v{{/}}\n", currFeeRates) + tests.Outf("\n{{blue}}fee rates have decreased to %v{{/}}\n", nextFeeRates) }) }, ) diff --git a/tests/e2e/p/workflow.go b/tests/e2e/p/workflow.go index aaec96e0b8f7..505e1c2452a6 100644 --- a/tests/e2e/p/workflow.go +++ b/tests/e2e/p/workflow.go @@ -151,7 +151,7 @@ var _ = e2e.DescribePChain("[Workflow]", func() { pChainExportFee := uint64(0) ginkgo.By("export avax from P to X chain", func() { - _, nextFeeRates, err := pChainClient.GetFeeRates(e2e.DefaultContext()) + nextFeeRates, err := pChainClient.GetNextFeeRates(e2e.DefaultContext()) require.NoError(err) tx, err := pWallet.IssueExportTx( diff --git a/vms/platformvm/client.go b/vms/platformvm/client.go index 374ad52bc096..2b5c7c49f9ee 100644 --- a/vms/platformvm/client.go +++ b/vms/platformvm/client.go @@ -133,9 +133,8 @@ 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) - - // GetFeeRates returns the current unit fees and the next unit fees that a transaction must pay to be accepted - GetFeeRates(ctx context.Context, options ...rpc.Option) (commonfees.Dimensions, commonfees.Dimensions, error) + // GetNextFeeRates returns the next fee rates that a transaction must pay to be accepted now + GetNextFeeRates(ctx context.Context, options ...rpc.Option) (commonfees.Dimensions, error) } // Client implementation for interacting with the P Chain endpoint @@ -551,8 +550,8 @@ func (c *client) GetBlockByHeight(ctx context.Context, height uint64, options .. return formatting.Decode(res.Encoding, res.Block) } -func (c *client) GetFeeRates(ctx context.Context, options ...rpc.Option) (commonfees.Dimensions, commonfees.Dimensions, error) { +func (c *client) GetNextFeeRates(ctx context.Context, options ...rpc.Option) (commonfees.Dimensions, error) { res := &GetFeeRatesReply{} err := c.requester.SendRequest(ctx, "platform.getFeeRates", struct{}{}, res, options...) - return res.CurrentFeeRates, res.NextFeeRates, err + return res.NextFeeRates, err } diff --git a/vms/platformvm/service.go b/vms/platformvm/service.go index 550e720113cc..525018922495 100644 --- a/vms/platformvm/service.go +++ b/vms/platformvm/service.go @@ -1825,15 +1825,14 @@ func (s *Service) GetBlockByHeight(_ *http.Request, args *api.GetBlockByHeightAr // GetFeeRatesReply is the response from GetFeeRates type GetFeeRatesReply struct { - CurrentFeeRates commonfees.Dimensions `json:"currentFeeRates"` - NextFeeRates commonfees.Dimensions `json:"nextFeeRates"` + NextFeeRates commonfees.Dimensions `json:"nextFeeRates"` } -// GetTimestamp returns the current timestamp on chain. -func (s *Service) GetFeeRates(_ *http.Request, _ *struct{}, reply *GetFeeRatesReply) error { +// GetNextFeeRates returns the next fee rates that a transaction must pay to be accepted now +func (s *Service) GetNextFeeRates(_ *http.Request, _ *struct{}, reply *GetFeeRatesReply) error { s.vm.ctx.Log.Debug("API called", zap.String("service", "platform"), - zap.String("method", "getFeeRates"), + zap.String("method", "getNextFeeRates"), ) s.vm.ctx.Lock.Lock() @@ -1845,8 +1844,6 @@ func (s *Service) GetFeeRates(_ *http.Request, _ *struct{}, reply *GetFeeRatesRe return fmt.Errorf("could not retrieve state for block %s", preferredID) } - reply.CurrentFeeRates = commonfees.Empty // TODO ABENEGIA: fix this up once algo is changed - currentChainTime := onAccept.GetTimestamp() nextTimestamp, _, err := state.NextBlockTime(onAccept, &s.vm.clock) if err != nil { diff --git a/vms/platformvm/service_test.go b/vms/platformvm/service_test.go index cd89b0b9f442..d777cd2d633b 100644 --- a/vms/platformvm/service_test.go +++ b/vms/platformvm/service_test.go @@ -1069,30 +1069,43 @@ func TestServiceGetBlockByHeight(t *testing.T) { } } -// TODO ABENEGIA: unlock once fee rate algo is being fixed -// func TestGetFeeRates(t *testing.T) { -// require := require.New(t) -// service, _, _ := defaultService(t) +func TestGetFeeRates(t *testing.T) { + require := require.New(t) + service, _, _ := defaultService(t) -// reply := GetFeeRatesReply{} -// require.NoError(service.GetFeeRates(nil, nil, &reply)) + now := time.Now().Truncate(time.Second) + service.vm.clock.Set(now) + feeCfg := fee.GetDynamicConfig(true /*isEActive*/) -// service.vm.ctx.Lock.Lock() + // initially minimal fees + reply0 := GetFeeRatesReply{} + require.NoError(service.GetNextFeeRates(nil, nil, &reply0)) + require.Equal(feeCfg.MinFeeRate, reply0.NextFeeRates) -// feeRates, err := service.vm.state.GetFeeRates() -// require.NoError(err) -// require.Equal(feeRates, reply.CurrentFeeRates) + // let cumulated complexity go above target. Fee rates will go up + service.vm.ctx.Lock.Lock() + elapsedTime := time.Second + var targetComplexity commonfees.Dimensions + for i := commonfees.Dimension(0); i < commonfees.FeeDimensions; i++ { + targetComplexity[i] = feeCfg.BlockTargetComplexityRate[i] * uint64(elapsedTime/time.Second) + } + complexity, err := commonfees.Add(targetComplexity, commonfees.Dimensions{10, 20, 30, 40}) + require.NoError(err) + service.vm.state.SetExcessComplexity(complexity) + service.vm.ctx.Lock.Unlock() -// updatedFeeRates := commonfees.Dimensions{ -// 123, -// 456, -// 789, -// 1011, -// } -// service.vm.state.SetFeeRates(updatedFeeRates) + reply1 := GetFeeRatesReply{} + require.NoError(service.GetNextFeeRates(nil, nil, &reply1)) + highFeeRates := reply1.NextFeeRates + require.True(commonfees.Compare(highFeeRates, feeCfg.MinFeeRate)) -// service.vm.ctx.Lock.Unlock() + // let time tick. Fee rates will go down + service.vm.ctx.Lock.Lock() + now = now.Add(3 * time.Second) + service.vm.clock.Set(now) + service.vm.ctx.Lock.Unlock() -// require.NoError(service.GetFeeRates(nil, nil, &reply)) -// require.Equal(updatedFeeRates, reply.CurrentFeeRates) -// } + reply2 := GetFeeRatesReply{} + require.NoError(service.GetNextFeeRates(nil, nil, &reply2)) + require.True(commonfees.Compare(highFeeRates, reply2.NextFeeRates)) +} diff --git a/wallet/chain/p/wallet.go b/wallet/chain/p/wallet.go index 15e03d315fa1..846e9ea40187 100644 --- a/wallet/chain/p/wallet.go +++ b/wallet/chain/p/wallet.go @@ -662,7 +662,7 @@ func (w *wallet) refreshFeesData(ctx *builder.Context, options ...common.Option) w.staticFeesConfig = staticFeesConfigFromContext(ctx) - _, w.nextFeeRates, err = w.client.GetFeeRates(opsCtx) + w.nextFeeRates, err = w.client.GetNextFeeRates(opsCtx) if err != nil { return err } From d9478395f7f7bb6a80d7c8c03cf5cbe136646668 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 10 Jun 2024 10:17:48 +0200 Subject: [PATCH 170/190] nit --- vms/components/fees/config.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/vms/components/fees/config.go b/vms/components/fees/config.go index 60deaad3b4b8..1b972d45c980 100644 --- a/vms/components/fees/config.go +++ b/vms/components/fees/config.go @@ -12,8 +12,7 @@ type DynamicFeesConfig struct { MinFeeRate Dimensions `json:"minimal-fee-rate"` // UpdateDenominators contains, per each fee dimension, the - // exponential update coefficient. Setting an entry to 0 makes - // the corresponding fee rate constant. + // exponential normalization coefficient. UpdateDenominators Dimensions `json:"update-denominator"` // BlockTargetComplexityRate contains, per each fee dimension, the From 30513a8e39d8414866bbe6c5da65d8b377366c74 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 10 Jun 2024 14:13:54 +0200 Subject: [PATCH 171/190] fixed race in UT --- vms/platformvm/service_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vms/platformvm/service_test.go b/vms/platformvm/service_test.go index fd208f7fc0c1..bde27fb415d5 100644 --- a/vms/platformvm/service_test.go +++ b/vms/platformvm/service_test.go @@ -1163,9 +1163,11 @@ func TestGetFeeRates(t *testing.T) { require := require.New(t) service, _, _ := defaultService(t) + service.vm.ctx.Lock.Lock() now := time.Now().Truncate(time.Second) service.vm.clock.Set(now) feeCfg := fee.GetDynamicConfig(true /*isEActive*/) + service.vm.ctx.Lock.Unlock() // initially minimal fees reply0 := GetFeeRatesReply{} From f6d0a68fa3b9da7e0a8c7a64ea09dd2810dbf2dd Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Tue, 11 Jun 2024 15:18:38 +0200 Subject: [PATCH 172/190] nit --- vms/platformvm/state/block_helpers.go | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/vms/platformvm/state/block_helpers.go b/vms/platformvm/state/block_helpers.go index b39e658af551..74845996fc6e 100644 --- a/vms/platformvm/state/block_helpers.go +++ b/vms/platformvm/state/block_helpers.go @@ -11,7 +11,6 @@ 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" - "github.com/ava-labs/avalanchego/vms/platformvm/upgrade" commonfees "github.com/ava-labs/avalanchego/vms/components/fees" ) @@ -88,7 +87,7 @@ func PickFeeCalculator(cfg *config.Config, state Chain, parentBlkTime time.Time) feeCalculator = fee.NewStaticCalculator(staticFeeCfg, cfg.UpgradeConfig, childBlkTime) } else { feesCfg := fee.GetDynamicConfig(isEActive) - feesMan, err := updatedFeeManager(cfg.UpgradeConfig, state, parentBlkTime) + feesMan, err := updatedFeeManager(isEActive, state, parentBlkTime) if err != nil { return nil, fmt.Errorf("failed updating fee manager: %w", err) } @@ -97,19 +96,15 @@ func PickFeeCalculator(cfg *config.Config, state Chain, parentBlkTime time.Time) return feeCalculator, nil } -func updatedFeeManager(upgrades upgrade.Config, state Chain, parentBlkTime time.Time) (*commonfees.Manager, error) { - var ( - isEActive = upgrades.IsEActivated(parentBlkTime) - feeCfg = fee.GetDynamicConfig(isEActive) - feeManager *commonfees.Manager - ) - +func updatedFeeManager(isEActive bool, state Chain, parentBlkTime time.Time) (*commonfees.Manager, error) { + var feeManager *commonfees.Manager if isEActive { excessComplexity, err := state.GetExcessComplexity() if err != nil { return nil, fmt.Errorf("failed retrieving excess complexity: %w", err) } childBlkTime := state.GetTimestamp() + feeCfg := fee.GetDynamicConfig(isEActive) feeManager, err = commonfees.NewUpdatedManager( feeCfg, From a2c4e736e50b8fdc0106b3e7b8343e3c55b6e947 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 17 Jun 2024 15:18:00 +0200 Subject: [PATCH 173/190] wip: reworked fee manager --- vms/components/fees/config.go | 19 +++-- vms/components/fees/manager.go | 60 +++++++++------- vms/components/fees/manager_test.go | 2 +- vms/platformvm/block/builder/builder.go | 27 ++++--- .../block/executor/standard_block_test.go | 4 +- vms/platformvm/block/executor/verifier.go | 31 +++++--- vms/platformvm/service_test.go | 51 ++++++------- vms/platformvm/state/block_helpers.go | 19 ++--- vms/platformvm/state/diff.go | 8 +-- vms/platformvm/state/mock_state.go | 72 +++++++++---------- vms/platformvm/state/state.go | 8 +-- vms/platformvm/txs/fee/calculator.go | 20 +++--- vms/platformvm/txs/fee/calculator_test.go | 34 ++++----- 13 files changed, 192 insertions(+), 163 deletions(-) diff --git a/vms/components/fees/config.go b/vms/components/fees/config.go index 57eaae698cee..82d365c8d17b 100644 --- a/vms/components/fees/config.go +++ b/vms/components/fees/config.go @@ -3,7 +3,11 @@ package fees -import "errors" +import ( + "errors" + "fmt" + "time" +) var ( errZeroLeakGasCoeff = errors.New("zero leak gas coefficient") @@ -27,7 +31,7 @@ type DynamicFeesConfig struct { FeeDimensionWeights Dimensions `json:"fee-dimension-weights"` MaxGasPerSecond Gas - LeakGasCoeff Gas // TODO ABENEGIA: not sure of the unit of measurement here + LeakGasCoeff Gas // techically the unit of measure if sec^{-1}, but picking Gas reduces casts needed } func (c *DynamicFeesConfig) Validate() error { @@ -44,10 +48,15 @@ func (c *DynamicFeesConfig) Validate() error { // We cap the maximum gas consumed by time with a leaky bucket approach // MaxGas = min (MaxGas + MaxGasPerSecond/LeakGasCoeff*ElapsedTime, MaxGasPerSecond) -func MaxGas(cfg DynamicFeesConfig, currentGasCapacity Gas, elapsedTime uint64) Gas { +func MaxGas(cfg DynamicFeesConfig, currentGasCapacity Gas, parentBlkTime, childBlkTime time.Time) (Gas, error) { + if !childBlkTime.After(parentBlkTime) { + return ZeroGas, fmt.Errorf("unexpected block times, parentBlkTim %v, childBlkTime %v", parentBlkTime, childBlkTime) + } + + elapsedTime := uint64(childBlkTime.Unix() - parentBlkTime.Unix()) if elapsedTime > uint64(cfg.LeakGasCoeff) { - return cfg.MaxGasPerSecond + return cfg.MaxGasPerSecond, nil } - return min(cfg.MaxGasPerSecond, currentGasCapacity+cfg.MaxGasPerSecond*Gas(elapsedTime)/cfg.LeakGasCoeff) + return min(cfg.MaxGasPerSecond, currentGasCapacity+cfg.MaxGasPerSecond*Gas(elapsedTime)/cfg.LeakGasCoeff), nil } diff --git a/vms/components/fees/manager.go b/vms/components/fees/manager.go index 4814cf47f7b2..a577c49839c3 100644 --- a/vms/components/fees/manager.go +++ b/vms/components/fees/manager.go @@ -18,9 +18,9 @@ type Manager struct { // Avax denominated gas price, i.e. fee per unit of complexity. gasPrice GasPrice - // cumulatedGas helps aggregating the gas consumed - // by a block so that we can verify it's not too big/build it properly. - cumulatedGas Gas + // blockGas helps aggregating the gas consumed in a single block + // so that we can verify it's not too big/build it properly. + blockGas Gas // currentExcessGas stores current excess gas, cumulated over time // to be updated once a block is accepted with cumulatedGas @@ -35,25 +35,25 @@ func NewManager(gasPrice GasPrice) *Manager { func NewUpdatedManager( feesConfig DynamicFeesConfig, - excessGas Gas, + currentExcessGas Gas, parentBlkTime, childBlkTime int64, ) (*Manager, error) { res := &Manager{ - currentExcessGas: excessGas, + currentExcessGas: currentExcessGas, } targetGas, err := TargetGas(feesConfig, parentBlkTime, childBlkTime) if err != nil { - return nil, fmt.Errorf("failed calculating target block gas: %w", err) + return nil, fmt.Errorf("failed calculating target gas: %w", err) } - if excessGas > targetGas { - excessGas -= targetGas + if currentExcessGas > targetGas { + currentExcessGas -= targetGas } else { - excessGas = ZeroGas + currentExcessGas = ZeroGas } - res.gasPrice = fakeExponential(feesConfig.MinGasPrice, excessGas, feesConfig.UpdateDenominator) + res.gasPrice = fakeExponential(feesConfig.MinGasPrice, currentExcessGas, feesConfig.UpdateDenominator) return res, nil } @@ -74,11 +74,11 @@ func (m *Manager) GetGasPrice() GasPrice { return m.gasPrice } -func (m *Manager) GetGas() Gas { - return m.cumulatedGas +func (m *Manager) GetBlockGas() Gas { + return m.blockGas } -func (m *Manager) GetCurrentExcessComplexity() Gas { +func (m *Manager) GetExcessGas() Gas { return m.currentExcessGas } @@ -87,31 +87,43 @@ func (m *Manager) CalculateFee(g Gas) (uint64, error) { return safemath.Mul64(uint64(m.gasPrice), uint64(g)) } -// CumulateComplexity tries to cumulate the consumed complexity [units]. Before -// actually cumulating them, it checks whether the result would breach [bounds]. +// CumulateGas 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 (m *Manager) CumulateComplexity(gas, bound Gas) error { +func (m *Manager) CumulateGas(gas, bound Gas) error { // Ensure we can consume (don't want partial update of values) - consumed, err := safemath.Add64(uint64(m.cumulatedGas), uint64(gas)) + blkGas, err := safemath.Add64(uint64(m.blockGas), uint64(gas)) if err != nil { return fmt.Errorf("%w: %w", errGasBoundBreached, err) } - if Gas(consumed) > bound { + if Gas(blkGas) > bound { return errGasBoundBreached } - m.cumulatedGas = Gas(consumed) + excessGas, err := safemath.Add64(uint64(m.currentExcessGas), uint64(gas)) + if err != nil { + return fmt.Errorf("%w: %w", errGasBoundBreached, err) + } + + m.blockGas = Gas(blkGas) + m.currentExcessGas = Gas(excessGas) return nil } // Sometimes, e.g. while building a tx, we'd like freedom to speculatively add complexity -// and to remove it later on. [RemoveComplexity] grants this freedom -func (m *Manager) RemoveComplexity(gasToRm Gas) error { - revertedGas, err := safemath.Sub(m.cumulatedGas, gasToRm) +// and to remove it later on. [RemoveGas] grants this freedom +func (m *Manager) RemoveGas(gasToRm Gas) error { + rBlkdGas, err := safemath.Sub(m.blockGas, gasToRm) if err != nil { - return fmt.Errorf("%w: current Gas %d, gas to revert %d", err, m.cumulatedGas, gasToRm) + return fmt.Errorf("%w: current Gas %d, gas to revert %d", err, m.blockGas, gasToRm) } - m.cumulatedGas = revertedGas + rExcessGas, err := safemath.Sub(m.currentExcessGas, gasToRm) + if err != nil { + return fmt.Errorf("%w: current Excess gas %d, gas to revert %d", err, m.currentExcessGas, gasToRm) + } + + m.blockGas = rBlkdGas + m.currentExcessGas = rExcessGas return nil } diff --git a/vms/components/fees/manager_test.go b/vms/components/fees/manager_test.go index 7fa8dee32d34..dce2052d8a4c 100644 --- a/vms/components/fees/manager_test.go +++ b/vms/components/fees/manager_test.go @@ -50,7 +50,7 @@ func TestFakeExponential(t *testing.T) { factor GasPrice numerator Gas denominator Gas - want uint64 + want GasPrice }{ // When numerator == 0 the return value should always equal the value of factor {1, 0, 1, 1}, diff --git a/vms/platformvm/block/builder/builder.go b/vms/platformvm/block/builder/builder.go index 81b686549581..a302309b07fa 100644 --- a/vms/platformvm/block/builder/builder.go +++ b/vms/platformvm/block/builder/builder.go @@ -25,7 +25,6 @@ import ( "github.com/ava-labs/avalanchego/vms/platformvm/txs/fee" "github.com/ava-labs/avalanchego/vms/platformvm/txs/mempool" - safemath "github.com/ava-labs/avalanchego/utils/math" commonfees "github.com/ava-labs/avalanchego/vms/components/fees" blockexecutor "github.com/ava-labs/avalanchego/vms/platformvm/block/executor" txexecutor "github.com/ava-labs/avalanchego/vms/platformvm/txs/executor" @@ -340,28 +339,26 @@ func packBlockTxs( var ( upgrades = backend.Config.UpgradeConfig isEActive = upgrades.IsEActivated(timestamp) + targetGas = commonfees.ZeroGas blockTxs []*txs.Tx inputs set.Set[ids.ID] ) - feeCfg, err := fee.GetDynamicConfig(isEActive) - if err != nil { - return nil, fmt.Errorf("failed retrieving dynamic fees config: %w", err) - } - feeCalculator, err := state.PickFeeCalculator(backend.Config, stateDiff, parentBlkTime) if err != nil { return nil, fmt.Errorf("failed picking fee calculator: %w", err) } - targetGas, err := commonfees.TargetGas(feeCfg, parentBlkTime.Unix(), timestamp.Unix()) - if err != nil { - return nil, fmt.Errorf("failed calculating target block complexity: %w", err) - } - targetExcessGas, err := safemath.Add64(uint64(targetGas), uint64(feeCalculator.GetCurrentExcessComplexity())) - if err != nil { - return nil, fmt.Errorf("failed calculating target excess complexity: %w", err) + if isEActive { + feeCfg, err := fee.GetDynamicConfig(isEActive) + if err != nil { + return nil, fmt.Errorf("failed retrieving dynamic fees config: %w", err) + } + targetGas, err = commonfees.TargetGas(feeCfg, parentBlkTime.Unix(), timestamp.Unix()) + if err != nil { + return nil, fmt.Errorf("failed calculating target block complexity: %w", err) + } } for { @@ -373,9 +370,9 @@ func packBlockTxs( txSize := len(tx.Bytes()) // pre e upgrade is active, we fill blocks till a target size - // post e upgrade is active, we fill blocks till a target complexity + // post e upgrade is active, we fill blocks till a target gas targetSizeReached := (!isEActive && txSize > remainingSize) || - (isEActive && feeCalculator.GetGas() >= commonfees.Gas(targetExcessGas)) + (isEActive && feeCalculator.GetBlockGas() >= targetGas) if targetSizeReached { break } diff --git a/vms/platformvm/block/executor/standard_block_test.go b/vms/platformvm/block/executor/standard_block_test.go index 502b347a4ba2..c80dc7380d53 100644 --- a/vms/platformvm/block/executor/standard_block_test.go +++ b/vms/platformvm/block/executor/standard_block_test.go @@ -58,7 +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().GetExcessComplexity().Return(commonfees.ZeroGas, nil).AnyTimes() + onParentAccept.EXPECT().GetExcessGas().Return(commonfees.ZeroGas, nil).AnyTimes() onParentAccept.EXPECT().GetCurrentGasCap().Return(commonfees.ZeroGas, nil).AnyTimes() // wrong height @@ -153,7 +153,7 @@ func TestBanffStandardBlockTimeVerification(t *testing.T) { } utxoID := utxo.InputID() onParentAccept.EXPECT().GetUTXO(utxoID).Return(utxo, nil).AnyTimes() - onParentAccept.EXPECT().GetExcessComplexity().Return(commonfees.ZeroGas, nil).AnyTimes() + onParentAccept.EXPECT().GetExcessGas().Return(commonfees.ZeroGas, nil).AnyTimes() onParentAccept.EXPECT().GetCurrentGasCap().Return(commonfees.ZeroGas, nil).AnyTimes() // Create the tx diff --git a/vms/platformvm/block/executor/verifier.go b/vms/platformvm/block/executor/verifier.go index 4b3df9f7689a..a1aaf5a99c17 100644 --- a/vms/platformvm/block/executor/verifier.go +++ b/vms/platformvm/block/executor/verifier.go @@ -10,13 +10,14 @@ import ( "github.com/ava-labs/avalanchego/chains/atomic" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils/set" - "github.com/ava-labs/avalanchego/vms/components/fees" "github.com/ava-labs/avalanchego/vms/platformvm/block" "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" + + commonfees "github.com/ava-labs/avalanchego/vms/components/fees" ) var ( @@ -251,8 +252,8 @@ func (v *verifier) ApricotAtomicBlock(b *block.ApricotAtomicBlock) error { inputs: atomicExecutor.Inputs, timestamp: atomicExecutor.OnAccept.GetTimestamp(), - blockGas: fees.ZeroGas, - excessGas: fees.ZeroGas, + blockGas: commonfees.ZeroGas, + excessGas: commonfees.ZeroGas, atomicRequests: atomicExecutor.AtomicRequests, } return nil @@ -423,9 +424,13 @@ func (v *verifier) proposalBlock( return err } - blkGas := feeCalculator.GetGas() - onCommitState.SetCurrentGasCap(currentGasCap + blkGas) - onAbortState.SetCurrentGasCap(currentGasCap + blkGas) + blkGas := feeCalculator.GetBlockGas() + nextGasCap := commonfees.Gas(0) + if currentGasCap > blkGas { + nextGasCap = currentGasCap - blkGas + } + onCommitState.SetCurrentGasCap(nextGasCap) + onAbortState.SetCurrentGasCap(nextGasCap) onCommitState.AddTx(b.Tx, status.Committed) onAbortState.AddTx(b.Tx, status.Aborted) @@ -450,7 +455,7 @@ func (v *verifier) proposalBlock( // always be the same as the Banff Proposal Block. timestamp: onAbortState.GetTimestamp(), blockGas: blkGas, - excessGas: feeCalculator.GetCurrentExcessComplexity(), + excessGas: feeCalculator.GetExcessGas(), atomicRequests: atomicRequests, } return nil @@ -476,8 +481,12 @@ func (v *verifier) standardBlock( blkID := b.ID() - blkGas := feeCalculator.GetGas() - onAcceptState.SetCurrentGasCap(currentGasCap + blkGas) + blkGas := feeCalculator.GetBlockGas() + nextGasCap := commonfees.Gas(0) + if currentGasCap > blkGas { + nextGasCap = currentGasCap - blkGas + } + onAcceptState.SetCurrentGasCap(nextGasCap) v.blkIDToState[blkID] = &blockState{ statelessBlock: b, @@ -487,7 +496,7 @@ func (v *verifier) standardBlock( timestamp: onAcceptState.GetTimestamp(), blockGas: blkGas, - excessGas: feeCalculator.GetCurrentExcessComplexity(), + excessGas: feeCalculator.GetExcessGas(), inputs: inputs, atomicRequests: atomicRequests, } @@ -554,7 +563,7 @@ func (v *verifier) processStandardTxs( } if v.txExecutorBackend.Config.UpgradeConfig.IsEActivated(state.GetTimestamp()) { - state.SetExcessComplexity(feeCalculator.GetCurrentExcessComplexity()) + state.SetExcessGas(feeCalculator.GetExcessGas()) } if numFuncs := len(funcs); numFuncs == 1 { diff --git a/vms/platformvm/service_test.go b/vms/platformvm/service_test.go index 15f56f4cfda1..db3198ed2668 100644 --- a/vms/platformvm/service_test.go +++ b/vms/platformvm/service_test.go @@ -82,35 +82,36 @@ func testReplayFeeCalculator(cfg *config.Config, parentBlkTime time.Time, state var ( childBlkTime = state.GetTimestamp() isEActive = cfg.UpgradeConfig.IsEActivated(childBlkTime) - - feeCalculator *fee.Calculator ) if !isEActive { - feeCalculator = fee.NewStaticCalculator(cfg.StaticFeeConfig, cfg.UpgradeConfig, childBlkTime) - } else { - 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) - } - excessComplexity, err := state.GetExcessComplexity() - if err != nil { - return nil, fmt.Errorf("failed retrieving excess complexity: %w", err) - } + return fee.NewStaticCalculator(cfg.StaticFeeConfig, cfg.UpgradeConfig, childBlkTime), nil + } - elapsedTime := childBlkTime.Unix() - parentBlkTime.Unix() - maxGas := commonfees.MaxGas(feesCfg, currentGasCap, uint64(elapsedTime)) - feesMan, err := commonfees.NewUpdatedManager(feesCfg, excessComplexity, parentBlkTime.Unix(), childBlkTime.Unix()) - if err != nil { - return nil, fmt.Errorf("failed updating fee manager: %w", err) - } - feeCalculator = fee.NewDynamicCalculator(feesMan, maxGas) + 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) } - return feeCalculator, nil + excessComplexity, err := state.GetExcessGas() + if err != nil { + return nil, fmt.Errorf("failed retrieving excess complexity: %w", err) + } + + gasCap, err := commonfees.MaxGas(feesCfg, currentGasCap, parentBlkTime, childBlkTime) + if err != nil { + return nil, fmt.Errorf("failed retrieving gas cap: %w", err) + } + + feesMan, err := commonfees.NewUpdatedManager(feesCfg, excessComplexity, parentBlkTime.Unix(), childBlkTime.Unix()) + if err != nil { + return nil, fmt.Errorf("failed updating fee manager: %w", err) + } + + return fee.NewDynamicCalculator(feesMan, gasCap), nil } func defaultService(t *testing.T) (*Service, *mutableSharedMemory, *txstest.WalletFactory) { @@ -1208,7 +1209,7 @@ func TestGetFeeRates(t *testing.T) { elapsedTime := time.Second targetGas := commonfees.Gas(uint64(feeCfg.GasTargetRate) * uint64(elapsedTime/time.Second)) gas := targetGas + commonfees.Gas(10) - service.vm.state.SetExcessComplexity(gas) + service.vm.state.SetExcessGas(gas) service.vm.ctx.Lock.Unlock() reply1 := GetGasPriceReply{} diff --git a/vms/platformvm/state/block_helpers.go b/vms/platformvm/state/block_helpers.go index bf4938c60929..45a6da68c11a 100644 --- a/vms/platformvm/state/block_helpers.go +++ b/vms/platformvm/state/block_helpers.go @@ -74,7 +74,7 @@ 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 mnodify [state] +// [PickFeeCalculator] does not modify [state] func PickFeeCalculator(cfg *config.Config, state Chain, parentBlkTime time.Time) (*fee.Calculator, error) { var ( childBlkTime = state.GetTimestamp() @@ -90,7 +90,7 @@ func PickFeeCalculator(cfg *config.Config, state Chain, parentBlkTime time.Time) return nil, fmt.Errorf("failed retrieving dynamic fees config: %w", err) } - feesMan, err := updatedFeeManager(feesCfg, state, parentBlkTime) + feesMan, err := updatedFeeManager(feesCfg, state, parentBlkTime, childBlkTime) if err != nil { return nil, fmt.Errorf("failed updating fee manager: %w", err) } @@ -100,18 +100,19 @@ func PickFeeCalculator(cfg *config.Config, state Chain, parentBlkTime time.Time) return nil, fmt.Errorf("failed retrieving gas cap: %w", err) } - elapsedTime := childBlkTime.Unix() - parentBlkTime.Unix() - maxGas := commonfees.MaxGas(feesCfg, currentGasCap, uint64(elapsedTime)) - feeCalculator := fee.NewDynamicCalculator(feesMan, maxGas) - return feeCalculator, nil + gasCap, err := commonfees.MaxGas(feesCfg, currentGasCap, parentBlkTime, childBlkTime) + if err != nil { + return nil, fmt.Errorf("failed retrieving gas cap: %w", err) + } + + return fee.NewDynamicCalculator(feesMan, gasCap), nil } -func updatedFeeManager(feesCfg commonfees.DynamicFeesConfig, state Chain, parentBlkTime time.Time) (*commonfees.Manager, error) { - excessComplexity, err := state.GetExcessComplexity() +func updatedFeeManager(feesCfg commonfees.DynamicFeesConfig, state Chain, parentBlkTime, childBlkTime time.Time) (*commonfees.Manager, error) { + excessComplexity, err := state.GetExcessGas() if err != nil { return nil, fmt.Errorf("failed retrieving excess complexity: %w", err) } - childBlkTime := state.GetTimestamp() feeManager, err := commonfees.NewUpdatedManager( feesCfg, excessComplexity, diff --git a/vms/platformvm/state/diff.go b/vms/platformvm/state/diff.go index fe1acea83486..a25845df0727 100644 --- a/vms/platformvm/state/diff.go +++ b/vms/platformvm/state/diff.go @@ -94,13 +94,13 @@ func NewDiffOn(parentState Chain) (Diff, error) { }) } -func (d *diff) GetExcessComplexity() (commonfees.Gas, error) { +func (d *diff) GetExcessGas() (commonfees.Gas, error) { if d.excessComplexity == nil { parentState, ok := d.stateVersions.GetState(d.parentID) if !ok { return commonfees.ZeroGas, fmt.Errorf("%w: %s", ErrMissingParentState, d.parentID) } - parentExcessComplexity, err := parentState.GetExcessComplexity() + parentExcessComplexity, err := parentState.GetExcessGas() if err != nil { return commonfees.ZeroGas, err } @@ -112,7 +112,7 @@ func (d *diff) GetExcessComplexity() (commonfees.Gas, error) { return *d.excessComplexity, nil } -func (d *diff) SetExcessComplexity(gas commonfees.Gas) { +func (d *diff) SetExcessGas(gas commonfees.Gas) { if d.excessComplexity == nil { d.excessComplexity = new(commonfees.Gas) } @@ -457,7 +457,7 @@ func (d *diff) DeleteUTXO(utxoID ids.ID) { func (d *diff) Apply(baseState Chain) error { baseState.SetTimestamp(d.timestamp) if d.excessComplexity != nil { - baseState.SetExcessComplexity(*d.excessComplexity) + baseState.SetExcessGas(*d.excessComplexity) } if d.currentGasCap != nil { baseState.SetCurrentGasCap(*d.currentGasCap) diff --git a/vms/platformvm/state/mock_state.go b/vms/platformvm/state/mock_state.go index c6a22f9c94e0..0c8bc8dc1126 100644 --- a/vms/platformvm/state/mock_state.go +++ b/vms/platformvm/state/mock_state.go @@ -273,19 +273,19 @@ func (mr *MockChainMockRecorder) GetDelegateeReward(arg0, arg1 any) *gomock.Call return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDelegateeReward", reflect.TypeOf((*MockChain)(nil).GetDelegateeReward), arg0, arg1) } -// GetExcessComplexity mocks base method. -func (m *MockChain) GetExcessComplexity() (fees.Gas, error) { +// GetExcessGas mocks base method. +func (m *MockChain) GetExcessGas() (fees.Gas, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetExcessComplexity") + ret := m.ctrl.Call(m, "GetExcessGas") ret0, _ := ret[0].(fees.Gas) ret1, _ := ret[1].(error) return ret0, ret1 } -// GetExcessComplexity indicates an expected call of GetExcessComplexity. -func (mr *MockChainMockRecorder) GetExcessComplexity() *gomock.Call { +// GetExcessGas indicates an expected call of GetExcessGas. +func (mr *MockChainMockRecorder) GetExcessGas() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetExcessComplexity", reflect.TypeOf((*MockChain)(nil).GetExcessComplexity)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetExcessGas", reflect.TypeOf((*MockChain)(nil).GetExcessGas)) } // GetPendingDelegatorIterator mocks base method. @@ -494,16 +494,16 @@ func (mr *MockChainMockRecorder) SetDelegateeReward(arg0, arg1, arg2 any) *gomoc return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetDelegateeReward", reflect.TypeOf((*MockChain)(nil).SetDelegateeReward), arg0, arg1, arg2) } -// SetExcessComplexity mocks base method. -func (m *MockChain) SetExcessComplexity(arg0 fees.Gas) { +// SetExcessGas mocks base method. +func (m *MockChain) SetExcessGas(arg0 fees.Gas) { m.ctrl.T.Helper() - m.ctrl.Call(m, "SetExcessComplexity", arg0) + m.ctrl.Call(m, "SetExcessGas", arg0) } -// SetExcessComplexity indicates an expected call of SetExcessComplexity. -func (mr *MockChainMockRecorder) SetExcessComplexity(arg0 any) *gomock.Call { +// SetExcessGas indicates an expected call of SetExcessGas. +func (mr *MockChainMockRecorder) SetExcessGas(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetExcessComplexity", reflect.TypeOf((*MockChain)(nil).SetExcessComplexity), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetExcessGas", reflect.TypeOf((*MockChain)(nil).SetExcessGas), arg0) } // SetSubnetOwner mocks base method. @@ -789,19 +789,19 @@ func (mr *MockDiffMockRecorder) GetDelegateeReward(arg0, arg1 any) *gomock.Call return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDelegateeReward", reflect.TypeOf((*MockDiff)(nil).GetDelegateeReward), arg0, arg1) } -// GetExcessComplexity mocks base method. -func (m *MockDiff) GetExcessComplexity() (fees.Gas, error) { +// GetExcessGas mocks base method. +func (m *MockDiff) GetExcessGas() (fees.Gas, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetExcessComplexity") + ret := m.ctrl.Call(m, "GetExcessGas") ret0, _ := ret[0].(fees.Gas) ret1, _ := ret[1].(error) return ret0, ret1 } -// GetExcessComplexity indicates an expected call of GetExcessComplexity. -func (mr *MockDiffMockRecorder) GetExcessComplexity() *gomock.Call { +// GetExcessGas indicates an expected call of GetExcessGas. +func (mr *MockDiffMockRecorder) GetExcessGas() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetExcessComplexity", reflect.TypeOf((*MockDiff)(nil).GetExcessComplexity)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetExcessGas", reflect.TypeOf((*MockDiff)(nil).GetExcessGas)) } // GetPendingDelegatorIterator mocks base method. @@ -1010,16 +1010,16 @@ func (mr *MockDiffMockRecorder) SetDelegateeReward(arg0, arg1, arg2 any) *gomock return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetDelegateeReward", reflect.TypeOf((*MockDiff)(nil).SetDelegateeReward), arg0, arg1, arg2) } -// SetExcessComplexity mocks base method. -func (m *MockDiff) SetExcessComplexity(arg0 fees.Gas) { +// SetExcessGas mocks base method. +func (m *MockDiff) SetExcessGas(arg0 fees.Gas) { m.ctrl.T.Helper() - m.ctrl.Call(m, "SetExcessComplexity", arg0) + m.ctrl.Call(m, "SetExcessGas", arg0) } -// SetExcessComplexity indicates an expected call of SetExcessComplexity. -func (mr *MockDiffMockRecorder) SetExcessComplexity(arg0 any) *gomock.Call { +// SetExcessGas indicates an expected call of SetExcessGas. +func (mr *MockDiffMockRecorder) SetExcessGas(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetExcessComplexity", reflect.TypeOf((*MockDiff)(nil).SetExcessComplexity), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetExcessGas", reflect.TypeOf((*MockDiff)(nil).SetExcessGas), arg0) } // SetSubnetOwner mocks base method. @@ -1430,19 +1430,19 @@ func (mr *MockStateMockRecorder) GetDelegateeReward(arg0, arg1 any) *gomock.Call return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDelegateeReward", reflect.TypeOf((*MockState)(nil).GetDelegateeReward), arg0, arg1) } -// GetExcessComplexity mocks base method. -func (m *MockState) GetExcessComplexity() (fees.Gas, error) { +// GetExcessGas mocks base method. +func (m *MockState) GetExcessGas() (fees.Gas, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetExcessComplexity") + ret := m.ctrl.Call(m, "GetExcessGas") ret0, _ := ret[0].(fees.Gas) ret1, _ := ret[1].(error) return ret0, ret1 } -// GetExcessComplexity indicates an expected call of GetExcessComplexity. -func (mr *MockStateMockRecorder) GetExcessComplexity() *gomock.Call { +// GetExcessGas indicates an expected call of GetExcessGas. +func (mr *MockStateMockRecorder) GetExcessGas() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetExcessComplexity", reflect.TypeOf((*MockState)(nil).GetExcessComplexity)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetExcessGas", reflect.TypeOf((*MockState)(nil).GetExcessGas)) } // GetLastAccepted mocks base method. @@ -1755,16 +1755,16 @@ func (mr *MockStateMockRecorder) SetDelegateeReward(arg0, arg1, arg2 any) *gomoc return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetDelegateeReward", reflect.TypeOf((*MockState)(nil).SetDelegateeReward), arg0, arg1, arg2) } -// SetExcessComplexity mocks base method. -func (m *MockState) SetExcessComplexity(arg0 fees.Gas) { +// SetExcessGas mocks base method. +func (m *MockState) SetExcessGas(arg0 fees.Gas) { m.ctrl.T.Helper() - m.ctrl.Call(m, "SetExcessComplexity", arg0) + m.ctrl.Call(m, "SetExcessGas", arg0) } -// SetExcessComplexity indicates an expected call of SetExcessComplexity. -func (mr *MockStateMockRecorder) SetExcessComplexity(arg0 any) *gomock.Call { +// SetExcessGas indicates an expected call of SetExcessGas. +func (mr *MockStateMockRecorder) SetExcessGas(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetExcessComplexity", reflect.TypeOf((*MockState)(nil).SetExcessComplexity), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetExcessGas", reflect.TypeOf((*MockState)(nil).SetExcessGas), arg0) } // SetHeight mocks base method. diff --git a/vms/platformvm/state/state.go b/vms/platformvm/state/state.go index 96568fd6b75b..d2932690a0d6 100644 --- a/vms/platformvm/state/state.go +++ b/vms/platformvm/state/state.go @@ -101,8 +101,8 @@ type Chain interface { avax.UTXOGetter avax.UTXODeleter - GetExcessComplexity() (commonfees.Gas, error) - SetExcessComplexity(commonfees.Gas) + GetExcessGas() (commonfees.Gas, error) + SetExcessGas(commonfees.Gas) GetCurrentGasCap() (commonfees.Gas, error) SetCurrentGasCap(commonfees.Gas) @@ -1012,11 +1012,11 @@ func (s *state) GetStartTime(nodeID ids.NodeID, subnetID ids.ID) (time.Time, err return staker.StartTime, nil } -func (s *state) GetExcessComplexity() (commonfees.Gas, error) { +func (s *state) GetExcessGas() (commonfees.Gas, error) { return s.excessComplexity, nil } -func (s *state) SetExcessComplexity(gas commonfees.Gas) { +func (s *state) SetExcessGas(gas commonfees.Gas) { s.excessComplexity = gas } diff --git a/vms/platformvm/txs/fee/calculator.go b/vms/platformvm/txs/fee/calculator.go index 036fa3aea273..3b0ebb3cefde 100644 --- a/vms/platformvm/txs/fee/calculator.go +++ b/vms/platformvm/txs/fee/calculator.go @@ -81,25 +81,25 @@ func (c *Calculator) RemoveFeesFor(unitsToRm fees.Dimensions) (uint64, error) { return c.c.removeFeesFor(unitsToRm) } -func (c *Calculator) GetGas() fees.Gas { +func (c *Calculator) GetGasPrice() fees.GasPrice { if c.c.feeManager != nil { - return c.c.feeManager.GetGas() + return c.c.feeManager.GetGasPrice() } - return fees.ZeroGas + return fees.ZeroGasPrice } -func (c *Calculator) GetCurrentExcessComplexity() fees.Gas { +func (c *Calculator) GetBlockGas() fees.Gas { if c.c.feeManager != nil { - return c.c.feeManager.GetCurrentExcessComplexity() + return c.c.feeManager.GetBlockGas() } return fees.ZeroGas } -func (c *Calculator) GetGasPrice() fees.GasPrice { +func (c *Calculator) GetExcessGas() fees.Gas { if c.c.feeManager != nil { - return c.c.feeManager.GetGasPrice() + return c.c.feeManager.GetExcessGas() } - return fees.ZeroGasPrice + return fees.ZeroGas } type calculator struct { @@ -418,7 +418,7 @@ func (c *calculator) addFeesFor(complexity fees.Dimensions) (uint64, error) { return 0, fmt.Errorf("failed adding fees: %w", err) } - if err := c.feeManager.CumulateComplexity(txGas, c.maxGas); err != nil { + if err := c.feeManager.CumulateGas(txGas, c.maxGas); err != nil { return 0, fmt.Errorf("failed cumulating complexity: %w", err) } fee, err := c.feeManager.CalculateFee(txGas) @@ -444,7 +444,7 @@ func (c *calculator) removeFeesFor(unitsToRm fees.Dimensions) (uint64, error) { return 0, fmt.Errorf("failed adding fees: %w", err) } - if err := c.feeManager.RemoveComplexity(txGas); err != nil { + if err := c.feeManager.RemoveGas(txGas); err != nil { return 0, fmt.Errorf("failed removing units: %w", err) } fee, err := c.feeManager.CalculateFee(txGas) diff --git a/vms/platformvm/txs/fee/calculator_test.go b/vms/platformvm/txs/fee/calculator_test.go index ac5c150482c5..ae2db7a4c94c 100644 --- a/vms/platformvm/txs/fee/calculator_test.go +++ b/vms/platformvm/txs/fee/calculator_test.go @@ -59,25 +59,25 @@ func TestAddAndRemoveFees(t *testing.T) { feeDelta, err := fc.AddFeesFor(units) r.NoError(err) - r.Equal(gas, fc.c.feeManager.GetGas()) + r.Equal(gas, fc.c.feeManager.GetBlockGas()) r.NotZero(feeDelta) r.Equal(feeDelta, fc.c.fee) feeDelta2, err := fc.AddFeesFor(units) r.NoError(err) - r.Equal(doubleGas, fc.c.feeManager.GetGas()) + r.Equal(doubleGas, fc.c.feeManager.GetBlockGas()) r.Equal(feeDelta, feeDelta2) r.Equal(feeDelta+feeDelta2, fc.c.fee) feeDelta3, err := fc.RemoveFeesFor(units) r.NoError(err) - r.Equal(gas, fc.c.feeManager.GetGas()) + r.Equal(gas, fc.c.feeManager.GetBlockGas()) r.Equal(feeDelta, feeDelta3) r.Equal(feeDelta, fc.c.fee) feeDelta4, err := fc.RemoveFeesFor(units) r.NoError(err) - r.Zero(fc.c.feeManager.GetGas()) + r.Zero(fc.c.feeManager.GetBlockGas()) r.Equal(feeDelta, feeDelta4) r.Zero(fc.c.fee) } @@ -141,7 +141,7 @@ func TestTxFees(t *testing.T) { unsignedAndSignedTx: addSubnetValidatorTx, checksF: func(t *testing.T, fc *calculator) { require.Equal(t, 19_110*units.NanoAvax, fc.fee) - require.Equal(t, fees.Gas(1911), fc.feeManager.GetGas()) + require.Equal(t, fees.Gas(1911), fc.feeManager.GetBlockGas()) }, }, { @@ -185,7 +185,7 @@ func TestTxFees(t *testing.T) { expectedError: nil, checksF: func(t *testing.T, fc *calculator) { require.Equal(t, 19_540*units.NanoAvax, fc.fee) - require.Equal(t, fees.Gas(1_954), fc.feeManager.GetGas()) + require.Equal(t, fees.Gas(1_954), fc.feeManager.GetBlockGas()) }, }, { @@ -221,7 +221,7 @@ func TestTxFees(t *testing.T) { expectedError: nil, checksF: func(t *testing.T, fc *calculator) { require.Equal(t, 18_590*units.NanoAvax, fc.fee) - require.Equal(t, fees.Gas(1_859), fc.feeManager.GetGas()) + require.Equal(t, fees.Gas(1_859), fc.feeManager.GetBlockGas()) }, }, { @@ -249,7 +249,7 @@ func TestTxFees(t *testing.T) { expectedError: nil, checksF: func(t *testing.T, fc *calculator) { require.Equal(t, 18_870*units.NanoAvax, fc.fee) - require.Equal(t, fees.Gas(1_887), fc.feeManager.GetGas()) + require.Equal(t, fees.Gas(1_887), fc.feeManager.GetBlockGas()) }, }, { @@ -277,7 +277,7 @@ func TestTxFees(t *testing.T) { expectedError: nil, checksF: func(t *testing.T, fc *calculator) { require.Equal(t, 19_720*units.NanoAvax, fc.fee) - require.Equal(t, fees.Gas(1_972), fc.feeManager.GetGas()) + require.Equal(t, fees.Gas(1_972), fc.feeManager.GetBlockGas()) }, }, { @@ -305,7 +305,7 @@ func TestTxFees(t *testing.T) { expectedError: nil, checksF: func(t *testing.T, fc *calculator) { require.Equal(t, 19_030*units.NanoAvax, fc.fee) - require.Equal(t, fees.Gas(1_903), fc.feeManager.GetGas()) + require.Equal(t, fees.Gas(1_903), fc.feeManager.GetBlockGas()) }, }, { @@ -349,7 +349,7 @@ func TestTxFees(t *testing.T) { expectedError: nil, checksF: func(t *testing.T, fc *calculator) { require.Equal(t, 23_170*units.NanoAvax, fc.fee) - require.Equal(t, fees.Gas(2_317), fc.feeManager.GetGas()) + require.Equal(t, fees.Gas(2_317), fc.feeManager.GetBlockGas()) }, }, { @@ -363,7 +363,7 @@ func TestTxFees(t *testing.T) { expectedError: nil, checksF: func(t *testing.T, fc *calculator) { require.Equal(t, 23_170*units.NanoAvax, fc.fee) - require.Equal(t, fees.Gas(2_317), fc.feeManager.GetGas()) + require.Equal(t, fees.Gas(2_317), fc.feeManager.GetBlockGas()) }, }, { @@ -410,7 +410,7 @@ func TestTxFees(t *testing.T) { expectedError: nil, checksF: func(t *testing.T, fc *calculator) { require.Equal(t, 21_250*units.NanoAvax, fc.fee) - require.Equal(t, fees.Gas(2_125), fc.feeManager.GetGas()) + require.Equal(t, fees.Gas(2_125), fc.feeManager.GetBlockGas()) }, }, { @@ -422,7 +422,7 @@ func TestTxFees(t *testing.T) { expectedError: nil, checksF: func(t *testing.T, fc *calculator) { require.Equal(t, 21_250*units.NanoAvax, fc.fee) - require.Equal(t, fees.Gas(2_125), fc.feeManager.GetGas()) + require.Equal(t, fees.Gas(2_125), fc.feeManager.GetBlockGas()) }, }, { @@ -454,7 +454,7 @@ func TestTxFees(t *testing.T) { expectedError: nil, checksF: func(t *testing.T, fc *calculator) { require.Equal(t, 18_190*units.NanoAvax, fc.fee) - require.Equal(t, fees.Gas(1_819), fc.feeManager.GetGas()) + require.Equal(t, fees.Gas(1_819), fc.feeManager.GetBlockGas()) }, }, { @@ -482,7 +482,7 @@ func TestTxFees(t *testing.T) { expectedError: nil, checksF: func(t *testing.T, fc *calculator) { require.Equal(t, 31_230*units.NanoAvax, fc.fee) - require.Equal(t, fees.Gas(3_123), fc.feeManager.GetGas()) + require.Equal(t, fees.Gas(3_123), fc.feeManager.GetBlockGas()) }, }, { @@ -510,7 +510,7 @@ func TestTxFees(t *testing.T) { expectedError: nil, checksF: func(t *testing.T, fc *calculator) { require.Equal(t, 20_410*units.NanoAvax, fc.fee) - require.Equal(t, fees.Gas(2_041), fc.feeManager.GetGas()) + require.Equal(t, fees.Gas(2_041), fc.feeManager.GetBlockGas()) }, }, { From 4da1199d77c0c04c7d45a96612e9acef5006a637 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Tue, 18 Jun 2024 10:32:25 +0200 Subject: [PATCH 174/190] simplified dimensions --- vms/components/fees/dimensions.go | 61 -------------------------- vms/components/fees/dimensions_test.go | 21 --------- 2 files changed, 82 deletions(-) delete mode 100644 vms/components/fees/dimensions_test.go diff --git a/vms/components/fees/dimensions.go b/vms/components/fees/dimensions.go index dc57c332eefd..e5c025b7a4c4 100644 --- a/vms/components/fees/dimensions.go +++ b/vms/components/fees/dimensions.go @@ -4,10 +4,6 @@ package fees import ( - "encoding/binary" - "errors" - "fmt" - safemath "github.com/ava-labs/avalanchego/utils/math" ) @@ -17,29 +13,13 @@ const ( UTXOWrite Dimension = 2 // includes delete Compute Dimension = 3 // signatures checks, tx-specific - bandwidthString string = "Bandwidth" - utxosReadString string = "UTXOsRead" - utxosWriteString string = "UTXOsWrite" - computeString string = "Compute" - FeeDimensions = 4 - - uint64Len = 8 ) var ( - errUnknownDimension = errors.New("unknown dimension") - ZeroGas = Gas(0) ZeroGasPrice = GasPrice(0) Empty = Dimensions{} - - DimensionStrings = []string{ - bandwidthString, - utxosReadString, - utxosWriteString, - computeString, - } ) type ( @@ -50,14 +30,6 @@ type ( Dimensions [FeeDimensions]uint64 ) -func (d Dimension) String() (string, error) { - if d < 0 || d >= FeeDimensions { - return "", errUnknownDimension - } - - return DimensionStrings[d], nil -} - func Add(lhs, rhs Dimensions) (Dimensions, error) { var res Dimensions for i := 0; i < FeeDimensions; i++ { @@ -84,36 +56,3 @@ func ScalarProd(lhs, rhs Dimensions) (Gas, error) { } return Gas(res), nil } - -// [Compare] returns true only if rhs[i] >= lhs[i] for each dimensions -// Arrays ordering is not total, so we avoided naming [Compare] as [Less] -// to discourage improper use -func Compare(lhs, rhs Dimensions) bool { - for i := 0; i < FeeDimensions; i++ { - if lhs[i] > rhs[i] { - return false - } - } - return true -} - -func (d *Dimensions) Bytes() []byte { - res := make([]byte, FeeDimensions*uint64Len) - for i := Dimension(0); i < FeeDimensions; i++ { - binary.BigEndian.PutUint64(res[i*uint64Len:], d[i]) - } - return res -} - -func (d *Dimensions) FromBytes(b []byte) error { - if len(b) != FeeDimensions*uint64Len { - return fmt.Errorf("unexpected bytes length: expected %d, actual %d", - FeeDimensions*uint64Len, - len(b), - ) - } - for i := Dimension(0); i < FeeDimensions; i++ { - d[i] = binary.BigEndian.Uint64(b[i*uint64Len : (i+1)*uint64Len]) - } - return nil -} diff --git a/vms/components/fees/dimensions_test.go b/vms/components/fees/dimensions_test.go deleted file mode 100644 index 2f2dcd3d12a9..000000000000 --- a/vms/components/fees/dimensions_test.go +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. -// See the file LICENSE for licensing terms. - -package fees - -import ( - "math" - "testing" - - "github.com/stretchr/testify/require" -) - -func TestMarshalUnmarshalDimensions(t *testing.T) { - require := require.New(t) - - input := Dimensions{0, 1, 2024, math.MaxUint64} - bytes := input.Bytes() - var output Dimensions - require.NoError(output.FromBytes(bytes)) - require.Equal(input, output) -} From 0ebb3186c33c93377ae09834a39acb7e384ae8d7 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Tue, 18 Jun 2024 12:17:59 +0200 Subject: [PATCH 175/190] minor refactoring --- vms/components/fees/config.go | 12 ++++++++++-- vms/platformvm/block/executor/verifier.go | 10 ++-------- vms/platformvm/service_test.go | 2 +- vms/platformvm/state/block_helpers.go | 2 +- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/vms/components/fees/config.go b/vms/components/fees/config.go index 82d365c8d17b..120874365dd6 100644 --- a/vms/components/fees/config.go +++ b/vms/components/fees/config.go @@ -47,8 +47,8 @@ func (c *DynamicFeesConfig) Validate() error { } // We cap the maximum gas consumed by time with a leaky bucket approach -// MaxGas = min (MaxGas + MaxGasPerSecond/LeakGasCoeff*ElapsedTime, MaxGasPerSecond) -func MaxGas(cfg DynamicFeesConfig, currentGasCapacity Gas, parentBlkTime, childBlkTime time.Time) (Gas, error) { +// GasCap = min (GasCap + MaxGasPerSecond/LeakGasCoeff*ElapsedTime, MaxGasPerSecond) +func GasCap(cfg DynamicFeesConfig, currentGasCapacity Gas, parentBlkTime, childBlkTime time.Time) (Gas, error) { if !childBlkTime.After(parentBlkTime) { return ZeroGas, fmt.Errorf("unexpected block times, parentBlkTim %v, childBlkTime %v", parentBlkTime, childBlkTime) } @@ -60,3 +60,11 @@ func MaxGas(cfg DynamicFeesConfig, currentGasCapacity Gas, parentBlkTime, childB return min(cfg.MaxGasPerSecond, currentGasCapacity+cfg.MaxGasPerSecond*Gas(elapsedTime)/cfg.LeakGasCoeff), nil } + +func UpdateGasCap(currentGasCap, blkGas Gas) Gas { + nextGasCap := Gas(0) + if currentGasCap > blkGas { + nextGasCap = currentGasCap - blkGas + } + return nextGasCap +} diff --git a/vms/platformvm/block/executor/verifier.go b/vms/platformvm/block/executor/verifier.go index a1aaf5a99c17..d89d7511bc84 100644 --- a/vms/platformvm/block/executor/verifier.go +++ b/vms/platformvm/block/executor/verifier.go @@ -425,10 +425,7 @@ func (v *verifier) proposalBlock( } blkGas := feeCalculator.GetBlockGas() - nextGasCap := commonfees.Gas(0) - if currentGasCap > blkGas { - nextGasCap = currentGasCap - blkGas - } + nextGasCap := commonfees.UpdateGasCap(currentGasCap, blkGas) onCommitState.SetCurrentGasCap(nextGasCap) onAbortState.SetCurrentGasCap(nextGasCap) @@ -482,10 +479,7 @@ func (v *verifier) standardBlock( blkID := b.ID() blkGas := feeCalculator.GetBlockGas() - nextGasCap := commonfees.Gas(0) - if currentGasCap > blkGas { - nextGasCap = currentGasCap - blkGas - } + nextGasCap := commonfees.UpdateGasCap(currentGasCap, blkGas) onAcceptState.SetCurrentGasCap(nextGasCap) v.blkIDToState[blkID] = &blockState{ diff --git a/vms/platformvm/service_test.go b/vms/platformvm/service_test.go index db3198ed2668..c1fc2e7465cb 100644 --- a/vms/platformvm/service_test.go +++ b/vms/platformvm/service_test.go @@ -101,7 +101,7 @@ func testReplayFeeCalculator(cfg *config.Config, parentBlkTime time.Time, state return nil, fmt.Errorf("failed retrieving excess complexity: %w", err) } - gasCap, err := commonfees.MaxGas(feesCfg, currentGasCap, parentBlkTime, childBlkTime) + gasCap, err := commonfees.GasCap(feesCfg, currentGasCap, parentBlkTime, childBlkTime) if err != nil { return nil, fmt.Errorf("failed retrieving gas cap: %w", err) } diff --git a/vms/platformvm/state/block_helpers.go b/vms/platformvm/state/block_helpers.go index 45a6da68c11a..77b6f40a8f3b 100644 --- a/vms/platformvm/state/block_helpers.go +++ b/vms/platformvm/state/block_helpers.go @@ -100,7 +100,7 @@ func PickFeeCalculator(cfg *config.Config, state Chain, parentBlkTime time.Time) return nil, fmt.Errorf("failed retrieving gas cap: %w", err) } - gasCap, err := commonfees.MaxGas(feesCfg, currentGasCap, parentBlkTime, childBlkTime) + gasCap, err := commonfees.GasCap(feesCfg, currentGasCap, parentBlkTime, childBlkTime) if err != nil { return nil, fmt.Errorf("failed retrieving gas cap: %w", err) } From eeb625d50ec438e09fa99f6ab4e4ca8d6c225473 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Tue, 18 Jun 2024 17:00:22 +0200 Subject: [PATCH 176/190] fixed GetNextGasData API --- tests/e2e/p/dynamic_fees.go | 8 ++++---- tests/e2e/p/workflow.go | 2 +- vms/components/fee/manager.go | 4 ++++ vms/platformvm/client.go | 9 +++++---- vms/platformvm/service.go | 6 ++++-- vms/platformvm/service_test.go | 6 +++--- vms/platformvm/txs/fee/calculator_api.go | 5 +++++ vms/platformvm/txs/fee/dynamic_calculator.go | 2 ++ vms/platformvm/txs/fee/static_calculator.go | 8 +++++--- wallet/chain/p/wallet.go | 21 ++++++++------------ 10 files changed, 41 insertions(+), 30 deletions(-) diff --git a/tests/e2e/p/dynamic_fees.go b/tests/e2e/p/dynamic_fees.go index adcdbb371b47..b6edcc6beb9a 100644 --- a/tests/e2e/p/dynamic_fees.go +++ b/tests/e2e/p/dynamic_fees.go @@ -63,7 +63,7 @@ var _ = ginkgo.Describe("[Dynamic Fees]", func() { tests.Outf("{{blue}} P-chain balance before P->X export: %d {{/}}\n", pStartBalance) ginkgo.By("checking that initial fee values match with configured ones", func() { - nextFeeRates, err := pChainClient.GetNextGasPrice(e2e.DefaultContext()) + nextFeeRates, _, err := pChainClient.GetNextGasData(e2e.DefaultContext()) require.NoError(err) require.Equal(customDynamicFeesConfig.MinGasPrice, nextFeeRates) }) @@ -88,7 +88,7 @@ var _ = ginkgo.Describe("[Dynamic Fees]", func() { subnetID = subnetTx.ID() }) - nextFeeRates, err := pChainClient.GetNextGasPrice(e2e.DefaultContext()) + nextFeeRates, _, err := pChainClient.GetNextGasData(e2e.DefaultContext()) require.NoError(err) tests.Outf("{{blue}} next fee rates: %v {{/}}\n", nextFeeRates) @@ -109,7 +109,7 @@ var _ = ginkgo.Describe("[Dynamic Fees]", func() { ) require.NoError(err) - updatedFeeRates, err := pChainClient.GetNextGasPrice(e2e.DefaultContext()) + updatedFeeRates, _, err := pChainClient.GetNextGasData(e2e.DefaultContext()) require.NoError(err) tests.Outf("{{blue}} current fee rates: %v {{/}}\n", updatedFeeRates) @@ -125,7 +125,7 @@ var _ = ginkgo.Describe("[Dynamic Fees]", func() { initialFeeRates := nextFeeRates e2e.Eventually(func() bool { var err error - nextFeeRates, err = pChainClient.GetNextGasPrice(e2e.DefaultContext()) + nextFeeRates, _, err = pChainClient.GetNextGasData(e2e.DefaultContext()) require.NoError(err) tests.Outf("{{blue}} next fee rates: %v {{/}}\n", nextFeeRates) return nextFeeRates < initialFeeRates diff --git a/tests/e2e/p/workflow.go b/tests/e2e/p/workflow.go index 6f898b3a4028..a2c9bc6e0dfd 100644 --- a/tests/e2e/p/workflow.go +++ b/tests/e2e/p/workflow.go @@ -141,7 +141,7 @@ var _ = e2e.DescribePChain("[Workflow]", func() { pChainExportFee := uint64(0) ginkgo.By("export avax from P to X chain", func() { - nextGasPrice, err := pChainClient.GetNextGasPrice(e2e.DefaultContext()) + nextGasPrice, _, err := pChainClient.GetNextGasData(e2e.DefaultContext()) require.NoError(err) tx, err := pWallet.IssueExportTx( diff --git a/vms/components/fee/manager.go b/vms/components/fee/manager.go index b2cefaeecbbd..ca748129c9d1 100644 --- a/vms/components/fee/manager.go +++ b/vms/components/fee/manager.go @@ -87,6 +87,10 @@ func (m *Manager) GetExcessGas() Gas { return m.currentExcessGas } +func (m *Manager) GetGasCap() Gas { + return m.gasCap +} + // CalculateFee must be a stateless method func (m *Manager) CalculateFee(g Gas) (uint64, error) { return safemath.Mul64(uint64(m.gasPrice), uint64(g)) diff --git a/vms/platformvm/client.go b/vms/platformvm/client.go index f793efd103a3..e1e70d33bd23 100644 --- a/vms/platformvm/client.go +++ b/vms/platformvm/client.go @@ -133,8 +133,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) - // GetNextGasPrice returns the gas price that a transaction must pay to be accepted now - GetNextGasPrice(ctx context.Context, options ...rpc.Option) (commonfee.GasPrice, 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) } // Client implementation for interacting with the P Chain endpoint @@ -550,8 +551,8 @@ func (c *client) GetBlockByHeight(ctx context.Context, height uint64, options .. return formatting.Decode(res.Encoding, res.Block) } -func (c *client) GetNextGasPrice(ctx context.Context, options ...rpc.Option) (commonfee.GasPrice, error) { +func (c *client) GetNextGasData(ctx context.Context, options ...rpc.Option) (commonfee.GasPrice, commonfee.Gas, error) { res := &GetGasPriceReply{} err := c.requester.SendRequest(ctx, "platform.getNextGasPrice", struct{}{}, res, options...) - return res.NextGasPrice, err + return res.NextGasPrice, res.NextGasCap, err } diff --git a/vms/platformvm/service.go b/vms/platformvm/service.go index 5ba3a720e5d6..deefaafad2d2 100644 --- a/vms/platformvm/service.go +++ b/vms/platformvm/service.go @@ -1832,13 +1832,14 @@ func (s *Service) GetBlockByHeight(_ *http.Request, args *api.GetBlockByHeightAr // GetGasPriceReply is the response from GetFeeRates type GetGasPriceReply struct { NextGasPrice commonfee.GasPrice `json:"nextGasPrice"` + NextGasCap commonfee.Gas `json:"nextGasCap"` } // GetNextFeeRates returns the next fee rates that a transaction must pay to be accepted now -func (s *Service) GetNextGasPrice(_ *http.Request, _ *struct{}, reply *GetGasPriceReply) error { +func (s *Service) GetNextGasData(_ *http.Request, _ *struct{}, reply *GetGasPriceReply) error { s.vm.ctx.Log.Debug("API called", zap.String("service", "platform"), - zap.String("method", "getNextGasPrice"), + zap.String("method", "getNextGasData"), ) s.vm.ctx.Lock.Lock() @@ -1867,6 +1868,7 @@ func (s *Service) GetNextGasPrice(_ *http.Request, _ *struct{}, reply *GetGasPri return err } reply.NextGasPrice = feeCalculator.GetGasPrice() + reply.NextGasCap = feeCalculator.GetGasCap() return nil } diff --git a/vms/platformvm/service_test.go b/vms/platformvm/service_test.go index 762493fb1f76..c64877120792 100644 --- a/vms/platformvm/service_test.go +++ b/vms/platformvm/service_test.go @@ -1201,7 +1201,7 @@ func TestGetFeeRates(t *testing.T) { // initially minimal fees reply0 := GetGasPriceReply{} - require.NoError(service.GetNextGasPrice(nil, nil, &reply0)) + require.NoError(service.GetNextGasData(nil, nil, &reply0)) require.Equal(feeCfg.MinGasPrice, reply0.NextGasPrice) // let cumulated complexity go above target. Fee rates will go up @@ -1213,7 +1213,7 @@ func TestGetFeeRates(t *testing.T) { service.vm.ctx.Lock.Unlock() reply1 := GetGasPriceReply{} - require.NoError(service.GetNextGasPrice(nil, nil, &reply1)) + require.NoError(service.GetNextGasData(nil, nil, &reply1)) highGasPrice := reply1.NextGasPrice require.Greater(highGasPrice, feeCfg.MinGasPrice) @@ -1224,6 +1224,6 @@ func TestGetFeeRates(t *testing.T) { service.vm.ctx.Lock.Unlock() reply2 := GetGasPriceReply{} - require.NoError(service.GetNextGasPrice(nil, nil, &reply2)) + require.NoError(service.GetNextGasData(nil, nil, &reply2)) require.Less(reply2.NextGasPrice, highGasPrice) } diff --git a/vms/platformvm/txs/fee/calculator_api.go b/vms/platformvm/txs/fee/calculator_api.go index fa7020702ec5..4cfc9694adde 100644 --- a/vms/platformvm/txs/fee/calculator_api.go +++ b/vms/platformvm/txs/fee/calculator_api.go @@ -47,6 +47,10 @@ func (c *Calculator) GetExcessGas() fee.Gas { return c.b.getExcessGas() } +func (c *Calculator) GetGasCap() fee.Gas { + return c.b.getGasCap() +} + // backend is the interfaces that any fee backend must implement type backend interface { txs.Visitor @@ -58,6 +62,7 @@ type backend interface { getGasPrice() fee.GasPrice getBlockGas() fee.Gas getExcessGas() fee.Gas + getGasCap() fee.Gas setCredentials(creds []verify.Verifiable) computeFee(tx txs.UnsignedTx, creds []verify.Verifiable) (uint64, error) isEActive() bool diff --git a/vms/platformvm/txs/fee/dynamic_calculator.go b/vms/platformvm/txs/fee/dynamic_calculator.go index c2c7a969f960..f368571ab1bb 100644 --- a/vms/platformvm/txs/fee/dynamic_calculator.go +++ b/vms/platformvm/txs/fee/dynamic_calculator.go @@ -318,6 +318,8 @@ func (c *dynamicCalculator) getBlockGas() fee.Gas { return c.feeManager.GetBlock func (c *dynamicCalculator) getExcessGas() fee.Gas { return c.feeManager.GetExcessGas() } +func (c *dynamicCalculator) getGasCap() fee.Gas { return c.feeManager.GetGasCap() } + func (c *dynamicCalculator) setCredentials(creds []verify.Verifiable) { c.credentials = creds } diff --git a/vms/platformvm/txs/fee/static_calculator.go b/vms/platformvm/txs/fee/static_calculator.go index f9c67dc5524d..417487749879 100644 --- a/vms/platformvm/txs/fee/static_calculator.go +++ b/vms/platformvm/txs/fee/static_calculator.go @@ -157,11 +157,13 @@ func (*staticCalculator) removeFeesFor(fee.Dimensions) (uint64, error) { return 0, errComplexityNotPriced } -func (*staticCalculator) getGasPrice() fee.GasPrice { return 0 } +func (*staticCalculator) getGasPrice() fee.GasPrice { return fee.ZeroGasPrice } -func (*staticCalculator) getBlockGas() fee.Gas { return 0 } +func (*staticCalculator) getBlockGas() fee.Gas { return fee.ZeroGas } -func (*staticCalculator) getExcessGas() fee.Gas { return 0 } +func (*staticCalculator) getExcessGas() fee.Gas { return fee.ZeroGas } + +func (*staticCalculator) getGasCap() fee.Gas { return fee.ZeroGas } func (*staticCalculator) setCredentials([]verify.Verifiable) {} diff --git a/wallet/chain/p/wallet.go b/wallet/chain/p/wallet.go index 01196bdd00ba..284057a2f898 100644 --- a/wallet/chain/p/wallet.go +++ b/wallet/chain/p/wallet.go @@ -294,7 +294,7 @@ type wallet struct { isEForkActive bool staticFeesConfig fee.StaticConfig gasPrice commonfee.GasPrice - maxComplexity commonfee.Gas + gasCap commonfee.Gas } func (w *wallet) Builder() builder.Builder { @@ -638,38 +638,33 @@ func (w *wallet) feeCalculator(ctx *builder.Context, options ...common.Option) ( return nil, err } - var feeCalculator *fee.Calculator if !w.isEForkActive { return fee.NewStaticCalculator(w.staticFeesConfig, upgrade.Config{}, time.Time{}), nil } - feeCalculator = fee.NewDynamicCalculator(commonfee.NewManager(w.gasPrice, fee.TempGasCap)) - return feeCalculator, nil + return fee.NewDynamicCalculator(commonfee.NewManager(w.gasPrice, w.gasCap)), nil } func (w *wallet) refreshFeesData(ctx *builder.Context, options ...common.Option) error { var ( ops = common.NewOptions(options) opsCtx = ops.Context() - err error ) chainTime, err := w.client.GetTimestamp(opsCtx) if err != nil { return err } - - w.staticFeesConfig = staticFeesConfigFromContext(ctx) - eUpgradeTime := version.GetEUpgradeTime(w.builder.Context().NetworkID) w.isEForkActive = !chainTime.Before(eUpgradeTime) + if !w.isEForkActive { - return nil // nothing else to update + w.staticFeesConfig = staticFeesConfigFromContext(ctx) + return nil } - feeCfg, _ := fee.GetDynamicConfig(w.isEForkActive) - w.gasPrice = feeCfg.MinGasPrice - w.maxComplexity = fee.TempGasCap - return nil + + w.gasPrice, w.gasCap, err = w.client.GetNextGasData(opsCtx) + return err } func staticFeesConfigFromContext(ctx *builder.Context) fee.StaticConfig { From 72f8f15b6fd84c01dc1b91e95c63a539da264e16 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Tue, 18 Jun 2024 18:22:26 +0200 Subject: [PATCH 177/190] fixed block building --- vms/components/fee/manager.go | 11 ++++++----- vms/components/fee/manager_test.go | 12 ++++++------ vms/platformvm/block/builder/builder.go | 12 ++++++++---- vms/platformvm/service_test.go | 2 +- vms/platformvm/state/block_helpers.go | 4 ++-- 5 files changed, 23 insertions(+), 18 deletions(-) diff --git a/vms/components/fee/manager.go b/vms/components/fee/manager.go index ca748129c9d1..b3baff1c9c5e 100644 --- a/vms/components/fee/manager.go +++ b/vms/components/fee/manager.go @@ -8,6 +8,7 @@ import ( "fmt" "math" "math/big" + "time" safemath "github.com/ava-labs/avalanchego/utils/math" ) @@ -40,14 +41,14 @@ func NewManager(gasPrice GasPrice, gasCap Gas) *Manager { func NewUpdatedManager( feesConfig DynamicFeesConfig, gasCap, currentExcessGas Gas, - parentBlkTime, childBlkTime int64, + parentBlkTime, childBlkTime time.Time, ) (*Manager, error) { res := &Manager{ gasCap: gasCap, currentExcessGas: currentExcessGas, } - targetGas, err := TargetGas(feesConfig, parentBlkTime, childBlkTime) + targetGas, err := targetGas(feesConfig, parentBlkTime, childBlkTime) if err != nil { return nil, fmt.Errorf("failed calculating target gas: %w", err) } @@ -62,12 +63,12 @@ func NewUpdatedManager( return res, nil } -func TargetGas(feesConfig DynamicFeesConfig, parentBlkTime, childBlkTime int64) (Gas, error) { - if childBlkTime < parentBlkTime { +func targetGas(feesConfig DynamicFeesConfig, parentBlkTime, childBlkTime time.Time) (Gas, error) { + if parentBlkTime.Compare(childBlkTime) > 0 { return ZeroGas, fmt.Errorf("unexpected block times, parentBlkTim %v, childBlkTime %v", parentBlkTime, childBlkTime) } - elapsedTime := uint64(childBlkTime - parentBlkTime) + elapsedTime := uint64(childBlkTime.Unix() - parentBlkTime.Unix()) targetGas, over := safemath.Mul64(uint64(feesConfig.GasTargetRate), elapsedTime) if over != nil { targetGas = math.MaxUint64 diff --git a/vms/components/fee/manager_test.go b/vms/components/fee/manager_test.go index 51848f5ba8d8..731b885902e2 100644 --- a/vms/components/fee/manager_test.go +++ b/vms/components/fee/manager_test.go @@ -41,8 +41,8 @@ func TestUpdateGasPrice(t *testing.T) { testDynamicFeeCfg, testGasCap, excessGas, - parentBlkTime.Unix(), - childBlkTime.Unix(), + parentBlkTime, + childBlkTime, ) require.NoError(err) @@ -139,8 +139,8 @@ func TestPChainGasPriceIncreaseDueToPeak(t *testing.T) { testDynamicFeeCfg, testGasCap, excessGas, - parentBlkData.blkTime, - childBlkData.blkTime, + time.Unix(parentBlkData.blkTime, 0), + time.Unix(childBlkData.blkTime, 0), ) require.NoError(err) @@ -178,8 +178,8 @@ func TestPChainGasPriceIncreaseDueToPeak(t *testing.T) { testDynamicFeeCfg, testGasCap, offPeakGas, - parentBlkTime.Unix(), - childBlkTime.Unix(), + parentBlkTime, + childBlkTime, ) require.NoError(err) diff --git a/vms/platformvm/block/builder/builder.go b/vms/platformvm/block/builder/builder.go index 86eb856e2813..15c851f4117a 100644 --- a/vms/platformvm/block/builder/builder.go +++ b/vms/platformvm/block/builder/builder.go @@ -339,7 +339,7 @@ func packBlockTxs( var ( upgrades = backend.Config.UpgradeConfig isEActive = upgrades.IsEActivated(timestamp) - targetGas = commonfee.ZeroGas + gasCap = commonfee.ZeroGas blockTxs []*txs.Tx inputs set.Set[ids.ID] @@ -355,9 +355,13 @@ func packBlockTxs( if err != nil { return nil, fmt.Errorf("failed retrieving dynamic fees config: %w", err) } - targetGas, err = commonfee.TargetGas(feeCfg, parentBlkTime.Unix(), timestamp.Unix()) + currentGasCap, err := stateDiff.GetCurrentGasCap() if err != nil { - return nil, fmt.Errorf("failed calculating target block complexity: %w", err) + return nil, fmt.Errorf("failed retrieving current gas cap: %w", err) + } + gasCap, err = commonfee.GasCap(feeCfg, currentGasCap, parentBlkTime, timestamp) + if err != nil { + return nil, fmt.Errorf("failed calculating next gas cap: %w", err) } } @@ -372,7 +376,7 @@ 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() >= targetGas) + (isEActive && feeCalculator.GetBlockGas() >= gasCap) if targetSizeReached { break } diff --git a/vms/platformvm/service_test.go b/vms/platformvm/service_test.go index c64877120792..806637c0f10e 100644 --- a/vms/platformvm/service_test.go +++ b/vms/platformvm/service_test.go @@ -106,7 +106,7 @@ func testReplayFeeCalculator(cfg *config.Config, parentBlkTime time.Time, state return nil, fmt.Errorf("failed retrieving gas cap: %w", err) } - feesMan, err := commonfee.NewUpdatedManager(feesCfg, gasCap, excessComplexity, parentBlkTime.Unix(), childBlkTime.Unix()) + feesMan, err := commonfee.NewUpdatedManager(feesCfg, gasCap, excessComplexity, parentBlkTime, childBlkTime) if err != nil { return nil, fmt.Errorf("failed updating fee manager: %w", err) } diff --git a/vms/platformvm/state/block_helpers.go b/vms/platformvm/state/block_helpers.go index 4034530df51f..cb53fa79bea5 100644 --- a/vms/platformvm/state/block_helpers.go +++ b/vms/platformvm/state/block_helpers.go @@ -116,8 +116,8 @@ func updatedFeeManager(feesCfg commonfee.DynamicFeesConfig, state Chain, parentB feesCfg, gasCap, excessGas, - parentBlkTime.Unix(), - childBlkTime.Unix(), + parentBlkTime, + childBlkTime, ) if err != nil { return nil, fmt.Errorf("failed updating fee rates, %w", err) From 338db53eebd59e94b34f34da26967d9e1b47f90a Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Wed, 19 Jun 2024 09:42:26 +0200 Subject: [PATCH 178/190] fixed UTs --- vms/components/fee/manager.go | 4 ++-- vms/platformvm/service_test.go | 16 ++++++++++------ 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/vms/components/fee/manager.go b/vms/components/fee/manager.go index b3baff1c9c5e..71eb59e90d5c 100644 --- a/vms/components/fee/manager.go +++ b/vms/components/fee/manager.go @@ -48,7 +48,7 @@ func NewUpdatedManager( currentExcessGas: currentExcessGas, } - targetGas, err := targetGas(feesConfig, parentBlkTime, childBlkTime) + targetGas, err := TargetGas(feesConfig, parentBlkTime, childBlkTime) if err != nil { return nil, fmt.Errorf("failed calculating target gas: %w", err) } @@ -63,7 +63,7 @@ func NewUpdatedManager( return res, nil } -func targetGas(feesConfig DynamicFeesConfig, parentBlkTime, childBlkTime time.Time) (Gas, error) { +func TargetGas(feesConfig DynamicFeesConfig, parentBlkTime, childBlkTime time.Time) (Gas, error) { if parentBlkTime.Compare(childBlkTime) > 0 { return ZeroGas, fmt.Errorf("unexpected block times, parentBlkTim %v, childBlkTime %v", parentBlkTime, childBlkTime) } diff --git a/vms/platformvm/service_test.go b/vms/platformvm/service_test.go index 806637c0f10e..3a1521e3a893 100644 --- a/vms/platformvm/service_test.go +++ b/vms/platformvm/service_test.go @@ -1193,7 +1193,7 @@ func TestGetFeeRates(t *testing.T) { service, _, _ := defaultService(t) service.vm.ctx.Lock.Lock() - now := time.Now().Truncate(time.Second) + now := service.vm.state.GetTimestamp().Add(time.Second) service.vm.clock.Set(now) feeCfg, err := fee.GetDynamicConfig(true /*isEActive*/) require.NoError(err) @@ -1204,12 +1204,16 @@ func TestGetFeeRates(t *testing.T) { require.NoError(service.GetNextGasData(nil, nil, &reply0)) require.Equal(feeCfg.MinGasPrice, reply0.NextGasPrice) - // let cumulated complexity go above target. Fee rates will go up + // let gas go above target. Gas price will go up service.vm.ctx.Lock.Lock() - elapsedTime := time.Second - targetGas := commonfee.Gas(uint64(feeCfg.GasTargetRate) * uint64(elapsedTime/time.Second)) - gas := targetGas + commonfee.Gas(10) - service.vm.state.SetExcessGas(gas) + chainTime := service.vm.state.GetTimestamp() + elapsedTime := 10 * time.Second + targetGas, err := commonfee.TargetGas(feeCfg, chainTime, chainTime.Add(elapsedTime)) + require.NoError(err) + + excessGas, err := service.vm.state.GetExcessGas() + require.NoError(err) + service.vm.state.SetExcessGas(excessGas + targetGas + commonfee.Gas(20_000)) service.vm.ctx.Lock.Unlock() reply1 := GetGasPriceReply{} From 792a13fa4a49f6db2a0e90fa352a9773f51fb0ea Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Wed, 19 Jun 2024 10:36:43 +0200 Subject: [PATCH 179/190] nit --- vms/platformvm/block/executor/acceptor.go | 8 ++++---- vms/platformvm/block/executor/verifier.go | 3 --- vms/platformvm/block/executor/verifier_test.go | 2 +- vms/platformvm/metrics/metrics.go | 4 ++-- vms/platformvm/metrics/no_op.go | 2 +- 5 files changed, 8 insertions(+), 11 deletions(-) diff --git a/vms/platformvm/block/executor/acceptor.go b/vms/platformvm/block/executor/acceptor.go index 925ad72b019a..dfed136eb109 100644 --- a/vms/platformvm/block/executor/acceptor.go +++ b/vms/platformvm/block/executor/acceptor.go @@ -79,7 +79,7 @@ func (a *acceptor) ApricotAtomicBlock(b *block.ApricotAtomicBlock) error { return fmt.Errorf("%w %s", errMissingBlockState, blkID) } - a.metrics.SetExcessComplexity(blkState.excessGas) + a.metrics.SetExcessGas(blkState.excessGas) a.metrics.SetBlockGas(blkState.blockGas) // Update the state to reflect the changes made in [onAcceptState]. @@ -139,7 +139,7 @@ func (a *acceptor) optionBlock(b block.Block, blockType string) error { return err } - a.metrics.SetExcessComplexity(parentState.excessGas) + a.metrics.SetExcessGas(parentState.excessGas) a.metrics.SetBlockGas(parentState.blockGas) if err := a.commonAccept(b); err != nil { @@ -158,7 +158,7 @@ func (a *acceptor) optionBlock(b block.Block, blockType string) error { } // we set option complexity at its parent block's one. - a.metrics.SetExcessComplexity(parentState.excessGas) + a.metrics.SetExcessGas(parentState.excessGas) a.metrics.SetBlockGas(parentState.blockGas) if err := blkState.onAcceptState.Apply(a.state); err != nil { @@ -239,7 +239,7 @@ func (a *acceptor) standardBlock(b block.Block, blockType string) error { return fmt.Errorf("%w %s", errMissingBlockState, blkID) } - a.metrics.SetExcessComplexity(blkState.excessGas) + a.metrics.SetExcessGas(blkState.excessGas) a.metrics.SetBlockGas(blkState.blockGas) // Update the state to reflect the changes made in [onAcceptState]. diff --git a/vms/platformvm/block/executor/verifier.go b/vms/platformvm/block/executor/verifier.go index 491d19b7d173..0184864d2642 100644 --- a/vms/platformvm/block/executor/verifier.go +++ b/vms/platformvm/block/executor/verifier.go @@ -367,9 +367,6 @@ func (v *verifier) abortBlock(b block.Block) error { statelessBlock: b, onAcceptState: onAbortState, timestamp: onAbortState.GetTimestamp(), - - // blockComplexity not set. We'll assign same complexity - // as proposal blocks upon acceptance } return nil } diff --git a/vms/platformvm/block/executor/verifier_test.go b/vms/platformvm/block/executor/verifier_test.go index d5e5b533e405..11228a2175d9 100644 --- a/vms/platformvm/block/executor/verifier_test.go +++ b/vms/platformvm/block/executor/verifier_test.go @@ -521,7 +521,7 @@ func TestStandardBlockGas(t *testing.T) { 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 + // check that gas cap is non-zero post E upgrade and zero pre E upgrade blkState, found := env.blkManager.(*manager).blkIDToState[blk.ID()] require.True(found) diff --git a/vms/platformvm/metrics/metrics.go b/vms/platformvm/metrics/metrics.go index 879702407b03..ae493db10aef 100644 --- a/vms/platformvm/metrics/metrics.go +++ b/vms/platformvm/metrics/metrics.go @@ -41,7 +41,7 @@ type Metrics interface { // Mark when this node will unstake from a subnet. SetTimeUntilSubnetUnstake(subnetID ids.ID, timeUntilUnstake time.Duration) // Mark cumulated gas in excess of target gas - SetExcessComplexity(commonfee.Gas) + SetExcessGas(commonfee.Gas) // Mark gas cumulated across txs of last accepted block SetBlockGas(commonfee.Gas) } @@ -170,7 +170,7 @@ func (m *metrics) SetTimeUntilSubnetUnstake(subnetID ids.ID, timeUntilUnstake ti m.timeUntilSubnetUnstake.WithLabelValues(subnetID.String()).Set(float64(timeUntilUnstake)) } -func (m *metrics) SetExcessComplexity(g commonfee.Gas) { +func (m *metrics) SetExcessGas(g commonfee.Gas) { m.excessGas.Set(float64(g)) } diff --git a/vms/platformvm/metrics/no_op.go b/vms/platformvm/metrics/no_op.go index d37dbc0eeb32..21df88c57f11 100644 --- a/vms/platformvm/metrics/no_op.go +++ b/vms/platformvm/metrics/no_op.go @@ -53,6 +53,6 @@ func (noopMetrics) SetSubnetPercentConnected(ids.ID, float64) {} func (noopMetrics) SetPercentConnected(float64) {} -func (noopMetrics) SetExcessComplexity(commonfee.Gas) {} +func (noopMetrics) SetExcessGas(commonfee.Gas) {} func (noopMetrics) SetBlockGas(commonfee.Gas) {} From 263ad2d570d6089d13c35faeda361f940e092458 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 20 Jun 2024 15:56:17 +0200 Subject: [PATCH 180/190] nit --- vms/platformvm/txs/fee/dynamic_calculator.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vms/platformvm/txs/fee/dynamic_calculator.go b/vms/platformvm/txs/fee/dynamic_calculator.go index 73ec3ba8757b..f5d14a2b111b 100644 --- a/vms/platformvm/txs/fee/dynamic_calculator.go +++ b/vms/platformvm/txs/fee/dynamic_calculator.go @@ -252,7 +252,7 @@ func (c *dynamicCalculator) meterTx( } func (c *dynamicCalculator) addFeesFor(complexity fee.Dimensions) (uint64, error) { - if c.fc == nil || complexity == fee.Empty { + if complexity == fee.Empty { return 0, nil } @@ -278,7 +278,7 @@ func (c *dynamicCalculator) addFeesFor(complexity fee.Dimensions) (uint64, error } func (c *dynamicCalculator) removeFeesFor(unitsToRm fee.Dimensions) (uint64, error) { - if c.fc == nil || unitsToRm == fee.Empty { + if unitsToRm == fee.Empty { return 0, nil } From 020198d126b39fc7267e945664d0f498134c2408 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 27 Jun 2024 15:49:10 +0200 Subject: [PATCH 181/190] nit --- vms/components/fee/dimensions.go | 4 ++-- vms/components/fee/manager_test.go | 6 +++--- vms/platformvm/txs/fee/dynamic_calculator.go | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/vms/components/fee/dimensions.go b/vms/components/fee/dimensions.go index fc59c70145d5..7c5e14f785e2 100644 --- a/vms/components/fee/dimensions.go +++ b/vms/components/fee/dimensions.go @@ -42,10 +42,10 @@ func Add(lhs, rhs Dimensions) (Dimensions, error) { return res, nil } -func ScalarProd(lhs, rhs Dimensions) (Gas, error) { +func ToGas(weights, dimensions Dimensions) (Gas, error) { var res uint64 for i := 0; i < FeeDimensions; i++ { - v, err := safemath.Mul64(lhs[i], rhs[i]) + v, err := safemath.Mul64(weights[i], dimensions[i]) if err != nil { return ZeroGas, err } diff --git a/vms/components/fee/manager_test.go b/vms/components/fee/manager_test.go index 731b885902e2..15b4896b7df3 100644 --- a/vms/components/fee/manager_test.go +++ b/vms/components/fee/manager_test.go @@ -132,7 +132,7 @@ func TestPChainGasPriceIncreaseDueToPeak(t *testing.T) { parentBlkData := blockComplexities[i-1] childBlkData := blockComplexities[i] - excessGas, err := ScalarProd(testDynamicFeeCfg.FeeDimensionWeights, parentBlkData.complexity) + excessGas, err := ToGas(testDynamicFeeCfg.FeeDimensionWeights, parentBlkData.complexity) require.NoError(err) m, err := NewUpdatedManager( @@ -155,7 +155,7 @@ func TestPChainGasPriceIncreaseDueToPeak(t *testing.T) { ) // at peak the total fee should be no more than 100 Avax. - childGas, err := ScalarProd(testDynamicFeeCfg.FeeDimensionWeights, childBlkData.complexity) + childGas, err := ToGas(testDynamicFeeCfg.FeeDimensionWeights, childBlkData.complexity) require.NoError(err) fee, err := m.CalculateFee(childGas) @@ -167,7 +167,7 @@ func TestPChainGasPriceIncreaseDueToPeak(t *testing.T) { // OFF PEAK offPeakBlkComplexity := Dimensions{1473, 510, 510, 5000} - offPeakGas, err := ScalarProd(testDynamicFeeCfg.FeeDimensionWeights, offPeakBlkComplexity) + offPeakGas, err := ToGas(testDynamicFeeCfg.FeeDimensionWeights, offPeakBlkComplexity) require.NoError(err) elapsedTime := time.Unix(1615238881, 0).Sub(time.Unix(1615237936, 0)) diff --git a/vms/platformvm/txs/fee/dynamic_calculator.go b/vms/platformvm/txs/fee/dynamic_calculator.go index d3da4aa850d1..0fafd04db954 100644 --- a/vms/platformvm/txs/fee/dynamic_calculator.go +++ b/vms/platformvm/txs/fee/dynamic_calculator.go @@ -260,7 +260,7 @@ func (c *dynamicCalculator) addFeesFor(complexity fee.Dimensions) (uint64, error if err != nil { return 0, fmt.Errorf("failed adding fees: %w", err) } - txGas, err := fee.ScalarProd(complexity, feeCfg.FeeDimensionWeights) + txGas, err := fee.ToGas(feeCfg.FeeDimensionWeights, complexity) if err != nil { return 0, fmt.Errorf("failed adding fees: %w", err) } @@ -286,7 +286,7 @@ func (c *dynamicCalculator) removeFeesFor(unitsToRm fee.Dimensions) (uint64, err if err != nil { return 0, fmt.Errorf("failed adding fees: %w", err) } - txGas, err := fee.ScalarProd(unitsToRm, feeCfg.FeeDimensionWeights) + txGas, err := fee.ToGas(feeCfg.FeeDimensionWeights, unitsToRm) if err != nil { return 0, fmt.Errorf("failed adding fees: %w", err) } From ec8b45b7037312bf46c7785d8ad496149b679a3d Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Wed, 10 Jul 2024 19:43:39 +0200 Subject: [PATCH 182/190] P chain units fees update rescale gas - V2 (#3181) --- tests/e2e/p/workflow.go | 7 +- vms/components/fee/calculator.go | 88 ++++++++++------ vms/components/fee/dimensions.go | 16 ++- vms/components/fee/manager_test.go | 7 +- vms/platformvm/block/builder/builder.go | 16 ++- vms/platformvm/block/executor/verifier.go | 30 +++++- vms/platformvm/client.go | 9 ++ vms/platformvm/service.go | 31 ++++++ vms/platformvm/service_test.go | 2 +- vms/platformvm/state/chain_time_helpers.go | 13 ++- vms/platformvm/txs/executor/helpers_test.go | 2 + vms/platformvm/txs/fee/calculator.go | 4 +- vms/platformvm/txs/fee/calculator_test.go | 103 ++++++++++++------- vms/platformvm/txs/fee/dynamic_calculator.go | 58 +++++------ vms/platformvm/txs/fee/dynamic_config.go | 4 +- vms/platformvm/txs/fee/static_calculator.go | 4 +- vms/platformvm/txs/txstest/builder.go | 2 +- wallet/chain/p/builder_test.go | 83 +++++++-------- wallet/chain/p/wallet.go | 13 ++- 19 files changed, 326 insertions(+), 166 deletions(-) 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) From f71cbb9df98a81e4511e52aa299d015cede9f9d1 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 11 Jul 2024 11:17:46 +0200 Subject: [PATCH 183/190] improved UT + fixed linter failing --- tests/e2e/p/dynamic_fees.go | 2 + vms/components/fee/manager_test.go | 47 +++++++++++++----------- vms/platformvm/txs/fee/dynamic_config.go | 6 +-- 3 files changed, 30 insertions(+), 25 deletions(-) diff --git a/tests/e2e/p/dynamic_fees.go b/tests/e2e/p/dynamic_fees.go index b6edcc6beb9a..718fb3a7281d 100644 --- a/tests/e2e/p/dynamic_fees.go +++ b/tests/e2e/p/dynamic_fees.go @@ -1,6 +1,8 @@ // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. // See the file LICENSE for licensing terms. +//go:build test + package p import ( diff --git a/vms/components/fee/manager_test.go b/vms/components/fee/manager_test.go index c2d7b876cf22..0b8efaf74992 100644 --- a/vms/components/fee/manager_test.go +++ b/vms/components/fee/manager_test.go @@ -16,11 +16,11 @@ import ( var ( testDynamicFeeCfg = DynamicFeesConfig{ - MinGasPrice: GasPrice(60 * units.NanoAvax), - UpdateDenominator: Gas(50_000), - GasTargetRate: Gas(250), + MinGasPrice: GasPrice(10 * units.NanoAvax), + UpdateDenominator: Gas(100_000), + GasTargetRate: Gas(2_500), - FeeDimensionWeights: Dimensions{1, 1, 1, 1}, + FeeDimensionWeights: Dimensions{6, 10, 10, 1}, } testGasCap = Gas(math.MaxUint64) ) @@ -30,7 +30,7 @@ func TestUpdateGasPrice(t *testing.T) { var ( parentGasPrice = GasPrice(10) - excessGas = Gas(300) + excessGas = Gas(15_000) elapsedTime = time.Second parentBlkTime = time.Now().Truncate(time.Second) @@ -112,29 +112,29 @@ func TestPChainGasPriceIncreaseDueToPeak(t *testing.T) { {1615237936, Dimensions{34064, 13056, 13056, 128000}}, {1615237936, Dimensions{34064, 13056, 13056, 128000}}, {1615237936, Dimensions{34064, 13056, 13056, 128000}}, - // {1615237936, Dimensions{820, 360, 442, 4000}}, - // {1615237936, Dimensions{34064, 13056, 13056, 128000}}, - // {1615237936, Dimensions{34064, 13056, 13056, 128000}}, - // {1615237936, Dimensions{34064, 13056, 13056, 128000}}, - // {1615237936, Dimensions{34064, 13056, 13056, 128000}}, - // {1615237936, Dimensions{34064, 13056, 13056, 128000}}, - // {1615237936, Dimensions{34064, 13056, 13056, 128000}}, - // {1615237936, Dimensions{34064, 13056, 13056, 128000}}, - // {1615237936, Dimensions{34064, 13056, 13056, 128000}}, - // {1615237936, Dimensions{3589, 1326, 1326, 13000}}, - // {1615237936, Dimensions{550, 180, 180, 2000}}, - // {1615237936, Dimensions{413, 102, 102, 1000}}, + {1615237936, Dimensions{820, 360, 442, 4000}}, + {1615237936, Dimensions{34064, 13056, 13056, 128000}}, + {1615237936, Dimensions{34064, 13056, 13056, 128000}}, + {1615237936, Dimensions{34064, 13056, 13056, 128000}}, + {1615237936, Dimensions{34064, 13056, 13056, 128000}}, + {1615237936, Dimensions{34064, 13056, 13056, 128000}}, + {1615237936, Dimensions{34064, 13056, 13056, 128000}}, + {1615237936, Dimensions{34064, 13056, 13056, 128000}}, + {1615237936, Dimensions{34064, 13056, 13056, 128000}}, + {1615237936, Dimensions{3589, 1326, 1326, 13000}}, + {1615237936, Dimensions{550, 180, 180, 2000}}, + {1615237936, Dimensions{413, 102, 102, 1000}}, } // PEAK INCOMING peakGasPrice := testDynamicFeeCfg.MinGasPrice + excessGas, err := ToGas(testDynamicFeeCfg.FeeDimensionWeights, blockComplexities[0].complexity) + require.NoError(err) + for i := 1; i < len(blockComplexities); i++ { parentBlkData := blockComplexities[i-1] childBlkData := blockComplexities[i] - excessGas, err := ToGas(testDynamicFeeCfg.FeeDimensionWeights, parentBlkData.complexity) - require.NoError(err) - m, err := NewUpdatedManager( testDynamicFeeCfg, testGasCap, @@ -145,12 +145,13 @@ func TestPChainGasPriceIncreaseDueToPeak(t *testing.T) { require.NoError(err) // check that gas price is strictly above minimal - require.Greater(m.GetGasPrice(), testDynamicFeeCfg.MinGasPrice, - fmt.Sprintf("failed at %d of %d iteration, \n curr gas price %v \n next gas price %v", + require.Greater(m.GetGasPrice(), peakGasPrice, + fmt.Sprintf("failed at %d of %d iteration, \n curr gas price %v \n next gas price %v \n dimensions %v", i, len(blockComplexities), peakGasPrice, m.GetGasPrice(), + childBlkData, ), ) @@ -160,6 +161,8 @@ func TestPChainGasPriceIncreaseDueToPeak(t *testing.T) { require.NoError(err) require.Less(fee, 100*units.Avax, fmt.Sprintf("iteration: %d, total: %d", i, len(blockComplexities))) require.NoError(m.DoneWithLatestTx()) + excessGas, err = m.GetExcessGas() + require.NoError(err) peakGasPrice = m.GetGasPrice() } diff --git a/vms/platformvm/txs/fee/dynamic_config.go b/vms/platformvm/txs/fee/dynamic_config.go index d7d3b7b928f3..c2b63494afd1 100644 --- a/vms/platformvm/txs/fee/dynamic_config.go +++ b/vms/platformvm/txs/fee/dynamic_config.go @@ -19,9 +19,9 @@ var ( eUpgradeDynamicFeesConfig = commonfee.DynamicFeesConfig{ MinGasPrice: commonfee.GasPrice(10 * units.NanoAvax), - UpdateDenominator: commonfee.Gas(50_000), - GasTargetRate: commonfee.Gas(250), - FeeDimensionWeights: commonfee.Dimensions{1, 1, 1, 1}, + UpdateDenominator: commonfee.Gas(100_000), + GasTargetRate: commonfee.Gas(2_500), + FeeDimensionWeights: commonfee.Dimensions{6, 10, 10, 1}, MaxGasPerSecond: commonfee.Gas(1_000_000), LeakGasCoeff: commonfee.Gas(1), } From aa0934a5f9f26ac052e7d15677b0877b9b609f2a Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 11 Jul 2024 11:41:56 +0200 Subject: [PATCH 184/190] nit --- vms/components/fee/manager_test.go | 75 ++++++++++++++++-------------- 1 file changed, 39 insertions(+), 36 deletions(-) diff --git a/vms/components/fee/manager_test.go b/vms/components/fee/manager_test.go index 0b8efaf74992..3802b8cbe2a1 100644 --- a/vms/components/fee/manager_test.go +++ b/vms/components/fee/manager_test.go @@ -87,43 +87,44 @@ func TestPChainGasPriceIncreaseDueToPeak(t *testing.T) { require := require.New(t) // See mainnet P-chain block 2LJVD1rfEfaJtTwRggFXaUXhME4t5WYGhYP9Aj7eTYqGsfknuC its descendants + peakTime := int64(1615237936) blockComplexities := []struct { blkTime int64 complexity Dimensions }{ - {1615237936, Dimensions{28234, 10812, 10812, 106000}}, - {1615237936, Dimensions{17634, 6732, 6732, 66000}}, - {1615237936, Dimensions{12334, 4692, 4692, 46000}}, - {1615237936, Dimensions{5709, 2142, 2142, 21000}}, - {1615237936, Dimensions{15514, 5916, 5916, 58000}}, - {1615237936, Dimensions{12069, 4590, 4590, 45000}}, - {1615237936, Dimensions{8359, 3162, 3162, 31000}}, - {1615237936, Dimensions{5444, 2040, 2040, 20000}}, - {1615237936, Dimensions{1734, 612, 612, 6000}}, - {1615237936, Dimensions{5974, 2244, 2244, 22000}}, - {1615237936, Dimensions{3059, 1122, 1122, 11000}}, - {1615237936, Dimensions{7034, 2652, 2652, 26000}}, - {1615237936, Dimensions{7564, 2856, 2856, 28000}}, - {1615237936, Dimensions{34064, 13056, 13056, 128000}}, - {1615237936, Dimensions{34064, 13056, 13056, 128000}}, - {1615237936, Dimensions{34064, 13056, 13056, 128000}}, - {1615237936, Dimensions{34064, 13056, 13056, 128000}}, - {1615237936, Dimensions{34064, 13056, 13056, 128000}}, - {1615237936, Dimensions{34064, 13056, 13056, 128000}}, - {1615237936, Dimensions{34064, 13056, 13056, 128000}}, - {1615237936, Dimensions{34064, 13056, 13056, 128000}}, - {1615237936, Dimensions{820, 360, 442, 4000}}, - {1615237936, Dimensions{34064, 13056, 13056, 128000}}, - {1615237936, Dimensions{34064, 13056, 13056, 128000}}, - {1615237936, Dimensions{34064, 13056, 13056, 128000}}, - {1615237936, Dimensions{34064, 13056, 13056, 128000}}, - {1615237936, Dimensions{34064, 13056, 13056, 128000}}, - {1615237936, Dimensions{34064, 13056, 13056, 128000}}, - {1615237936, Dimensions{34064, 13056, 13056, 128000}}, - {1615237936, Dimensions{34064, 13056, 13056, 128000}}, - {1615237936, Dimensions{3589, 1326, 1326, 13000}}, - {1615237936, Dimensions{550, 180, 180, 2000}}, - {1615237936, Dimensions{413, 102, 102, 1000}}, + {peakTime, Dimensions{28234, 10812, 10812, 106000}}, + {peakTime, Dimensions{17634, 6732, 6732, 66000}}, + {peakTime, Dimensions{12334, 4692, 4692, 46000}}, + {peakTime, Dimensions{5709, 2142, 2142, 21000}}, + {peakTime, Dimensions{15514, 5916, 5916, 58000}}, + {peakTime, Dimensions{12069, 4590, 4590, 45000}}, + {peakTime, Dimensions{8359, 3162, 3162, 31000}}, + {peakTime, Dimensions{5444, 2040, 2040, 20000}}, + {peakTime, Dimensions{1734, 612, 612, 6000}}, + {peakTime, Dimensions{5974, 2244, 2244, 22000}}, + {peakTime, Dimensions{3059, 1122, 1122, 11000}}, + {peakTime, Dimensions{7034, 2652, 2652, 26000}}, + {peakTime, Dimensions{7564, 2856, 2856, 28000}}, + {peakTime, Dimensions{34064, 13056, 13056, 128000}}, + {peakTime, Dimensions{34064, 13056, 13056, 128000}}, + {peakTime, Dimensions{34064, 13056, 13056, 128000}}, + {peakTime, Dimensions{34064, 13056, 13056, 128000}}, + {peakTime, Dimensions{34064, 13056, 13056, 128000}}, + {peakTime, Dimensions{34064, 13056, 13056, 128000}}, + {peakTime, Dimensions{34064, 13056, 13056, 128000}}, + {peakTime, Dimensions{34064, 13056, 13056, 128000}}, + {peakTime, Dimensions{820, 360, 442, 4000}}, + {peakTime, Dimensions{34064, 13056, 13056, 128000}}, + {peakTime, Dimensions{34064, 13056, 13056, 128000}}, + {peakTime, Dimensions{34064, 13056, 13056, 128000}}, + {peakTime, Dimensions{34064, 13056, 13056, 128000}}, + {peakTime, Dimensions{34064, 13056, 13056, 128000}}, + {peakTime, Dimensions{34064, 13056, 13056, 128000}}, + {peakTime, Dimensions{34064, 13056, 13056, 128000}}, + {peakTime, Dimensions{34064, 13056, 13056, 128000}}, + {peakTime, Dimensions{3589, 1326, 1326, 13000}}, + {peakTime, Dimensions{550, 180, 180, 2000}}, + {peakTime, Dimensions{413, 102, 102, 1000}}, } // PEAK INCOMING @@ -144,7 +145,7 @@ func TestPChainGasPriceIncreaseDueToPeak(t *testing.T) { ) require.NoError(err) - // check that gas price is strictly above minimal + // check that gas price is strictly increasing (since all block have the same timestamp) require.Greater(m.GetGasPrice(), peakGasPrice, fmt.Sprintf("failed at %d of %d iteration, \n curr gas price %v \n next gas price %v \n dimensions %v", i, @@ -160,19 +161,21 @@ func TestPChainGasPriceIncreaseDueToPeak(t *testing.T) { fee, err := m.GetLatestTxFee() require.NoError(err) require.Less(fee, 100*units.Avax, fmt.Sprintf("iteration: %d, total: %d", i, len(blockComplexities))) + + // update quantities for next block require.NoError(m.DoneWithLatestTx()) excessGas, err = m.GetExcessGas() require.NoError(err) - peakGasPrice = m.GetGasPrice() } // OFF PEAK + offPeakTime := int64(1615238881) offPeakBlkComplexity := Dimensions{1473, 510, 510, 5000} offPeakGas, err := ToGas(testDynamicFeeCfg.FeeDimensionWeights, offPeakBlkComplexity) require.NoError(err) - elapsedTime := time.Unix(1615238881, 0).Sub(time.Unix(1615237936, 0)) + elapsedTime := time.Unix(offPeakTime, 0).Sub(time.Unix(peakTime, 0)) parentBlkTime := time.Now().Truncate(time.Second) childBlkTime := parentBlkTime.Add(elapsedTime) From 6451b3e623f4f87d670bfa443f775c93c4fc7123 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 11 Jul 2024 12:06:31 +0200 Subject: [PATCH 185/190] Add/Remove fees consolidation --- vms/components/fee/calculator.go | 35 ++++++++++++------- .../{manager_test.go => calculator_test.go} | 35 +++++++++++++++++-- vms/platformvm/txs/fee/dynamic_calculator.go | 20 +++-------- 3 files changed, 59 insertions(+), 31 deletions(-) rename vms/components/fee/{manager_test.go => calculator_test.go} (89%) diff --git a/vms/components/fee/calculator.go b/vms/components/fee/calculator.go index 0aa0a09ee713..930244a0a443 100644 --- a/vms/components/fee/calculator.go +++ b/vms/components/fee/calculator.go @@ -111,36 +111,45 @@ func (c *Calculator) GetExcessGas() (Gas, error) { return Gas(g), nil } -// 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) CumulateComplexity(complexity Dimensions) error { +// AddFeesFor updates latest tx complexity. It should be called once when tx is being verified +// and may be called multiple times when tx is being built (and tx components are added in time). +// AddFeesFor checks that gas cap is not breached. It also returns the updated tx fee for convenience. +func (c *Calculator) AddFeesFor(complexity Dimensions) (uint64, error) { + if complexity == Empty { + return c.GetLatestTxFee() + } + // Ensure we can consume (don't want partial update of values) uc, err := Add(c.latestTxComplexity, complexity) if err != nil { - return fmt.Errorf("%w: %w", errGasBoundBreached, err) + return 0, fmt.Errorf("%w: %w", errGasBoundBreached, err) } + c.latestTxComplexity = uc + totalGas, err := c.GetBlockGas() if err != nil { - return fmt.Errorf("%w: %w", errGasBoundBreached, err) + return 0, fmt.Errorf("%w: %w", errGasBoundBreached, err) } if totalGas > c.gasCap { - return fmt.Errorf("%w: %w", errGasBoundBreached, err) + return 0, fmt.Errorf("%w: %w", errGasBoundBreached, err) } - c.latestTxComplexity = uc - return nil + return c.GetLatestTxFee() } // 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) RemoveComplexity(complexity Dimensions) error { +// and to remove it later on. [RemoveFeesFor] grants this freedom +func (c *Calculator) RemoveFeesFor(complexity Dimensions) (uint64, error) { + if complexity == Empty { + return c.GetLatestTxFee() + } + rc, err := Remove(c.latestTxComplexity, complexity) if err != nil { - return fmt.Errorf("%w: current Gas %d, gas to revert %d", err, c.cumulatedGas, complexity) + return 0, fmt.Errorf("%w: current Gas %d, gas to revert %d", err, c.cumulatedGas, complexity) } c.latestTxComplexity = rc - return nil + return c.GetLatestTxFee() } // DoneWithLatestTx should be invoked one a tx has been fully processed, before moving to the next one diff --git a/vms/components/fee/manager_test.go b/vms/components/fee/calculator_test.go similarity index 89% rename from vms/components/fee/manager_test.go rename to vms/components/fee/calculator_test.go index 3802b8cbe2a1..de9d895df60f 100644 --- a/vms/components/fee/manager_test.go +++ b/vms/components/fee/calculator_test.go @@ -25,6 +25,38 @@ var ( testGasCap = Gas(math.MaxUint64) ) +func TestAddAndRemoveFees(t *testing.T) { + r := require.New(t) + + var ( + fc = NewCalculator(testDynamicFeeCfg.FeeDimensionWeights, testDynamicFeeCfg.MinGasPrice, testGasCap) + + complexity = Dimensions{1, 2, 3, 4} + ) + + fee0, err := fc.GetLatestTxFee() + r.NoError(err) + r.Zero(fee0) + r.NoError(fc.DoneWithLatestTx()) + gas, err := fc.GetBlockGas() + r.NoError(err) + r.Zero(gas) + + fee1, err := fc.AddFeesFor(complexity) + r.NoError(err) + r.Greater(fee1, fee0) + gas, err = fc.GetBlockGas() + r.NoError(err) + r.NotZero(gas) + + rFee, err := fc.RemoveFeesFor(complexity) + r.NoError(err) + r.Equal(rFee, fee0) + gas, err = fc.GetBlockGas() + r.NoError(err) + r.Zero(gas) +} + func TestUpdateGasPrice(t *testing.T) { require := require.New(t) @@ -157,8 +189,7 @@ func TestPChainGasPriceIncreaseDueToPeak(t *testing.T) { ) // at peak the total fee should be no more than 100 Avax. - require.NoError(m.CumulateComplexity(childBlkData.complexity)) - fee, err := m.GetLatestTxFee() + fee, err := m.AddFeesFor(childBlkData.complexity) require.NoError(err) require.Less(fee, 100*units.Avax, fmt.Sprintf("iteration: %d, total: %d", i, len(blockComplexities))) diff --git a/vms/platformvm/txs/fee/dynamic_calculator.go b/vms/platformvm/txs/fee/dynamic_calculator.go index 8af234ce4a94..d4e20f46de5a 100644 --- a/vms/platformvm/txs/fee/dynamic_calculator.go +++ b/vms/platformvm/txs/fee/dynamic_calculator.go @@ -63,15 +63,9 @@ func (c *dynamicCalculator) CalculateFee(tx *txs.Tx) (uint64, error) { } func (c *dynamicCalculator) AddFeesFor(complexity fee.Dimensions) (uint64, error) { - if complexity == fee.Empty { - return 0, nil - } - if err := c.fc.CumulateComplexity(complexity); err != nil { - return 0, fmt.Errorf("failed cumulating complexity: %w", err) - } - fee, err := c.fc.GetLatestTxFee() + fee, err := c.fc.AddFeesFor(complexity) if err != nil { - return 0, fmt.Errorf("%w: %w", errFailedFeeCalculation, err) + return 0, fmt.Errorf("failed cumulating complexity: %w", err) } extraFee := fee - c.fee @@ -80,15 +74,9 @@ func (c *dynamicCalculator) AddFeesFor(complexity fee.Dimensions) (uint64, error } func (c *dynamicCalculator) RemoveFeesFor(unitsToRm fee.Dimensions) (uint64, error) { - if unitsToRm == fee.Empty { - return 0, nil - } - if err := c.fc.RemoveComplexity(unitsToRm); err != nil { - return 0, fmt.Errorf("failed removing units: %w", err) - } - fee, err := c.fc.GetLatestTxFee() + fee, err := c.fc.RemoveFeesFor(unitsToRm) if err != nil { - return 0, fmt.Errorf("%w: %w", errFailedFeeCalculation, err) + return 0, fmt.Errorf("failed removing complexity: %w", err) } removedFee := c.fee - fee From 60fb893a70dc086fb882c5730ba5ebfb489c5f0c Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 11 Jul 2024 16:22:25 +0200 Subject: [PATCH 186/190] added gas caps UTs --- vms/components/fee/calculator_test.go | 101 ++++++++++++++++++++++---- vms/components/fee/config.go | 7 +- 2 files changed, 90 insertions(+), 18 deletions(-) diff --git a/vms/components/fee/calculator_test.go b/vms/components/fee/calculator_test.go index de9d895df60f..593166b66f35 100644 --- a/vms/components/fee/calculator_test.go +++ b/vms/components/fee/calculator_test.go @@ -12,6 +12,8 @@ import ( "github.com/stretchr/testify/require" "github.com/ava-labs/avalanchego/utils/units" + + safemath "github.com/ava-labs/avalanchego/utils/math" ) var ( @@ -26,35 +28,51 @@ var ( ) func TestAddAndRemoveFees(t *testing.T) { - r := require.New(t) + require := require.New(t) var ( fc = NewCalculator(testDynamicFeeCfg.FeeDimensionWeights, testDynamicFeeCfg.MinGasPrice, testGasCap) - complexity = Dimensions{1, 2, 3, 4} + complexity = Dimensions{1, 2, 3, 4} + extraComplexity = Dimensions{2, 3, 4, 5} + overComplexity = Dimensions{math.MaxUint64, math.MaxUint64, math.MaxUint64, math.MaxUint64} ) fee0, err := fc.GetLatestTxFee() - r.NoError(err) - r.Zero(fee0) - r.NoError(fc.DoneWithLatestTx()) + require.NoError(err) + require.Zero(fee0) + require.NoError(fc.DoneWithLatestTx()) gas, err := fc.GetBlockGas() - r.NoError(err) - r.Zero(gas) + require.NoError(err) + require.Zero(gas) fee1, err := fc.AddFeesFor(complexity) - r.NoError(err) - r.Greater(fee1, fee0) + require.NoError(err) + require.Greater(fee1, fee0) + gas, err = fc.GetBlockGas() + require.NoError(err) + require.NotZero(gas) + + // complexity can't overflow + _, err = fc.AddFeesFor(overComplexity) + require.ErrorIs(err, safemath.ErrOverflow) gas, err = fc.GetBlockGas() - r.NoError(err) - r.NotZero(gas) + require.NoError(err) + require.NotZero(gas) + + // can't remove more complexity than it was added + _, err = fc.RemoveFeesFor(extraComplexity) + require.ErrorIs(err, safemath.ErrUnderflow) + gas, err = fc.GetBlockGas() + require.NoError(err) + require.NotZero(gas) rFee, err := fc.RemoveFeesFor(complexity) - r.NoError(err) - r.Equal(rFee, fee0) + require.NoError(err) + require.Equal(rFee, fee0) gas, err = fc.GetBlockGas() - r.NoError(err) - r.Zero(gas) + require.NoError(err) + require.Zero(gas) } func TestUpdateGasPrice(t *testing.T) { @@ -222,3 +240,56 @@ func TestPChainGasPriceIncreaseDueToPeak(t *testing.T) { // check that gas price decreases off peak require.Less(m.GetGasPrice(), peakGasPrice) } + +func TestGasCap(t *testing.T) { + require := require.New(t) + + var ( + now = time.Now().Truncate(time.Second) + parentBlkTime = now + // childBlkTime = parentBlkTime.Add(time.Second) + // grandChildBlkTime = childBlkTime.Add(5 * time.Second) + + cfg = DynamicFeesConfig{ + MaxGasPerSecond: Gas(1_000), + LeakGasCoeff: Gas(5), + } + + currCap = cfg.MaxGasPerSecond + ) + + // A block whose gas matches cap, will consume full available cap + blkGas := cfg.MaxGasPerSecond + currCap = UpdateGasCap(currCap, blkGas) + require.Equal(ZeroGas, currCap) + + // capacity grows linearly in time till MaxGas + for i := 1; i <= 5; i++ { + childBlkTime := parentBlkTime.Add(time.Duration(i) * time.Second) + nextCap, err := GasCap(cfg, currCap, parentBlkTime, childBlkTime) + require.NoError(err) + require.Equal(Gas(i)*cfg.MaxGasPerSecond/cfg.LeakGasCoeff, nextCap) + } + + // capacity won't grow beyond MaxGas + childBlkTime := parentBlkTime.Add(time.Duration(6) * time.Second) + nextCap, err := GasCap(cfg, currCap, parentBlkTime, childBlkTime) + require.NoError(err) + require.Equal(cfg.MaxGasPerSecond, nextCap) + + // Arrival of a block will reduce GasCap of block Gas content + blkGas = cfg.MaxGasPerSecond / 4 + currCap = UpdateGasCap(nextCap, blkGas) + require.Equal(3*cfg.MaxGasPerSecond/4, currCap) + + // capacity keeps growing again in time after block + childBlkTime = parentBlkTime.Add(time.Second) + nextCap, err = GasCap(cfg, currCap, parentBlkTime, childBlkTime) + require.NoError(err) + require.Equal(currCap+cfg.MaxGasPerSecond/cfg.LeakGasCoeff, nextCap) + + // time can only grow forward with capacity + childBlkTime = parentBlkTime.Add(-1 * time.Second) + _, err = GasCap(cfg, currCap, parentBlkTime, childBlkTime) + require.ErrorIs(err, errUnexpectedBlockTimes) +} diff --git a/vms/components/fee/config.go b/vms/components/fee/config.go index f2d7766c7c9e..0e4dccc1b791 100644 --- a/vms/components/fee/config.go +++ b/vms/components/fee/config.go @@ -12,6 +12,7 @@ import ( var ( errZeroLeakGasCoeff = errors.New("zero leak gas coefficient") errZerUpdateDenominator = errors.New("update denominator cannot be zero") + errUnexpectedBlockTimes = errors.New("unexpected block times") ) type DynamicFeesConfig struct { @@ -31,8 +32,8 @@ type DynamicFeesConfig struct { FeeDimensionWeights Dimensions `json:"fee-dimension-weights"` // Leaky bucket parameters to calculate gas cap - MaxGasPerSecond Gas - LeakGasCoeff Gas // techically the unit of measure if sec^{-1}, but picking Gas reduces casts needed + MaxGasPerSecond Gas // techically the unit of measure is Gas/sec, but picking Gas reduces casts needed + LeakGasCoeff Gas // techically the unit of measure is sec^{-1}, but picking Gas reduces casts needed } func (c *DynamicFeesConfig) Validate() error { @@ -51,7 +52,7 @@ func (c *DynamicFeesConfig) Validate() error { // GasCap = min (GasCap + MaxGasPerSecond/LeakGasCoeff*ElapsedTime, MaxGasPerSecond) func GasCap(cfg DynamicFeesConfig, currentGasCapacity Gas, parentBlkTime, childBlkTime time.Time) (Gas, error) { if parentBlkTime.Compare(childBlkTime) > 0 { - return ZeroGas, fmt.Errorf("unexpected block times, parentBlkTim %v, childBlkTime %v", parentBlkTime, childBlkTime) + return ZeroGas, fmt.Errorf("%w, parentBlkTim %v, childBlkTime %v", errUnexpectedBlockTimes, parentBlkTime, childBlkTime) } elapsedTime := uint64(childBlkTime.Unix() - parentBlkTime.Unix()) From 9e752636c20ac3e59473a5ea6b5bb5c8162ae913 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Fri, 12 Jul 2024 09:43:05 +0200 Subject: [PATCH 187/190] TestTxFees cleanup --- vms/platformvm/txs/fee/calculator_test.go | 359 +++++++++++----------- 1 file changed, 180 insertions(+), 179 deletions(-) diff --git a/vms/platformvm/txs/fee/calculator_test.go b/vms/platformvm/txs/fee/calculator_test.go index 3fe578df7220..f0652a90accf 100644 --- a/vms/platformvm/txs/fee/calculator_test.go +++ b/vms/platformvm/txs/fee/calculator_test.go @@ -19,7 +19,6 @@ import ( "github.com/ava-labs/avalanchego/utils/units" "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/components/fee" - "github.com/ava-labs/avalanchego/vms/components/verify" "github.com/ava-labs/avalanchego/vms/platformvm/reward" "github.com/ava-labs/avalanchego/vms/platformvm/signer" "github.com/ava-labs/avalanchego/vms/platformvm/stakeable" @@ -112,41 +111,41 @@ func TestTxFees(t *testing.T) { preApricotPhase3Time := upgrades.ApricotPhase3Time.Add(-1 * time.Second) tests := []struct { - name string - chainTime time.Time - unsignedAndSignedTx func(t *testing.T) (txs.UnsignedTx, *txs.Tx) - gasCapF func() fee.Gas - expectedError error - checksF func(*testing.T, Calculator) + name string + chainTime time.Time + signedTxF func(t *testing.T) *txs.Tx + gasCapF func() fee.Gas + expectedError error + checksF func(*testing.T, Calculator) }{ { - name: "AddValidatorTx pre EUpgrade", - chainTime: preEUpgradeTime, - unsignedAndSignedTx: addValidatorTx, + name: "AddValidatorTx pre EUpgrade", + chainTime: preEUpgradeTime, + signedTxF: addValidatorTx, checksF: func(t *testing.T, c Calculator) { require.Equal(t, feeTestsDefaultCfg.AddPrimaryNetworkValidatorFee, c.GetFee()) }, }, { - name: "AddValidatorTx post EUpgrade", - chainTime: postEUpgradeTime, - expectedError: errFailedFeeCalculation, - unsignedAndSignedTx: addValidatorTx, - checksF: func(*testing.T, Calculator) {}, + name: "AddValidatorTx post EUpgrade", + chainTime: postEUpgradeTime, + expectedError: errFailedFeeCalculation, + signedTxF: addValidatorTx, + checksF: func(*testing.T, Calculator) {}, }, { - name: "AddSubnetValidatorTx pre EUpgrade", - chainTime: preEUpgradeTime, - unsignedAndSignedTx: addSubnetValidatorTx, + name: "AddSubnetValidatorTx pre EUpgrade", + chainTime: preEUpgradeTime, + signedTxF: addSubnetValidatorTx, checksF: func(t *testing.T, c Calculator) { require.Equal(t, feeTestsDefaultCfg.AddSubnetValidatorFee, c.GetFee()) }, }, { - name: "AddSubnetValidatorTx post EUpgrade, success", - chainTime: postEUpgradeTime, - expectedError: nil, - unsignedAndSignedTx: addSubnetValidatorTx, + name: "AddSubnetValidatorTx post EUpgrade, success", + chainTime: postEUpgradeTime, + expectedError: nil, + signedTxF: addSubnetValidatorTx, checksF: func(t *testing.T, c Calculator) { require.Equal(t, 2_910*units.NanoAvax, c.GetFee()) haveGas, err := c.GetBlockGas() @@ -160,46 +159,46 @@ func TestTxFees(t *testing.T) { gasCapF: func() fee.Gas { return testBlockMaxGas - 1 }, - unsignedAndSignedTx: addSubnetValidatorTx, - expectedError: errFailedComplexityCumulation, - checksF: func(*testing.T, Calculator) {}, + signedTxF: addSubnetValidatorTx, + expectedError: errFailedComplexityCumulation, + checksF: func(*testing.T, Calculator) {}, }, { - name: "AddDelegatorTx pre EUpgrade", - chainTime: preEUpgradeTime, - unsignedAndSignedTx: addDelegatorTx, + name: "AddDelegatorTx pre EUpgrade", + chainTime: preEUpgradeTime, + signedTxF: addDelegatorTx, checksF: func(t *testing.T, c Calculator) { require.Equal(t, feeTestsDefaultCfg.AddPrimaryNetworkDelegatorFee, c.GetFee()) }, }, { - name: "AddDelegatorTx post EUpgrade", - chainTime: postEUpgradeTime, - expectedError: errFailedFeeCalculation, - unsignedAndSignedTx: addDelegatorTx, - checksF: func(*testing.T, Calculator) {}, + name: "AddDelegatorTx post EUpgrade", + chainTime: postEUpgradeTime, + expectedError: errFailedFeeCalculation, + signedTxF: addDelegatorTx, + checksF: func(*testing.T, Calculator) {}, }, { - name: "CreateChainTx pre ApricotPhase3", - chainTime: preApricotPhase3Time, - unsignedAndSignedTx: createChainTx, + name: "CreateChainTx pre ApricotPhase3", + chainTime: preApricotPhase3Time, + signedTxF: createChainTx, checksF: func(t *testing.T, c Calculator) { require.Equal(t, feeTestsDefaultCfg.CreateAssetTxFee, c.GetFee()) }, }, { - name: "CreateChainTx pre EUpgrade", - chainTime: preEUpgradeTime, - unsignedAndSignedTx: createChainTx, + name: "CreateChainTx pre EUpgrade", + chainTime: preEUpgradeTime, + signedTxF: createChainTx, checksF: func(t *testing.T, c Calculator) { require.Equal(t, feeTestsDefaultCfg.CreateBlockchainTxFee, c.GetFee()) }, }, { - name: "CreateChainTx post EUpgrade, success", - chainTime: postEUpgradeTime, - unsignedAndSignedTx: createChainTx, - expectedError: nil, + name: "CreateChainTx post EUpgrade, success", + chainTime: postEUpgradeTime, + signedTxF: createChainTx, + expectedError: nil, checksF: func(t *testing.T, c Calculator) { require.Equal(t, 1_950*units.NanoAvax, c.GetFee()) haveGas, err := c.GetBlockGas() @@ -208,9 +207,9 @@ func TestTxFees(t *testing.T) { }, }, { - name: "CreateChainTx post EUpgrade, utxos read cap breached", - chainTime: postEUpgradeTime, - unsignedAndSignedTx: createChainTx, + name: "CreateChainTx post EUpgrade, utxos read cap breached", + chainTime: postEUpgradeTime, + signedTxF: createChainTx, gasCapF: func() fee.Gas { return testBlockMaxGas - 1 }, @@ -218,26 +217,26 @@ func TestTxFees(t *testing.T) { checksF: func(*testing.T, Calculator) {}, }, { - name: "CreateSubnetTx pre ApricotPhase3", - chainTime: preApricotPhase3Time, - unsignedAndSignedTx: createSubnetTx, + name: "CreateSubnetTx pre ApricotPhase3", + chainTime: preApricotPhase3Time, + signedTxF: createSubnetTx, checksF: func(t *testing.T, c Calculator) { require.Equal(t, feeTestsDefaultCfg.CreateAssetTxFee, c.GetFee()) }, }, { - name: "CreateSubnetTx pre EUpgrade", - chainTime: preEUpgradeTime, - unsignedAndSignedTx: createSubnetTx, + name: "CreateSubnetTx pre EUpgrade", + chainTime: preEUpgradeTime, + signedTxF: createSubnetTx, checksF: func(t *testing.T, c Calculator) { require.Equal(t, feeTestsDefaultCfg.CreateSubnetTxFee, c.GetFee()) }, }, { - name: "CreateSubnetTx post EUpgrade, success", - chainTime: postEUpgradeTime, - unsignedAndSignedTx: createSubnetTx, - expectedError: nil, + name: "CreateSubnetTx post EUpgrade, success", + chainTime: postEUpgradeTime, + signedTxF: createSubnetTx, + expectedError: nil, checksF: func(t *testing.T, c Calculator) { require.Equal(t, 1_850*units.NanoAvax, c.GetFee()) haveGas, err := c.GetBlockGas() @@ -246,9 +245,9 @@ func TestTxFees(t *testing.T) { }, }, { - name: "CreateSubnetTx post EUpgrade, utxos read cap breached", - chainTime: postEUpgradeTime, - unsignedAndSignedTx: createSubnetTx, + name: "CreateSubnetTx post EUpgrade, utxos read cap breached", + chainTime: postEUpgradeTime, + signedTxF: createSubnetTx, gasCapF: func() fee.Gas { return testBlockMaxGas - 1 }, @@ -256,18 +255,18 @@ func TestTxFees(t *testing.T) { checksF: func(*testing.T, Calculator) {}, }, { - name: "RemoveSubnetValidatorTx pre EUpgrade", - chainTime: preEUpgradeTime, - unsignedAndSignedTx: removeSubnetValidatorTx, + name: "RemoveSubnetValidatorTx pre EUpgrade", + chainTime: preEUpgradeTime, + signedTxF: removeSubnetValidatorTx, checksF: func(t *testing.T, c Calculator) { require.Equal(t, feeTestsDefaultCfg.TxFee, c.GetFee()) }, }, { - name: "RemoveSubnetValidatorTx post EUpgrade, success", - chainTime: postEUpgradeTime, - unsignedAndSignedTx: removeSubnetValidatorTx, - expectedError: nil, + name: "RemoveSubnetValidatorTx post EUpgrade, success", + chainTime: postEUpgradeTime, + signedTxF: removeSubnetValidatorTx, + expectedError: nil, checksF: func(t *testing.T, c Calculator) { require.Equal(t, 2_880*units.NanoAvax, c.GetFee()) haveGas, err := c.GetBlockGas() @@ -281,23 +280,23 @@ func TestTxFees(t *testing.T) { gasCapF: func() fee.Gas { return testBlockMaxGas - 1 }, - unsignedAndSignedTx: removeSubnetValidatorTx, - expectedError: errFailedComplexityCumulation, - checksF: func(*testing.T, Calculator) {}, + signedTxF: removeSubnetValidatorTx, + expectedError: errFailedComplexityCumulation, + checksF: func(*testing.T, Calculator) {}, }, { - name: "TransformSubnetTx pre EUpgrade", - chainTime: preEUpgradeTime, - unsignedAndSignedTx: transformSubnetTx, + name: "TransformSubnetTx pre EUpgrade", + chainTime: preEUpgradeTime, + signedTxF: transformSubnetTx, checksF: func(t *testing.T, c Calculator) { require.Equal(t, feeTestsDefaultCfg.TransformSubnetTxFee, c.GetFee()) }, }, { - name: "TransformSubnetTx post EUpgrade, success", - chainTime: postEUpgradeTime, - unsignedAndSignedTx: transformSubnetTx, - expectedError: nil, + name: "TransformSubnetTx post EUpgrade, success", + chainTime: postEUpgradeTime, + signedTxF: transformSubnetTx, + expectedError: nil, checksF: func(t *testing.T, c Calculator) { require.Equal(t, 1_970*units.NanoAvax, c.GetFee()) haveGas, err := c.GetBlockGas() @@ -311,23 +310,23 @@ func TestTxFees(t *testing.T) { gasCapF: func() fee.Gas { return testBlockMaxGas - 1 }, - unsignedAndSignedTx: transformSubnetTx, - expectedError: errFailedComplexityCumulation, - checksF: func(*testing.T, Calculator) {}, + signedTxF: transformSubnetTx, + expectedError: errFailedComplexityCumulation, + checksF: func(*testing.T, Calculator) {}, }, { - name: "TransferSubnetOwnershipTx pre EUpgrade", - chainTime: preEUpgradeTime, - unsignedAndSignedTx: transferSubnetOwnershipTx, + name: "TransferSubnetOwnershipTx pre EUpgrade", + chainTime: preEUpgradeTime, + signedTxF: transferSubnetOwnershipTx, checksF: func(t *testing.T, c Calculator) { require.Equal(t, feeTestsDefaultCfg.TxFee, c.GetFee()) }, }, { - name: "TransferSubnetOwnershipTx post EUpgrade, success", - chainTime: postEUpgradeTime, - unsignedAndSignedTx: transferSubnetOwnershipTx, - expectedError: nil, + name: "TransferSubnetOwnershipTx post EUpgrade, success", + chainTime: postEUpgradeTime, + signedTxF: transferSubnetOwnershipTx, + expectedError: nil, checksF: func(t *testing.T, c Calculator) { require.Equal(t, 1_900*units.NanoAvax, c.GetFee()) haveGas, err := c.GetBlockGas() @@ -341,14 +340,14 @@ func TestTxFees(t *testing.T) { gasCapF: func() fee.Gas { return testBlockMaxGas - 1 }, - unsignedAndSignedTx: transferSubnetOwnershipTx, - expectedError: errFailedComplexityCumulation, - checksF: func(*testing.T, Calculator) {}, + signedTxF: transferSubnetOwnershipTx, + expectedError: errFailedComplexityCumulation, + checksF: func(*testing.T, Calculator) {}, }, { name: "AddPermissionlessValidatorTx Primary Network pre EUpgrade", chainTime: preEUpgradeTime, - unsignedAndSignedTx: func(t *testing.T) (txs.UnsignedTx, *txs.Tx) { + signedTxF: func(t *testing.T) *txs.Tx { return addPermissionlessValidatorTx(t, constants.PrimaryNetworkID) }, checksF: func(t *testing.T, c Calculator) { @@ -358,7 +357,7 @@ func TestTxFees(t *testing.T) { { name: "AddPermissionlessValidatorTx Subnet pre EUpgrade", chainTime: preEUpgradeTime, - unsignedAndSignedTx: func(t *testing.T) (txs.UnsignedTx, *txs.Tx) { + signedTxF: func(t *testing.T) *txs.Tx { subnetID := ids.GenerateTestID() require.NotEqual(t, constants.PrimaryNetworkID, subnetID) return addPermissionlessValidatorTx(t, subnetID) @@ -370,7 +369,7 @@ func TestTxFees(t *testing.T) { { name: "AddPermissionlessValidatorTx Primary Network post EUpgrade, success", chainTime: postEUpgradeTime, - unsignedAndSignedTx: func(t *testing.T) (txs.UnsignedTx, *txs.Tx) { + signedTxF: func(t *testing.T) *txs.Tx { return addPermissionlessValidatorTx(t, constants.PrimaryNetworkID) }, expectedError: nil, @@ -384,7 +383,7 @@ func TestTxFees(t *testing.T) { { name: "AddPermissionlessValidatorTx Subnet post EUpgrade, success", chainTime: postEUpgradeTime, - unsignedAndSignedTx: func(t *testing.T) (txs.UnsignedTx, *txs.Tx) { + signedTxF: func(t *testing.T) *txs.Tx { subnetID := ids.GenerateTestID() require.NotEqual(t, constants.PrimaryNetworkID, subnetID) return addPermissionlessValidatorTx(t, subnetID) @@ -403,7 +402,7 @@ func TestTxFees(t *testing.T) { gasCapF: func() fee.Gas { return testBlockMaxGas - 1 }, - unsignedAndSignedTx: func(t *testing.T) (txs.UnsignedTx, *txs.Tx) { + signedTxF: func(t *testing.T) *txs.Tx { subnetID := ids.GenerateTestID() return addPermissionlessValidatorTx(t, subnetID) }, @@ -413,7 +412,7 @@ func TestTxFees(t *testing.T) { { name: "AddPermissionlessDelegatorTx Primary Network pre EUpgrade", chainTime: preEUpgradeTime, - unsignedAndSignedTx: func(t *testing.T) (txs.UnsignedTx, *txs.Tx) { + signedTxF: func(t *testing.T) *txs.Tx { return addPermissionlessDelegatorTx(t, constants.PrimaryNetworkID) }, checksF: func(t *testing.T, c Calculator) { @@ -423,7 +422,7 @@ func TestTxFees(t *testing.T) { { name: "AddPermissionlessDelegatorTx pre EUpgrade", chainTime: preEUpgradeTime, - unsignedAndSignedTx: func(t *testing.T) (txs.UnsignedTx, *txs.Tx) { + signedTxF: func(t *testing.T) *txs.Tx { subnetID := ids.GenerateTestID() require.NotEqual(t, constants.PrimaryNetworkID, subnetID) return addPermissionlessDelegatorTx(t, subnetID) @@ -435,7 +434,7 @@ func TestTxFees(t *testing.T) { { name: "AddPermissionlessDelegatorTx Primary Network post EUpgrade, success", chainTime: postEUpgradeTime, - unsignedAndSignedTx: func(t *testing.T) (txs.UnsignedTx, *txs.Tx) { + signedTxF: func(t *testing.T) *txs.Tx { return addPermissionlessDelegatorTx(t, constants.PrimaryNetworkID) }, expectedError: nil, @@ -449,7 +448,7 @@ func TestTxFees(t *testing.T) { { name: "AddPermissionlessDelegatorTx Subnet post EUpgrade, success", chainTime: postEUpgradeTime, - unsignedAndSignedTx: func(t *testing.T) (txs.UnsignedTx, *txs.Tx) { + signedTxF: func(t *testing.T) *txs.Tx { return addPermissionlessDelegatorTx(t, constants.PrimaryNetworkID) }, expectedError: nil, @@ -466,7 +465,7 @@ func TestTxFees(t *testing.T) { gasCapF: func() fee.Gas { return testBlockMaxGas - 1 }, - unsignedAndSignedTx: func(t *testing.T) (txs.UnsignedTx, *txs.Tx) { + signedTxF: func(t *testing.T) *txs.Tx { subnetID := ids.GenerateTestID() require.NotEqual(t, constants.PrimaryNetworkID, subnetID) return addPermissionlessValidatorTx(t, subnetID) @@ -475,18 +474,18 @@ func TestTxFees(t *testing.T) { checksF: func(*testing.T, Calculator) {}, }, { - name: "BaseTx pre EUpgrade", - chainTime: preEUpgradeTime, - unsignedAndSignedTx: baseTx, + name: "BaseTx pre EUpgrade", + chainTime: preEUpgradeTime, + signedTxF: baseTx, checksF: func(t *testing.T, c Calculator) { require.Equal(t, feeTestsDefaultCfg.TxFee, c.GetFee()) }, }, { - name: "BaseTx post EUpgrade, success", - chainTime: postEUpgradeTime, - unsignedAndSignedTx: baseTx, - expectedError: nil, + name: "BaseTx post EUpgrade, success", + chainTime: postEUpgradeTime, + signedTxF: baseTx, + expectedError: nil, checksF: func(t *testing.T, c Calculator) { require.Equal(t, 1_810*units.NanoAvax, c.GetFee()) haveGas, err := c.GetBlockGas() @@ -500,23 +499,23 @@ func TestTxFees(t *testing.T) { gasCapF: func() fee.Gas { return testBlockMaxGas - 1 }, - unsignedAndSignedTx: baseTx, - expectedError: errFailedComplexityCumulation, - checksF: func(*testing.T, Calculator) {}, + signedTxF: baseTx, + expectedError: errFailedComplexityCumulation, + checksF: func(*testing.T, Calculator) {}, }, { - name: "ImportTx pre EUpgrade", - chainTime: preEUpgradeTime, - unsignedAndSignedTx: importTx, + name: "ImportTx pre EUpgrade", + chainTime: preEUpgradeTime, + signedTxF: importTx, checksF: func(t *testing.T, c Calculator) { require.Equal(t, feeTestsDefaultCfg.TxFee, c.GetFee()) }, }, { - name: "ImportTx post EUpgrade, success", - chainTime: postEUpgradeTime, - unsignedAndSignedTx: importTx, - expectedError: nil, + name: "ImportTx post EUpgrade, success", + chainTime: postEUpgradeTime, + signedTxF: importTx, + expectedError: nil, checksF: func(t *testing.T, c Calculator) { require.Equal(t, 3_120*units.NanoAvax, c.GetFee()) haveGas, err := c.GetBlockGas() @@ -530,23 +529,23 @@ func TestTxFees(t *testing.T) { gasCapF: func() fee.Gas { return testBlockMaxGas - 1 }, - unsignedAndSignedTx: importTx, - expectedError: errFailedComplexityCumulation, - checksF: func(*testing.T, Calculator) {}, + signedTxF: importTx, + expectedError: errFailedComplexityCumulation, + checksF: func(*testing.T, Calculator) {}, }, { - name: "ExportTx pre EUpgrade", - chainTime: preEUpgradeTime, - unsignedAndSignedTx: exportTx, + name: "ExportTx pre EUpgrade", + chainTime: preEUpgradeTime, + signedTxF: exportTx, checksF: func(t *testing.T, c Calculator) { require.Equal(t, feeTestsDefaultCfg.TxFee, c.GetFee()) }, }, { - name: "ExportTx post EUpgrade, success", - chainTime: postEUpgradeTime, - unsignedAndSignedTx: exportTx, - expectedError: nil, + name: "ExportTx post EUpgrade, success", + chainTime: postEUpgradeTime, + signedTxF: exportTx, + expectedError: nil, checksF: func(t *testing.T, c Calculator) { require.Equal(t, 2_040*units.NanoAvax, c.GetFee()) haveGas, err := c.GetBlockGas() @@ -560,17 +559,19 @@ func TestTxFees(t *testing.T) { gasCapF: func() fee.Gas { return testBlockMaxGas - 1 }, - unsignedAndSignedTx: exportTx, - expectedError: errFailedComplexityCumulation, - checksF: func(*testing.T, Calculator) {}, + signedTxF: exportTx, + expectedError: errFailedComplexityCumulation, + checksF: func(*testing.T, Calculator) {}, }, { name: "RewardValidatorTx pre EUpgrade", chainTime: preEUpgradeTime, - unsignedAndSignedTx: func(_ *testing.T) (txs.UnsignedTx, *txs.Tx) { - return &txs.RewardValidatorTx{ - TxID: ids.GenerateTestID(), - }, nil + signedTxF: func(_ *testing.T) *txs.Tx { + return &txs.Tx{ + Unsigned: &txs.RewardValidatorTx{ + TxID: ids.GenerateTestID(), + }, + } }, checksF: func(t *testing.T, c Calculator) { require.Equal(t, uint64(0), c.GetFee()) @@ -579,10 +580,12 @@ func TestTxFees(t *testing.T) { { name: "RewardValidatorTx post EUpgrade", chainTime: postEUpgradeTime, - unsignedAndSignedTx: func(_ *testing.T) (txs.UnsignedTx, *txs.Tx) { - return &txs.RewardValidatorTx{ - TxID: ids.GenerateTestID(), - }, nil + signedTxF: func(_ *testing.T) *txs.Tx { + return &txs.Tx{ + Unsigned: &txs.RewardValidatorTx{ + TxID: ids.GenerateTestID(), + }, + } }, checksF: func(t *testing.T, c Calculator) { require.Equal(t, uint64(0), c.GetFee()) @@ -591,10 +594,12 @@ func TestTxFees(t *testing.T) { { name: "AdvanceTimeTx pre EUpgrade", chainTime: preEUpgradeTime, - unsignedAndSignedTx: func(_ *testing.T) (txs.UnsignedTx, *txs.Tx) { - return &txs.AdvanceTimeTx{ - Time: uint64(time.Now().Unix()), - }, nil + signedTxF: func(_ *testing.T) *txs.Tx { + return &txs.Tx{ + Unsigned: &txs.AdvanceTimeTx{ + Time: uint64(time.Now().Unix()), + }, + } }, checksF: func(t *testing.T, c Calculator) { require.Equal(t, uint64(0), c.GetFee()) @@ -603,10 +608,12 @@ func TestTxFees(t *testing.T) { { name: "AdvanceTimeTx post EUpgrade", chainTime: postEUpgradeTime, - unsignedAndSignedTx: func(_ *testing.T) (txs.UnsignedTx, *txs.Tx) { - return &txs.AdvanceTimeTx{ - Time: uint64(time.Now().Unix()), - }, nil + signedTxF: func(_ *testing.T) *txs.Tx { + return &txs.Tx{ + Unsigned: &txs.AdvanceTimeTx{ + Time: uint64(time.Now().Unix()), + }, + } }, checksF: func(t *testing.T, c Calculator) { require.Equal(t, uint64(0), c.GetFee()) @@ -621,8 +628,6 @@ func TestTxFees(t *testing.T) { gasCap = tt.gasCapF() } - uTx, sTx := tt.unsignedAndSignedTx(t) - var c Calculator if !upgrades.IsEActivated(tt.chainTime) { c = NewStaticCalculator(feeTestsDefaultCfg, upgrades, tt.chainTime) @@ -630,18 +635,14 @@ func TestTxFees(t *testing.T) { c = NewDynamicCalculator(fee.NewCalculator(testFeeWeights, testGasPrice, gasCap)) } - var creds []verify.Verifiable - if sTx != nil { - // txs like RewardValidatorTx are not signed - creds = sTx.Creds - } - _, _ = c.CalculateFee(&txs.Tx{Unsigned: uTx, Creds: creds}) + sTx := tt.signedTxF(t) + _, _ = c.CalculateFee(sTx) tt.checksF(t, c) }) } } -func addValidatorTx(t *testing.T) (txs.UnsignedTx, *txs.Tx) { +func addValidatorTx(t *testing.T) *txs.Tx { r := require.New(t) defaultCtx := snowtest.Context(t, snowtest.PChainID) @@ -666,10 +667,10 @@ func addValidatorTx(t *testing.T) (txs.UnsignedTx, *txs.Tx) { sTx, err := txs.NewSigned(uTx, txs.Codec, feeTestSigners) r.NoError(err) - return uTx, sTx + return sTx } -func addSubnetValidatorTx(t *testing.T) (txs.UnsignedTx, *txs.Tx) { +func addSubnetValidatorTx(t *testing.T) *txs.Tx { r := require.New(t) defaultCtx := snowtest.Context(t, snowtest.PChainID) @@ -691,10 +692,10 @@ func addSubnetValidatorTx(t *testing.T) (txs.UnsignedTx, *txs.Tx) { } sTx, err := txs.NewSigned(uTx, txs.Codec, feeTestSigners) r.NoError(err) - return uTx, sTx + return sTx } -func addDelegatorTx(t *testing.T) (txs.UnsignedTx, *txs.Tx) { +func addDelegatorTx(t *testing.T) *txs.Tx { r := require.New(t) defaultCtx := snowtest.Context(t, snowtest.PChainID) @@ -717,10 +718,10 @@ func addDelegatorTx(t *testing.T) (txs.UnsignedTx, *txs.Tx) { } sTx, err := txs.NewSigned(uTx, txs.Codec, feeTestSigners) r.NoError(err) - return uTx, sTx + return sTx } -func createChainTx(t *testing.T) (txs.UnsignedTx, *txs.Tx) { +func createChainTx(t *testing.T) *txs.Tx { r := require.New(t) defaultCtx := snowtest.Context(t, snowtest.PChainID) @@ -737,10 +738,10 @@ func createChainTx(t *testing.T) (txs.UnsignedTx, *txs.Tx) { } sTx, err := txs.NewSigned(uTx, txs.Codec, feeTestSigners) r.NoError(err) - return uTx, sTx + return sTx } -func createSubnetTx(t *testing.T) (txs.UnsignedTx, *txs.Tx) { +func createSubnetTx(t *testing.T) *txs.Tx { r := require.New(t) defaultCtx := snowtest.Context(t, snowtest.PChainID) @@ -755,10 +756,10 @@ func createSubnetTx(t *testing.T) (txs.UnsignedTx, *txs.Tx) { } sTx, err := txs.NewSigned(uTx, txs.Codec, feeTestSigners) r.NoError(err) - return uTx, sTx + return sTx } -func removeSubnetValidatorTx(t *testing.T) (txs.UnsignedTx, *txs.Tx) { +func removeSubnetValidatorTx(t *testing.T) *txs.Tx { r := require.New(t) defaultCtx := snowtest.Context(t, snowtest.PChainID) @@ -772,10 +773,10 @@ func removeSubnetValidatorTx(t *testing.T) (txs.UnsignedTx, *txs.Tx) { } sTx, err := txs.NewSigned(uTx, txs.Codec, feeTestSigners) r.NoError(err) - return uTx, sTx + return sTx } -func transformSubnetTx(t *testing.T) (txs.UnsignedTx, *txs.Tx) { +func transformSubnetTx(t *testing.T) *txs.Tx { r := require.New(t) defaultCtx := snowtest.Context(t, snowtest.PChainID) @@ -801,10 +802,10 @@ func transformSubnetTx(t *testing.T) (txs.UnsignedTx, *txs.Tx) { } sTx, err := txs.NewSigned(uTx, txs.Codec, feeTestSigners) r.NoError(err) - return uTx, sTx + return sTx } -func transferSubnetOwnershipTx(t *testing.T) (txs.UnsignedTx, *txs.Tx) { +func transferSubnetOwnershipTx(t *testing.T) *txs.Tx { r := require.New(t) defaultCtx := snowtest.Context(t, snowtest.PChainID) @@ -826,10 +827,10 @@ func transferSubnetOwnershipTx(t *testing.T) (txs.UnsignedTx, *txs.Tx) { } sTx, err := txs.NewSigned(uTx, txs.Codec, feeTestSigners) r.NoError(err) - return uTx, sTx + return sTx } -func addPermissionlessValidatorTx(t *testing.T, subnetID ids.ID) (txs.UnsignedTx, *txs.Tx) { +func addPermissionlessValidatorTx(t *testing.T, subnetID ids.ID) *txs.Tx { r := require.New(t) defaultCtx := snowtest.Context(t, snowtest.PChainID) @@ -860,10 +861,10 @@ func addPermissionlessValidatorTx(t *testing.T, subnetID ids.ID) (txs.UnsignedTx } sTx, err := txs.NewSigned(uTx, txs.Codec, feeTestSigners) r.NoError(err) - return uTx, sTx + return sTx } -func addPermissionlessDelegatorTx(t *testing.T, subnetID ids.ID) (txs.UnsignedTx, *txs.Tx) { +func addPermissionlessDelegatorTx(t *testing.T, subnetID ids.ID) *txs.Tx { r := require.New(t) defaultCtx := snowtest.Context(t, snowtest.PChainID) @@ -889,10 +890,10 @@ func addPermissionlessDelegatorTx(t *testing.T, subnetID ids.ID) (txs.UnsignedTx } sTx, err := txs.NewSigned(uTx, txs.Codec, feeTestSigners) r.NoError(err) - return uTx, sTx + return sTx } -func baseTx(t *testing.T) (txs.UnsignedTx, *txs.Tx) { +func baseTx(t *testing.T) *txs.Tx { r := require.New(t) defaultCtx := snowtest.Context(t, snowtest.PChainID) @@ -901,10 +902,10 @@ func baseTx(t *testing.T) (txs.UnsignedTx, *txs.Tx) { uTx := &baseTx sTx, err := txs.NewSigned(uTx, txs.Codec, feeTestSigners) r.NoError(err) - return uTx, sTx + return sTx } -func importTx(t *testing.T) (txs.UnsignedTx, *txs.Tx) { +func importTx(t *testing.T) *txs.Tx { r := require.New(t) defaultCtx := snowtest.Context(t, snowtest.PChainID) @@ -927,10 +928,10 @@ func importTx(t *testing.T) (txs.UnsignedTx, *txs.Tx) { } sTx, err := txs.NewSigned(uTx, txs.Codec, feeTestSigners) r.NoError(err) - return uTx, sTx + return sTx } -func exportTx(t *testing.T) (txs.UnsignedTx, *txs.Tx) { +func exportTx(t *testing.T) *txs.Tx { r := require.New(t) defaultCtx := snowtest.Context(t, snowtest.PChainID) @@ -943,7 +944,7 @@ func exportTx(t *testing.T) (txs.UnsignedTx, *txs.Tx) { } sTx, err := txs.NewSigned(uTx, txs.Codec, feeTestSigners) r.NoError(err) - return uTx, sTx + return sTx } func txsCreationHelpers(defaultCtx *snow.Context) ( From 174185b8c6ef424f348427d7a7f3fa336966efc6 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Fri, 12 Jul 2024 10:24:42 +0200 Subject: [PATCH 188/190] nits --- vms/platformvm/state/state.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vms/platformvm/state/state.go b/vms/platformvm/state/state.go index fd1d397496de..0da0c17680ba 100644 --- a/vms/platformvm/state/state.go +++ b/vms/platformvm/state/state.go @@ -1332,7 +1332,7 @@ func (s *state) loadMetadata() error { case database.ErrNotFound: // fork introducing dynamic fees may not be active yet, - // hence we may have never stored fees windows. Set to nil + // hence we may have never stored excess complexity. Set to zero // TODO: remove once fork is active s.excessComplexity = commonfee.ZeroGas default: @@ -1350,7 +1350,7 @@ func (s *state) loadMetadata() error { case database.ErrNotFound: // fork introducing dynamic fees may not be active yet, - // hence we may have never stored fees windows. Set to nil + // hence we may have never stored gas cap. Set to max // TODO: remove once fork is active feesCfg, err := fee.GetDynamicConfig(true /*isEActive*/) if err != nil { From db7ba770e5d589c586266218e9c497aa0583e766 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Fri, 12 Jul 2024 10:24:42 +0200 Subject: [PATCH 189/190] nits --- vms/components/fee/calculator.go | 2 +- vms/platformvm/state/state.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/vms/components/fee/calculator.go b/vms/components/fee/calculator.go index 930244a0a443..0ac7f080e561 100644 --- a/vms/components/fee/calculator.go +++ b/vms/components/fee/calculator.go @@ -24,7 +24,7 @@ type Calculator struct { // gas cap enforced with adding gas via CumulateGas gasCap Gas - // Avax denominated gas price, i.e. fee per unit of complexity. + // Avax denominated gas price, i.e. fee per unit of gas. gasPrice GasPrice // cumulatedGas helps aggregating the gas consumed in a single block diff --git a/vms/platformvm/state/state.go b/vms/platformvm/state/state.go index fd1d397496de..0da0c17680ba 100644 --- a/vms/platformvm/state/state.go +++ b/vms/platformvm/state/state.go @@ -1332,7 +1332,7 @@ func (s *state) loadMetadata() error { case database.ErrNotFound: // fork introducing dynamic fees may not be active yet, - // hence we may have never stored fees windows. Set to nil + // hence we may have never stored excess complexity. Set to zero // TODO: remove once fork is active s.excessComplexity = commonfee.ZeroGas default: @@ -1350,7 +1350,7 @@ func (s *state) loadMetadata() error { case database.ErrNotFound: // fork introducing dynamic fees may not be active yet, - // hence we may have never stored fees windows. Set to nil + // hence we may have never stored gas cap. Set to max // TODO: remove once fork is active feesCfg, err := fee.GetDynamicConfig(true /*isEActive*/) if err != nil { From 45e8044065f0466ce33c4430ff49349955c37bbe Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Fri, 12 Jul 2024 10:41:47 +0200 Subject: [PATCH 190/190] nit --- vms/platformvm/txs/fee/dynamic_config.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vms/platformvm/txs/fee/dynamic_config.go b/vms/platformvm/txs/fee/dynamic_config.go index c2b63494afd1..7dac9e3b1062 100644 --- a/vms/platformvm/txs/fee/dynamic_config.go +++ b/vms/platformvm/txs/fee/dynamic_config.go @@ -22,8 +22,8 @@ var ( UpdateDenominator: commonfee.Gas(100_000), GasTargetRate: commonfee.Gas(2_500), FeeDimensionWeights: commonfee.Dimensions{6, 10, 10, 1}, - MaxGasPerSecond: commonfee.Gas(1_000_000), - LeakGasCoeff: commonfee.Gas(1), + MaxGasPerSecond: commonfee.Gas(500_000), + LeakGasCoeff: commonfee.Gas(5), } customDynamicFeesConfig *commonfee.DynamicFeesConfig