From 10d71e74ec6b1b590204e5d23cb5551e00702b2a Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 8 Jan 2024 10:33:16 +0100 Subject: [PATCH 001/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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/132] 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 c1d7dd2a8a80dc9e35b2207c9ef770c7e793ae6c Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 1 Feb 2024 18:36:41 +0100 Subject: [PATCH 102/132] wip: introducing dynamic fees config --- vms/avm/block/executor/block.go | 8 +- vms/avm/block/executor/block_test.go | 11 --- vms/avm/block/executor/manager.go | 9 +- vms/avm/block/executor/manager_test.go | 4 - vms/avm/config/config.go | 5 ++ vms/avm/config/dynamic_fees_config.go | 111 +++++++++++++++++++++++++ vms/avm/state/diff.go | 8 -- vms/avm/state/mock_state.go | 59 ------------- vms/avm/state/state.go | 19 +---- vms/avm/vm.go | 9 +- 10 files changed, 126 insertions(+), 117 deletions(-) create mode 100644 vms/avm/config/dynamic_fees_config.go diff --git a/vms/avm/block/executor/block.go b/vms/avm/block/executor/block.go index b3c4e2d1e283..1772b9b92c74 100644 --- a/vms/avm/block/executor/block.go +++ b/vms/avm/block/executor/block.go @@ -76,22 +76,18 @@ func (b *Block) Verify(context.Context) error { // Syntactic verification is generally pretty fast, so we verify this first // before performing any possible DB reads. TODO ABENEGIA: except we do DB reads now with fees stuff? + feesCfg := b.manager.backend.Config.GetDynamicFeesConfig() 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, fees.EmptyWindows) for _, tx := range txs { err := tx.Unsigned.Visit(&executor.SyntacticVerifier{ Backend: b.manager.backend, BlkFeeManager: feeManager, - UnitCaps: unitCaps, + UnitCaps: feesCfg.BlockUnitsCap, BlkTimestamp: newChainTime, Tx: tx, }) diff --git a/vms/avm/block/executor/block_test.go b/vms/avm/block/executor/block_test.go index 5c8615639427..5574b8f7477b 100644 --- a/vms/avm/block/executor/block_test.go +++ b/vms/avm/block/executor/block_test.go @@ -153,7 +153,6 @@ func TestBlockVerify(t *testing.T) { mockState := state.NewMockState(ctrl) mockState.EXPECT().GetUnitFees().Return(fees.DefaultUnitFees, nil).AnyTimes() - mockState.EXPECT().GetBlockUnitCaps().Return(fees.DefaultBlockMaxConsumedUnits, nil).AnyTimes() return &Block{ Block: mockBlock, @@ -195,7 +194,6 @@ 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, @@ -240,7 +238,6 @@ func TestBlockVerify(t *testing.T) { 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, @@ -289,7 +286,6 @@ func TestBlockVerify(t *testing.T) { mockState := state.NewMockState(ctrl) mockState.EXPECT().GetUnitFees().Return(fees.DefaultUnitFees, nil).AnyTimes() - mockState.EXPECT().GetBlockUnitCaps().Return(fees.DefaultBlockMaxConsumedUnits, nil).AnyTimes() return &Block{ Block: mockBlock, @@ -345,7 +341,6 @@ func TestBlockVerify(t *testing.T) { 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) @@ -406,7 +401,6 @@ func TestBlockVerify(t *testing.T) { 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) @@ -494,7 +488,6 @@ func TestBlockVerify(t *testing.T) { 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) @@ -566,7 +559,6 @@ func TestBlockVerify(t *testing.T) { mockState := state.NewMockState(ctrl) mockState.EXPECT().GetUnitFees().Return(fees.DefaultUnitFees, nil).AnyTimes() - mockState.EXPECT().GetBlockUnitCaps().Return(fees.DefaultBlockMaxConsumedUnits, nil).AnyTimes() return &Block{ Block: mockBlock, @@ -624,7 +616,6 @@ func TestBlockVerify(t *testing.T) { 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}) @@ -1003,7 +994,6 @@ func TestBlockReject(t *testing.T) { 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, @@ -1067,7 +1057,6 @@ func TestBlockReject(t *testing.T) { 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 7863022b8cdc..b10e4740fce8 100644 --- a/vms/avm/block/executor/manager.go +++ b/vms/avm/block/executor/manager.go @@ -148,12 +148,9 @@ func (m *manager) VerifyTx(tx *txs.Tx) error { return ErrChainNotSynced } - unitFees, err := m.state.GetUnitFees() - if err != nil { - return err - } + feesCfg := m.backend.Config.GetDynamicFeesConfig() - unitCaps, err := m.state.GetBlockUnitCaps() + unitFees, err := m.state.GetUnitFees() if err != nil { return err } @@ -161,7 +158,7 @@ func (m *manager) VerifyTx(tx *txs.Tx) error { err = tx.Unsigned.Visit(&executor.SyntacticVerifier{ Backend: m.backend, BlkFeeManager: fees.NewManager(unitFees, fees.EmptyWindows), - UnitCaps: unitCaps, + UnitCaps: feesCfg.BlockUnitsCap, BlkTimestamp: m.state.GetTimestamp(), Tx: tx, }) diff --git a/vms/avm/block/executor/manager_test.go b/vms/avm/block/executor/manager_test.go index 34012cb0264b..83fe00649c2d 100644 --- a/vms/avm/block/executor/manager_test.go +++ b/vms/avm/block/executor/manager_test.go @@ -150,7 +150,6 @@ func TestManagerVerifyTx(t *testing.T) { 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{ @@ -185,7 +184,6 @@ func TestManagerVerifyTx(t *testing.T) { 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{ @@ -223,7 +221,6 @@ func TestManagerVerifyTx(t *testing.T) { 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{ @@ -261,7 +258,6 @@ func TestManagerVerifyTx(t *testing.T) { 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/config/config.go b/vms/avm/config/config.go index b4da6e3781ea..f371373e24d1 100644 --- a/vms/avm/config/config.go +++ b/vms/avm/config/config.go @@ -23,3 +23,8 @@ type Config struct { func (c *Config) IsEForkActivated(timestamp time.Time) bool { return !timestamp.Before(c.EForkTime) } + +// TODO ABENEGIA: consider structuring this method to handle forks (or is it YAGNI?) +func (*Config) GetDynamicFeesConfig() DynamicFeesConfig { + return EForkDynamicFeesConfig +} diff --git a/vms/avm/config/dynamic_fees_config.go b/vms/avm/config/dynamic_fees_config.go new file mode 100644 index 000000000000..5db0b5c7db8f --- /dev/null +++ b/vms/avm/config/dynamic_fees_config.go @@ -0,0 +1,111 @@ +// 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, + }, + + MinUnitFees: commonfees.Dimensions{}, + + FeesChangeDenominator: commonfees.Dimensions{ + 1, + 1, + 1, + 1, + }, + + 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.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, + 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/avm/state/diff.go b/vms/avm/state/diff.go index 911bc1e1000f..ad96fae8b8fd 100644 --- a/vms/avm/state/diff.go +++ b/vms/avm/state/diff.go @@ -170,14 +170,6 @@ func (d *diff) GetUnitFees() (commonfees.Dimensions, error) { 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 5d281e470c73..73148cea657a 100644 --- a/vms/avm/state/mock_state.go +++ b/vms/avm/state/mock_state.go @@ -125,21 +125,6 @@ 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() @@ -408,21 +393,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)) -} - // GetLastAccepted mocks base method. func (m *MockState) GetLastAccepted() ids.ID { m.ctrl.T.Helper() @@ -539,20 +509,6 @@ 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() @@ -733,21 +689,6 @@ 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() diff --git a/vms/avm/state/state.go b/vms/avm/state/state.go index 141abbd8343e..099d0b7a61b6 100644 --- a/vms/avm/state/state.go +++ b/vms/avm/state/state.go @@ -74,7 +74,6 @@ type ReadOnlyChain interface { // 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 { @@ -107,7 +106,6 @@ type State interface { // 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() @@ -184,10 +182,7 @@ 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 + unitFees commonfees.Dimensions trackChecksum bool txChecksum ids.ID @@ -272,8 +267,7 @@ func New( singletonDB: singletonDB, - unitFees: fees.DefaultUnitFees, - blockUnitCaps: fees.DefaultBlockMaxConsumedUnits, + unitFees: fees.DefaultUnitFees, trackChecksum: trackChecksums, } @@ -528,15 +522,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) Commit() error { defer s.Abort() batch, err := s.CommitBatch() diff --git a/vms/avm/vm.go b/vms/avm/vm.go index 6c2ffc1262f9..2ca80d7f1c18 100644 --- a/vms/avm/vm.go +++ b/vms/avm/vm.go @@ -490,12 +490,9 @@ 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 - } + feesCfg := vm.Config.GetDynamicFeesConfig() - unitCaps, err := vm.state.GetBlockUnitCaps() + unitFees, err := vm.state.GetUnitFees() if err != nil { return nil, err } @@ -503,7 +500,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, fees.EmptyWindows), - UnitCaps: unitCaps, + UnitCaps: feesCfg.BlockUnitsCap, BlkTimestamp: vm.state.GetTimestamp(), Tx: tx, }) From e10904103d7387d48f1428d03b4ae17c551f4aa5 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 1 Feb 2024 19:16:42 +0100 Subject: [PATCH 103/132] wip: persisting dynamic unit fees and windows --- vms/avm/block/builder/builder_test.go | 6 +- vms/avm/block/executor/block.go | 12 +-- vms/avm/block/executor/block_test.go | 36 +++++--- vms/avm/block/executor/manager.go | 15 ++- vms/avm/block/executor/manager_test.go | 14 ++- vms/avm/state/diff.go | 28 ++++-- vms/avm/state/mock_state.go | 123 ++++++++++++++++++++++--- vms/avm/state/state.go | 79 +++++++++++++--- vms/avm/state/state_test.go | 12 ++- vms/avm/txs/executor/executor_test.go | 10 +- vms/avm/txs/fees/calculator.go | 19 ---- vms/avm/vm.go | 14 +-- 12 files changed, 266 insertions(+), 102 deletions(-) diff --git a/vms/avm/block/builder/builder_test.go b/vms/avm/block/builder/builder_test.go index 185c93260eca..983a942fd641 100644 --- a/vms/avm/block/builder/builder_test.go +++ b/vms/avm/block/builder/builder_test.go @@ -27,6 +27,7 @@ import ( "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/config" "github.com/ava-labs/avalanchego/vms/avm/fxs" "github.com/ava-labs/avalanchego/vms/avm/metrics" "github.com/ava-labs/avalanchego/vms/avm/state" @@ -526,12 +527,13 @@ func TestBlockBuilderAddLocalTx(t *testing.T) { Ctx: &snow.Context{ Log: logging.NoLog{}, }, - Codec: parser.Codec(), + Config: &config.Config{}, + Codec: parser.Codec(), } baseDB := versiondb.New(memdb.New()) - state, err := state.New(baseDB, parser, registerer, trackChecksums) + state, err := state.New(baseDB, parser, registerer, *backend.Config, trackChecksums) require.NoError(err) clk := &mockable.Clock{} diff --git a/vms/avm/block/executor/block.go b/vms/avm/block/executor/block.go index 1772b9b92c74..6af377d2f742 100644 --- a/vms/avm/block/executor/block.go +++ b/vms/avm/block/executor/block.go @@ -76,13 +76,13 @@ func (b *Block) Verify(context.Context) error { // Syntactic verification is generally pretty fast, so we verify this first // before performing any possible DB reads. TODO ABENEGIA: except we do DB reads now with fees stuff? - feesCfg := b.manager.backend.Config.GetDynamicFeesConfig() - unitFees, err := b.manager.state.GetUnitFees() - if err != nil { - return err - } + var ( + feesCfg = b.manager.backend.Config.GetDynamicFeesConfig() + unitFees = b.manager.state.GetUnitFees() + feeWindows = b.manager.state.GetFeeWindows() + ) - feeManager := fees.NewManager(unitFees, fees.EmptyWindows) + feeManager := fees.NewManager(unitFees, feeWindows) for _, tx := range txs { err := tx.Unsigned.Visit(&executor.SyntacticVerifier{ Backend: b.manager.backend, diff --git a/vms/avm/block/executor/block_test.go b/vms/avm/block/executor/block_test.go index 5574b8f7477b..1be5b5bcec31 100644 --- a/vms/avm/block/executor/block_test.go +++ b/vms/avm/block/executor/block_test.go @@ -28,8 +28,9 @@ 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" + + commonfees "github.com/ava-labs/avalanchego/vms/components/fees" ) func TestBlockVerify(t *testing.T) { @@ -152,7 +153,8 @@ func TestBlockVerify(t *testing.T) { mempool.EXPECT().MarkDropped(errTx.ID(), errTest).Times(1) mockState := state.NewMockState(ctrl) - mockState.EXPECT().GetUnitFees().Return(fees.DefaultUnitFees, nil).AnyTimes() + mockState.EXPECT().GetUnitFees().Return(commonfees.Empty).AnyTimes() + mockState.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows).AnyTimes() return &Block{ Block: mockBlock, @@ -193,7 +195,8 @@ 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().GetUnitFees().Return(commonfees.Empty).AnyTimes() + mockState.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows).AnyTimes() return &Block{ Block: mockBlock, @@ -237,7 +240,8 @@ func TestBlockVerify(t *testing.T) { mockState := state.NewMockState(ctrl) mockState.EXPECT().GetBlock(parentID).Return(mockParentBlock, nil) - mockState.EXPECT().GetUnitFees().Return(fees.DefaultUnitFees, nil).AnyTimes() + mockState.EXPECT().GetUnitFees().Return(commonfees.Empty).AnyTimes() + mockState.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows).AnyTimes() return &Block{ Block: mockBlock, @@ -285,7 +289,8 @@ func TestBlockVerify(t *testing.T) { mockParentState.EXPECT().GetTimestamp().Return(blockTimestamp.Add(1)) mockState := state.NewMockState(ctrl) - mockState.EXPECT().GetUnitFees().Return(fees.DefaultUnitFees, nil).AnyTimes() + mockState.EXPECT().GetUnitFees().Return(commonfees.Empty).AnyTimes() + mockState.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows).AnyTimes() return &Block{ Block: mockBlock, @@ -340,7 +345,8 @@ func TestBlockVerify(t *testing.T) { mockParentState.EXPECT().GetTimestamp().Return(blockTimestamp) mockState := state.NewMockState(ctrl) - mockState.EXPECT().GetUnitFees().Return(fees.DefaultUnitFees, nil).AnyTimes() + mockState.EXPECT().GetUnitFees().Return(commonfees.Empty).AnyTimes() + mockState.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows).AnyTimes() mempool := mempool.NewMockMempool(ctrl) mempool.EXPECT().MarkDropped(tx.ID(), errTest).Times(1) @@ -400,7 +406,8 @@ func TestBlockVerify(t *testing.T) { mockParentState.EXPECT().GetTimestamp().Return(blockTimestamp) mockState := state.NewMockState(ctrl) - mockState.EXPECT().GetUnitFees().Return(fees.DefaultUnitFees, nil).AnyTimes() + mockState.EXPECT().GetUnitFees().Return(commonfees.Empty).AnyTimes() + mockState.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows).AnyTimes() mempool := mempool.NewMockMempool(ctrl) mempool.EXPECT().MarkDropped(tx.ID(), errTest).Times(1) @@ -487,7 +494,8 @@ func TestBlockVerify(t *testing.T) { mockParentState.EXPECT().GetTimestamp().Return(blockTimestamp) mockState := state.NewMockState(ctrl) - mockState.EXPECT().GetUnitFees().Return(fees.DefaultUnitFees, nil).AnyTimes() + mockState.EXPECT().GetUnitFees().Return(commonfees.Empty).AnyTimes() + mockState.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows).AnyTimes() mempool := mempool.NewMockMempool(ctrl) mempool.EXPECT().MarkDropped(tx2.ID(), ErrConflictingBlockTxs).Times(1) @@ -558,7 +566,8 @@ func TestBlockVerify(t *testing.T) { mockParentState.EXPECT().GetTimestamp().Return(blockTimestamp) mockState := state.NewMockState(ctrl) - mockState.EXPECT().GetUnitFees().Return(fees.DefaultUnitFees, nil).AnyTimes() + mockState.EXPECT().GetUnitFees().Return(commonfees.Empty).AnyTimes() + mockState.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows).AnyTimes() return &Block{ Block: mockBlock, @@ -615,7 +624,8 @@ func TestBlockVerify(t *testing.T) { mockParentState.EXPECT().GetTimestamp().Return(blockTimestamp) mockState := state.NewMockState(ctrl) - mockState.EXPECT().GetUnitFees().Return(fees.DefaultUnitFees, nil).AnyTimes() + mockState.EXPECT().GetUnitFees().Return(commonfees.Empty).AnyTimes() + mockState.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows).AnyTimes() mockMempool := mempool.NewMockMempool(ctrl) mockMempool.EXPECT().Remove([]*txs.Tx{tx}) @@ -993,7 +1003,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().GetUnitFees().Return(commonfees.Empty).AnyTimes() + mockState.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows).AnyTimes() return &Block{ Block: mockBlock, @@ -1056,7 +1067,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().GetUnitFees().Return(commonfees.Empty).AnyTimes() + mockState.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows).AnyTimes() return &Block{ Block: mockBlock, diff --git a/vms/avm/block/executor/manager.go b/vms/avm/block/executor/manager.go index b10e4740fce8..a9ba59b83277 100644 --- a/vms/avm/block/executor/manager.go +++ b/vms/avm/block/executor/manager.go @@ -148,16 +148,15 @@ func (m *manager) VerifyTx(tx *txs.Tx) error { return ErrChainNotSynced } - feesCfg := m.backend.Config.GetDynamicFeesConfig() + var ( + feesCfg = m.backend.Config.GetDynamicFeesConfig() + unitFees = m.state.GetUnitFees() + feeWindows = m.state.GetFeeWindows() + ) - unitFees, err := m.state.GetUnitFees() - if err != nil { - return err - } - - err = tx.Unsigned.Visit(&executor.SyntacticVerifier{ + err := tx.Unsigned.Visit(&executor.SyntacticVerifier{ Backend: m.backend, - BlkFeeManager: fees.NewManager(unitFees, fees.EmptyWindows), + BlkFeeManager: fees.NewManager(unitFees, feeWindows), UnitCaps: feesCfg.BlockUnitsCap, BlkTimestamp: m.state.GetTimestamp(), Tx: tx, diff --git a/vms/avm/block/executor/manager_test.go b/vms/avm/block/executor/manager_test.go index 83fe00649c2d..49269744ad7c 100644 --- a/vms/avm/block/executor/manager_test.go +++ b/vms/avm/block/executor/manager_test.go @@ -20,7 +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" + commonfees "github.com/ava-labs/avalanchego/vms/components/fees" ) var ( @@ -149,7 +149,8 @@ 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().GetUnitFees().Return(commonfees.Empty).AnyTimes() + state.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows).AnyTimes() return &manager{ backend: &executor.Backend{ @@ -183,7 +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().GetUnitFees().Return(commonfees.Empty).AnyTimes() + state.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows).AnyTimes() return &manager{ backend: &executor.Backend{ @@ -220,7 +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().GetUnitFees().Return(commonfees.Empty).AnyTimes() + state.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows).AnyTimes() return &manager{ backend: &executor.Backend{ @@ -257,7 +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().GetUnitFees().Return(commonfees.Empty).AnyTimes() + state.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows).AnyTimes() return &manager{ backend: &executor.Backend{ diff --git a/vms/avm/state/diff.go b/vms/avm/state/diff.go index ad96fae8b8fd..41e1535a8814 100644 --- a/vms/avm/state/diff.go +++ b/vms/avm/state/diff.go @@ -39,8 +39,10 @@ type diff struct { addedBlockIDs map[uint64]ids.ID // map of height -> blockID addedBlocks map[ids.ID]block.Block // map of blockID -> block - lastAccepted ids.ID - timestamp time.Time + lastAccepted ids.ID + timestamp time.Time + unitFees commonfees.Dimensions + consumedUnitsWindows commonfees.Windows } func NewDiff( @@ -162,12 +164,20 @@ 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) GetUnitFees() commonfees.Dimensions { + return d.unitFees +} + +func (d *diff) SetUnitFees(uf commonfees.Dimensions) { + d.unitFees = uf +} + +func (d *diff) GetFeeWindows() commonfees.Windows { + return d.consumedUnitsWindows +} + +func (d *diff) SetConsumedUnitsWindows(windows commonfees.Windows) { + d.consumedUnitsWindows = windows } func (d *diff) Apply(state Chain) { @@ -189,4 +199,6 @@ func (d *diff) Apply(state Chain) { state.SetLastAccepted(d.lastAccepted) state.SetTimestamp(d.timestamp) + state.SetUnitFees(d.unitFees) + state.SetConsumedUnitsWindows(d.consumedUnitsWindows) } diff --git a/vms/avm/state/mock_state.go b/vms/avm/state/mock_state.go index 73148cea657a..96595571a452 100644 --- a/vms/avm/state/mock_state.go +++ b/vms/avm/state/mock_state.go @@ -125,6 +125,20 @@ func (mr *MockChainMockRecorder) GetBlockIDAtHeight(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBlockIDAtHeight", reflect.TypeOf((*MockChain)(nil).GetBlockIDAtHeight), arg0) } +// 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)) +} + // GetLastAccepted mocks base method. func (m *MockChain) GetLastAccepted() ids.ID { m.ctrl.T.Helper() @@ -184,12 +198,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. @@ -198,6 +211,18 @@ func (mr *MockChainMockRecorder) GetUnitFees() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUnitFees", reflect.TypeOf((*MockChain)(nil).GetUnitFees)) } +// 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) +} + // SetLastAccepted mocks base method. func (m *MockChain) SetLastAccepted(arg0 ids.ID) { m.ctrl.T.Helper() @@ -222,6 +247,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) +} + // MockState is a mock of State interface. type MockState struct { ctrl *gomock.Controller @@ -393,6 +430,20 @@ func (mr *MockStateMockRecorder) GetBlockIDAtHeight(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBlockIDAtHeight", reflect.TypeOf((*MockState)(nil).GetBlockIDAtHeight), arg0) } +// 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() @@ -452,12 +503,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. @@ -509,6 +559,18 @@ func (mr *MockStateMockRecorder) Prune(arg0, arg1 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Prune", reflect.TypeOf((*MockState)(nil).Prune), arg0, arg1) } +// 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) +} + // SetInitialized mocks base method. func (m *MockState) SetInitialized() error { m.ctrl.T.Helper() @@ -548,11 +610,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. @@ -689,6 +749,20 @@ func (mr *MockDiffMockRecorder) GetBlockIDAtHeight(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBlockIDAtHeight", reflect.TypeOf((*MockDiff)(nil).GetBlockIDAtHeight), arg0) } +// 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)) +} + // GetLastAccepted mocks base method. func (m *MockDiff) GetLastAccepted() ids.ID { m.ctrl.T.Helper() @@ -748,12 +822,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. @@ -762,6 +835,18 @@ func (mr *MockDiffMockRecorder) GetUnitFees() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUnitFees", reflect.TypeOf((*MockDiff)(nil).GetUnitFees)) } +// 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) +} + // SetLastAccepted mocks base method. func (m *MockDiff) SetLastAccepted(arg0 ids.ID) { m.ctrl.T.Helper() @@ -785,3 +870,15 @@ func (mr *MockDiffMockRecorder) SetTimestamp(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() 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) +} diff --git a/vms/avm/state/state.go b/vms/avm/state/state.go index 099d0b7a61b6..2c14af468b8b 100644 --- a/vms/avm/state/state.go +++ b/vms/avm/state/state.go @@ -26,8 +26,8 @@ import ( "github.com/ava-labs/avalanchego/utils/logging" "github.com/ava-labs/avalanchego/utils/timer" "github.com/ava-labs/avalanchego/vms/avm/block" + "github.com/ava-labs/avalanchego/vms/avm/config" "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" @@ -57,6 +57,8 @@ var ( isInitializedKey = []byte{0x00} timestampKey = []byte{0x01} lastAcceptedKey = []byte{0x02} + unitFeesKey = []byte{0x03} + feesWindowsKey = []byte{0x04} errStatusWithoutTx = errors.New("unexpected status without transactions") @@ -72,8 +74,8 @@ type ReadOnlyChain interface { GetLastAccepted() ids.ID GetTimestamp() time.Time - // at this iteration we don't need to reset these, we are just metering - GetUnitFees() (commonfees.Dimensions, error) + GetUnitFees() commonfees.Dimensions + GetFeeWindows() commonfees.Windows } type Chain interface { @@ -85,6 +87,9 @@ type Chain interface { AddBlock(block block.Block) SetLastAccepted(blkID ids.ID) SetTimestamp(t time.Time) + + SetUnitFees(uf commonfees.Dimensions) + SetConsumedUnitsWindows(windows commonfees.Windows) } // State persistently maintains a set of UTXOs, transaction, statuses, and @@ -104,9 +109,6 @@ 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 - // Discard uncommitted changes to the database. Abort() @@ -154,6 +156,7 @@ type State interface { * '-- lastAcceptedKey -> lastAccepted */ type state struct { + cfg config.Config parser block.Parser db *versiondb.Database @@ -182,7 +185,8 @@ type state struct { timestamp, persistedTimestamp time.Time singletonDB database.Database - unitFees commonfees.Dimensions + unitFees commonfees.Dimensions + feesWindows commonfees.Windows trackChecksum bool txChecksum ids.ID @@ -192,6 +196,7 @@ func New( db *versiondb.Database, parser block.Parser, metrics prometheus.Registerer, + cfg config.Config, trackChecksums bool, ) (State, error) { utxoDB := prefixdb.New(utxoPrefix, db) @@ -244,6 +249,7 @@ func New( s := &state{ parser: parser, + cfg: cfg, db: db, modifiedUTXOs: make(map[ids.ID]*avax.UTXO), @@ -265,10 +271,7 @@ func New( blockCache: blockCache, blockDB: blockDB, - singletonDB: singletonDB, - - unitFees: fees.DefaultUnitFees, - + singletonDB: singletonDB, trackChecksum: trackChecksums, } return s, s.initTxChecksum() @@ -486,6 +489,39 @@ func (s *state) initializeChainState(stopVertexID ids.ID, genesisTimestamp time. s.SetLastAccepted(genesis.ID()) s.SetTimestamp(genesis.Timestamp()) s.AddBlock(genesis) + + 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 + } + return s.Commit() } @@ -513,13 +549,20 @@ func (s *state) SetTimestamp(t time.Time) { s.timestamp = t } -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) GetFeeWindows() commonfees.Windows { + return s.feesWindows +} + +func (s *state) SetConsumedUnitsWindows(windows commonfees.Windows) { + s.feesWindows = windows } func (s *state) Commit() error { @@ -633,6 +676,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.persistedLastAccepted != s.lastAccepted { if err := database.PutID(s.singletonDB, lastAcceptedKey, s.lastAccepted); err != nil { return fmt.Errorf("failed to write last accepted: %w", err) diff --git a/vms/avm/state/state_test.go b/vms/avm/state/state_test.go index 758e55ffd7cd..bf7be512bfc7 100644 --- a/vms/avm/state/state_test.go +++ b/vms/avm/state/state_test.go @@ -17,6 +17,7 @@ import ( "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/version" "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" @@ -102,9 +103,10 @@ func (v *versions) GetState(blkID ids.ID) (Chain, bool) { func TestState(t *testing.T) { require := require.New(t) + cfg := config.Config{} db := memdb.New() vdb := versiondb.New(db) - s, err := New(vdb, parser, prometheus.NewRegistry(), trackChecksums) + s, err := New(vdb, parser, prometheus.NewRegistry(), cfg, trackChecksums) require.NoError(err) s.AddUTXO(populatedUTXO) @@ -112,7 +114,7 @@ func TestState(t *testing.T) { s.AddBlock(populatedBlk) require.NoError(s.Commit()) - s, err = New(vdb, parser, prometheus.NewRegistry(), trackChecksums) + s, err = New(vdb, parser, prometheus.NewRegistry(), cfg, trackChecksums) require.NoError(err) ChainUTXOTest(t, s) @@ -123,9 +125,10 @@ func TestState(t *testing.T) { func TestDiff(t *testing.T) { require := require.New(t) + cfg := config.Config{} db := memdb.New() vdb := versiondb.New(db) - s, err := New(vdb, parser, prometheus.NewRegistry(), trackChecksums) + s, err := New(vdb, parser, prometheus.NewRegistry(), cfg, trackChecksums) require.NoError(err) s.AddUTXO(populatedUTXO) @@ -283,9 +286,10 @@ func ChainBlockTest(t *testing.T, c Chain) { func TestInitializeChainState(t *testing.T) { require := require.New(t) + cfg := config.Config{} db := memdb.New() vdb := versiondb.New(db) - s, err := New(vdb, parser, prometheus.NewRegistry(), trackChecksums) + s, err := New(vdb, parser, prometheus.NewRegistry(), cfg, trackChecksums) require.NoError(err) stopVertexID := ids.GenerateTestID() diff --git a/vms/avm/txs/executor/executor_test.go b/vms/avm/txs/executor/executor_test.go index 66d210b40cb8..3c296bcaed9d 100644 --- a/vms/avm/txs/executor/executor_test.go +++ b/vms/avm/txs/executor/executor_test.go @@ -19,6 +19,7 @@ import ( "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" "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/state" "github.com/ava-labs/avalanchego/vms/avm/txs" @@ -45,10 +46,11 @@ func TestBaseTxExecutor(t *testing.T) { require.NoError(err) codec := parser.Codec() + cfg := config.Config{} db := memdb.New() vdb := versiondb.New(db) registerer := prometheus.NewRegistry() - state, err := state.New(vdb, parser, registerer, trackChecksums) + state, err := state.New(vdb, parser, registerer, cfg, trackChecksums) require.NoError(err) utxoID := avax.UTXOID{ @@ -153,10 +155,11 @@ func TestCreateAssetTxExecutor(t *testing.T) { require.NoError(err) codec := parser.Codec() + cfg := config.Config{} db := memdb.New() vdb := versiondb.New(db) registerer := prometheus.NewRegistry() - state, err := state.New(vdb, parser, registerer, trackChecksums) + state, err := state.New(vdb, parser, registerer, cfg, trackChecksums) require.NoError(err) utxoID := avax.UTXOID{ @@ -299,10 +302,11 @@ func TestOperationTxExecutor(t *testing.T) { require.NoError(err) codec := parser.Codec() + cfg := config.Config{} db := memdb.New() vdb := versiondb.New(db) registerer := prometheus.NewRegistry() - state, err := state.New(vdb, parser, registerer, trackChecksums) + state, err := state.New(vdb, parser, registerer, cfg, trackChecksums) require.NoError(err) outputOwners := secp256k1fx.OutputOwners{ diff --git a/vms/avm/txs/fees/calculator.go b/vms/avm/txs/fees/calculator.go index dffc194e4d13..fe271bb84fd2 100644 --- a/vms/avm/txs/fees/calculator.go +++ b/vms/avm/txs/fees/calculator.go @@ -6,7 +6,6 @@ package fees import ( "errors" "fmt" - "math" "github.com/ava-labs/avalanchego/codec" "github.com/ava-labs/avalanchego/vms/avm/config" @@ -19,24 +18,6 @@ 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") ) diff --git a/vms/avm/vm.go b/vms/avm/vm.go index 2ca80d7f1c18..63c92363e4ec 100644 --- a/vms/avm/vm.go +++ b/vms/avm/vm.go @@ -238,6 +238,7 @@ func (vm *VM) Initialize( vm.db, vm.parser, vm.registerer, + vm.Config, avmConfig.ChecksumsEnabled, ) if err != nil { @@ -490,16 +491,15 @@ func (vm *VM) ParseTx(_ context.Context, bytes []byte) (snowstorm.Tx, error) { return nil, err } - feesCfg := vm.Config.GetDynamicFeesConfig() - - unitFees, err := vm.state.GetUnitFees() - if err != nil { - return nil, err - } + var ( + feesCfg = vm.Config.GetDynamicFeesConfig() + unitFees = vm.state.GetUnitFees() + feeWindows = vm.state.GetFeeWindows() + ) err = tx.Unsigned.Visit(&txexecutor.SyntacticVerifier{ Backend: vm.txBackend, - BlkFeeManager: fees.NewManager(unitFees, fees.EmptyWindows), + BlkFeeManager: fees.NewManager(unitFees, feeWindows), UnitCaps: feesCfg.BlockUnitsCap, BlkTimestamp: vm.state.GetTimestamp(), Tx: tx, From f995750a640b44d0fa9229c5395683ee262099cc Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Fri, 16 Feb 2024 15:08:15 +0100 Subject: [PATCH 104/132] nit --- vms/avm/state/diff.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/vms/avm/state/diff.go b/vms/avm/state/diff.go index e1d2c0ac8a65..a7902b21a233 100644 --- a/vms/avm/state/diff.go +++ b/vms/avm/state/diff.go @@ -234,6 +234,10 @@ func (d *diff) Apply(state Chain) { state.SetLastAccepted(d.lastAccepted) state.SetTimestamp(d.timestamp) - state.SetUnitFees(*d.unitFees) - state.SetFeeWindows(*d.feesWindows) + if d.unitFees != nil { + state.SetUnitFees(*d.unitFees) + } + if d.feesWindows != nil { + state.SetFeeWindows(*d.feesWindows) + } } From 23e5cf5990e1230a51ad2f6403bf760c40bb2185 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Fri, 16 Feb 2024 16:18:34 +0100 Subject: [PATCH 105/132] Merge branch 'x-chain_meter_fees' into x-chain_units-fees-update --- vms/avm/utxo/spender.go | 14 ++ wallet/chain/x/builder_dynamic_fees.go | 67 ++------ wallet/chain/x/builder_dynamic_fees_test.go | 163 ++++++++++---------- 3 files changed, 110 insertions(+), 134 deletions(-) diff --git a/vms/avm/utxo/spender.go b/vms/avm/utxo/spender.go index b40c1beebd96..1ef81063a434 100644 --- a/vms/avm/utxo/spender.go +++ b/vms/avm/utxo/spender.go @@ -6,6 +6,7 @@ package utxo import ( "errors" "fmt" + "slices" "github.com/ava-labs/avalanchego/codec" "github.com/ava-labs/avalanchego/ids" @@ -138,6 +139,19 @@ func (s *spender) FinanceTx( keys = [][]*secp256k1.PrivateKey{} ) + // 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() == feeAssetID && rhs.Asset.AssetID() != feeAssetID: + return 1 + case lhs.Asset.AssetID() != feeAssetID && rhs.Asset.AssetID() == feeAssetID: + return -1 + default: + return 0 + } + }) + // Iterate over the UTXOs for _, utxo := range utxos { assetID := utxo.AssetID() diff --git a/wallet/chain/x/builder_dynamic_fees.go b/wallet/chain/x/builder_dynamic_fees.go index 0c70aa0f4174..2f971bb044e9 100644 --- a/wallet/chain/x/builder_dynamic_fees.go +++ b/wallet/chain/x/builder_dynamic_fees.go @@ -38,7 +38,7 @@ func NewDynamicFeesBuilder(addrs set.Set[ids.ShortID], backend BuilderBackend) * func (b *DynamicFeesBuilder) NewBaseTx( outputs []*avax.TransferableOutput, - unitFees, unitCaps commonfees.Dimensions, + feeCalc *fees.Calculator, options ...common.Option, ) (*txs.BaseTx, error) { // 1. Build core transaction without utxos @@ -64,14 +64,6 @@ func (b *DynamicFeesBuilder) NewBaseTx( toBurn[assetID] = amountToBurn } - feesMan := commonfees.NewManager(unitFees, commonfees.EmptyWindows) - feeCalc := &fees.Calculator{ - IsEUpgradeActive: 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 @@ -95,7 +87,7 @@ func (b *DynamicFeesBuilder) NewCreateAssetTx( symbol string, denomination byte, initialState map[uint32][]verify.State, - unitFees, unitCaps commonfees.Dimensions, + feeCalc *fees.Calculator, options ...common.Option, ) (*txs.CreateAssetTx, error) { // 1. Build core transaction without utxos @@ -128,13 +120,6 @@ 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, commonfees.EmptyWindows) - feeCalc := &fees.Calculator{ - IsEUpgradeActive: 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 { @@ -154,7 +139,7 @@ func (b *DynamicFeesBuilder) NewCreateAssetTx( func (b *DynamicFeesBuilder) NewOperationTx( operations []*txs.Operation, - unitFees, unitCaps commonfees.Dimensions, + feeCalc *fees.Calculator, options ...common.Option, ) (*txs.OperationTx, error) { // 1. Build core transaction without utxos @@ -173,13 +158,6 @@ 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, commonfees.EmptyWindows) - feeCalc := &fees.Calculator{ - IsEUpgradeActive: 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 { @@ -199,7 +177,7 @@ func (b *DynamicFeesBuilder) NewOperationTx( func (b *DynamicFeesBuilder) NewOperationTxMintFT( outputs map[ids.ID]*secp256k1fx.TransferOutput, - unitFees, unitCaps commonfees.Dimensions, + feeCalc *fees.Calculator, options ...common.Option, ) (*txs.OperationTx, error) { ops := common.NewOptions(options) @@ -209,8 +187,7 @@ func (b *DynamicFeesBuilder) NewOperationTxMintFT( } return b.NewOperationTx( operations, - unitFees, - unitCaps, + feeCalc, options..., ) } @@ -219,7 +196,7 @@ func (b *DynamicFeesBuilder) NewOperationTxMintNFT( assetID ids.ID, payload []byte, owners []*secp256k1fx.OutputOwners, - unitFees, unitCaps commonfees.Dimensions, + feeCalc *fees.Calculator, options ...common.Option, ) (*txs.OperationTx, error) { ops := common.NewOptions(options) @@ -229,8 +206,7 @@ func (b *DynamicFeesBuilder) NewOperationTxMintNFT( } return b.NewOperationTx( operations, - unitFees, - unitCaps, + feeCalc, options..., ) } @@ -238,7 +214,7 @@ func (b *DynamicFeesBuilder) NewOperationTxMintNFT( func (b *DynamicFeesBuilder) NewOperationTxMintProperty( assetID ids.ID, owner *secp256k1fx.OutputOwners, - unitFees, unitCaps commonfees.Dimensions, + feeCalc *fees.Calculator, options ...common.Option, ) (*txs.OperationTx, error) { ops := common.NewOptions(options) @@ -248,15 +224,14 @@ func (b *DynamicFeesBuilder) NewOperationTxMintProperty( } return b.NewOperationTx( operations, - unitFees, - unitCaps, + feeCalc, options..., ) } func (b *DynamicFeesBuilder) NewOperationTxBurnProperty( assetID ids.ID, - unitFees, unitCaps commonfees.Dimensions, + feeCalc *fees.Calculator, options ...common.Option, ) (*txs.OperationTx, error) { ops := common.NewOptions(options) @@ -266,8 +241,7 @@ func (b *DynamicFeesBuilder) NewOperationTxBurnProperty( } return b.NewOperationTx( operations, - unitFees, - unitCaps, + feeCalc, options..., ) } @@ -275,7 +249,7 @@ func (b *DynamicFeesBuilder) NewOperationTxBurnProperty( func (b *DynamicFeesBuilder) NewImportTx( sourceChainID ids.ID, to *secp256k1fx.OutputOwners, - unitFees, unitCaps commonfees.Dimensions, + feeCalc *fees.Calculator, options ...common.Option, ) (*txs.ImportTx, error) { ops := common.NewOptions(options) @@ -364,13 +338,6 @@ func (b *DynamicFeesBuilder) NewImportTx( } // 3. Finance fees as much as possible with imported, Avax-denominated UTXOs - feesMan := commonfees.NewManager(unitFees, commonfees.EmptyWindows) - feeCalc := &fees.Calculator{ - IsEUpgradeActive: 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 { @@ -448,7 +415,7 @@ func (b *DynamicFeesBuilder) NewImportTx( func (b *DynamicFeesBuilder) NewExportTx( chainID ids.ID, outputs []*avax.TransferableOutput, - unitFees, unitCaps commonfees.Dimensions, + feeCalc *fees.Calculator, options ...common.Option, ) (*txs.ExportTx, error) { // 1. Build core transaction without utxos @@ -476,14 +443,6 @@ func (b *DynamicFeesBuilder) NewExportTx( toBurn[assetID] = amountToBurn } - feesMan := commonfees.NewManager(unitFees, commonfees.EmptyWindows) - feeCalc := &fees.Calculator{ - IsEUpgradeActive: 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 diff --git a/wallet/chain/x/builder_dynamic_fees_test.go b/wallet/chain/x/builder_dynamic_fees_test.go index b07548abaafa..17311055f855 100644 --- a/wallet/chain/x/builder_dynamic_fees_test.go +++ b/wallet/chain/x/builder_dynamic_fees_test.go @@ -52,13 +52,17 @@ 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) + be = mocks.NewMockBuilderBackend(ctrl) + kc = secp256k1fx.NewKeychain(utxosKey) + sbe = mocks.NewMockSignerBackend(ctrl) + s = NewSigner(kc, sbe) + + // data to build tx outputsToMove = []*avax.TransferableOutput{{ Asset: avax.Asset{ID: avaxAssetID}, Out: &secp256k1fx.TransferOutput{ @@ -71,41 +75,38 @@ func TestBaseTx(t *testing.T) { }} ) - b := &DynamicFeesBuilder{ - addrs: set.Of(utxoAddr), - backend: be, - } - + // set expectations 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) + be.EXPECT().BlockchainID().Return(constants.PlatformChainID).AnyTimes() + be.EXPECT().UTXOs(gomock.Any(), constants.PlatformChainID).Return(utxos, nil).AnyTimes() + for _, utxo := range utxos { + sbe.EXPECT().GetUTXO(gomock.Any(), gomock.Any(), utxo.InputID()).Return(utxo, nil).AnyTimes() + } + + b := NewDynamicFeesBuilder(set.Of(utxoAddr), be) + // Post E-Upgrade + feeCalc := &fees.Calculator{ + IsEUpgradeActive: true, + FeeManager: commonfees.NewManager(testUnitFees, commonfees.EmptyWindows), + ConsumedUnitsCap: testBlockMaxConsumedUnits, + Codec: Parser.Codec(), + } utx, err := b.NewBaseTx( outputsToMove, - testUnitFees, - testBlockMaxConsumedUnits, + feeCalc, ) 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{ IsEUpgradeActive: true, - Codec: Parser.Codec(), FeeManager: commonfees.NewManager(testUnitFees, commonfees.EmptyWindows), ConsumedUnitsCap: testBlockMaxConsumedUnits, + Codec: Parser.Codec(), Credentials: tx.Creds, } require.NoError(utx.Visit(fc)) @@ -123,13 +124,16 @@ 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) + be = mocks.NewMockBuilderBackend(ctrl) + kc = secp256k1fx.NewKeychain(utxosKey) + sbe = mocks.NewMockSignerBackend(ctrl) + s = NewSigner(kc, sbe) + assetName = "Team Rocket" symbol = "TR" denomination uint8 = 0 @@ -180,44 +184,42 @@ func TestCreateAssetTx(t *testing.T) { } ) - b := &DynamicFeesBuilder{ - addrs: set.Of(utxoAddr), - backend: be, - } - + // set expectations 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) + for _, utxo := range utxos { + sbe.EXPECT().GetUTXO(gomock.Any(), gomock.Any(), utxo.InputID()).Return(utxo, nil).AnyTimes() + } + + b := NewDynamicFeesBuilder(set.Of(utxoAddr), be) + + // Post E-Upgrade + feeCalc := &fees.Calculator{ + IsEUpgradeActive: true, + FeeManager: commonfees.NewManager(testUnitFees, commonfees.EmptyWindows), + ConsumedUnitsCap: testBlockMaxConsumedUnits, + Codec: Parser.Codec(), + } utx, err := b.NewCreateAssetTx( assetName, symbol, denomination, initialState, - testUnitFees, - testBlockMaxConsumedUnits, + feeCalc, ) 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{ IsEUpgradeActive: true, - Codec: Parser.Codec(), FeeManager: commonfees.NewManager(testUnitFees, commonfees.EmptyWindows), ConsumedUnitsCap: testBlockMaxConsumedUnits, + Codec: Parser.Codec(), Credentials: tx.Creds, } require.NoError(utx.Visit(fc)) @@ -234,14 +236,17 @@ 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) + be = mocks.NewMockBuilderBackend(ctrl) + kc = secp256k1fx.NewKeychain(utxosKey) + sbe = mocks.NewMockSignerBackend(ctrl) + s = NewSigner(kc, sbe) + importKey = testKeys[0] importTo = &secp256k1fx.OutputOwners{ Threshold: 1, @@ -250,39 +255,36 @@ func TestImportTx(t *testing.T) { }, } ) - 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) + 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() + } + + b := NewDynamicFeesBuilder(set.Of(utxoAddr), be) + + // Post E-Upgrade + feeCalc := &fees.Calculator{ + IsEUpgradeActive: true, + FeeManager: commonfees.NewManager(testUnitFees, commonfees.EmptyWindows), + ConsumedUnitsCap: testBlockMaxConsumedUnits, + Codec: Parser.Codec(), + } utx, err := b.NewImportTx( sourceChainID, importTo, - testUnitFees, - testBlockMaxConsumedUnits, + feeCalc, ) 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) @@ -309,14 +311,17 @@ 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) + be = mocks.NewMockBuilderBackend(ctrl) + kc = secp256k1fx.NewKeychain(utxosKey) + sbe = mocks.NewMockSignerBackend(ctrl) + s = NewSigner(kc, sbe) + exportedOutputs = []*avax.TransferableOutput{{ Asset: avax.Asset{ID: avaxAssetID}, Out: &secp256k1fx.TransferOutput{ @@ -329,33 +334,31 @@ func TestExportTx(t *testing.T) { }} ) - 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) + for _, utxo := range utxos { + sbe.EXPECT().GetUTXO(gomock.Any(), gomock.Any(), utxo.InputID()).Return(utxo, nil).AnyTimes() + } + + b := NewDynamicFeesBuilder(set.Of(utxoAddr), be) + + // Post E-Upgrade + feeCalc := &fees.Calculator{ + IsEUpgradeActive: true, + FeeManager: commonfees.NewManager(testUnitFees, commonfees.EmptyWindows), + ConsumedUnitsCap: testBlockMaxConsumedUnits, + Codec: Parser.Codec(), + } utx, err := b.NewExportTx( subnetID, exportedOutputs, - testUnitFees, - testBlockMaxConsumedUnits, + feeCalc, ) 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) From a299f48399d71be4d2033a28a840c8c47939c1d7 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Sun, 18 Feb 2024 16:47:06 +0100 Subject: [PATCH 106/132] wip: cleaning up X-chain wallet --- wallet/chain/x/builder_test.go | 799 +++++++++++++++++++++------------ 1 file changed, 504 insertions(+), 295 deletions(-) diff --git a/wallet/chain/x/builder_test.go b/wallet/chain/x/builder_test.go index 510668b668fd..ba8bf8791c74 100644 --- a/wallet/chain/x/builder_test.go +++ b/wallet/chain/x/builder_test.go @@ -4,18 +4,18 @@ package x import ( - "math" "testing" "time" "github.com/stretchr/testify/require" - "go.uber.org/mock/gomock" + "golang.org/x/exp/slices" "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/config" "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" @@ -23,117 +23,179 @@ import ( "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" + "github.com/ava-labs/avalanchego/wallet/subnet/primary/common" stdcontext "context" commonfees "github.com/ava-labs/avalanchego/vms/components/fees" ) var ( - testKeys = secp256k1.TestKeys() + testKeys = secp256k1.TestKeys() + + // We hard-code [avaxAssetID] and [subnetAssetID] to make + // ordering of UTXOs generated by [testUTXOsList] is reproducible + avaxAssetID = ids.Empty.Prefix(1789) + xChainID = ids.Empty.Prefix(2021) + subnetAssetID = ids.Empty.Prefix(2024) + + testCtx = NewContext( + constants.UnitTestID, + xChainID, + avaxAssetID, + units.MicroAvax, // BaseTxFee + 99*units.MilliAvax, // CreateAssetTxFee + ) + 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, - } + testBlockMaxConsumedUnits = commonfees.Max ) // 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) - var ( - utxosKey = testKeys[1] - utxoAddr = utxosKey.PublicKey().Address() - utxos, avaxAssetID = testUTXOsList(utxosKey) + require = require.New(t) + + // backend + utxosKey = testKeys[1] + utxos = makeTestUTXOs(utxosKey) + genericBackend = newChainUTXOs( + require, + map[ids.ID][]*avax.UTXO{ + xChainID: utxos, + }, + ) + backend = NewBackend(testCtx, genericBackend) - be = mocks.NewMockBuilderBackend(ctrl) - kc = secp256k1fx.NewKeychain(utxosKey) - sbe = mocks.NewMockSignerBackend(ctrl) - s = NewSigner(kc, sbe) + // builder and signer + utxoAddr = utxosKey.Address() + builder = NewBuilder(set.Of(utxoAddr), backend) + kc = secp256k1fx.NewKeychain(utxosKey) + s = NewSigner(kc, genericBackend) - // data to build tx + // data to build the transaction 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()}, + Addrs: []ids.ShortID{utxoAddr}, }, }, }} ) - // set expectations - 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).AnyTimes() - for _, utxo := range utxos { - sbe.EXPECT().GetUTXO(gomock.Any(), gomock.Any(), utxo.InputID()).Return(utxo, nil).AnyTimes() - } - - b := NewBuilder(set.Of(utxoAddr), be) - - // Post E-Upgrade - feeCalc := &fees.Calculator{ - IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees), - ConsumedUnitsCap: testBlockMaxConsumedUnits, - Codec: Parser.Codec(), + { // Post E-Upgrade + feeCalc := &fees.Calculator{ + IsEUpgradeActive: true, + FeeManager: commonfees.NewManager(testUnitFees), + ConsumedUnitsCap: testBlockMaxConsumedUnits, + Codec: Parser.Codec(), + } + utx, err := builder.NewBaseTx( + outputsToMove, + feeCalc, + ) + require.NoError(err) + + tx, err := SignUnsigned(stdcontext.Background(), s, utx) + require.NoError(err) + + fc := &fees.Calculator{ + IsEUpgradeActive: true, + FeeManager: commonfees.NewManager(testUnitFees), + ConsumedUnitsCap: testBlockMaxConsumedUnits, + Credentials: tx.Creds, + Codec: Parser.Codec(), + } + require.NoError(utx.Visit(fc)) + require.Equal(9930*units.MicroAvax, fc.Fee) + + // check UTXOs selection and fee financing + ins := utx.Ins + outs := utx.Outs + require.Len(ins, 2) + require.Len(outs, 2) + + expectedConsumed := fc.Fee + outputsToMove[0].Out.Amount() + consumed := ins[0].In.Amount() + ins[1].In.Amount() - outs[0].Out.Amount() + require.Equal(expectedConsumed, consumed) + require.Equal(outputsToMove[0], outs[1]) } - utx, err := b.NewBaseTx( - outputsToMove, - feeCalc, - ) - require.NoError(err) - - tx, err := SignUnsigned(stdcontext.Background(), s, utx) - require.NoError(err) - fc := &fees.Calculator{ - IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees), - ConsumedUnitsCap: testBlockMaxConsumedUnits, - Codec: Parser.Codec(), - Credentials: tx.Creds, + { // Pre E-Upgrade + feeCalc := &fees.Calculator{ + IsEUpgradeActive: false, + Config: &config.Config{ + TxFee: testCtx.BaseTxFee(), + }, + FeeManager: commonfees.NewManager(commonfees.Empty), + ConsumedUnitsCap: commonfees.Max, + Codec: Parser.Codec(), + } + utx, err := builder.NewBaseTx( + outputsToMove, + feeCalc, + ) + require.NoError(err) + + tx, err := SignUnsigned(stdcontext.Background(), s, utx) + require.NoError(err) + + fc := &fees.Calculator{ + IsEUpgradeActive: false, + Config: &config.Config{ + TxFee: testCtx.BaseTxFee(), + }, + FeeManager: commonfees.NewManager(commonfees.Empty), + ConsumedUnitsCap: commonfees.Max, + Credentials: tx.Creds, + } + require.NoError(utx.Visit(fc)) + require.Equal(testCtx.BaseTxFee(), fc.Fee) + + // check UTXOs selection and fee financing + ins := utx.Ins + outs := utx.Outs + require.Len(ins, 2) + require.Len(outs, 2) + + expectedConsumed := fc.Fee + consumed := ins[0].In.Amount() + ins[1].In.Amount() - outs[0].Out.Amount() - outs[1].Out.Amount() + require.Equal(expectedConsumed, consumed) + require.Equal(outputsToMove[0], outs[1]) } - require.NoError(utx.Visit(fc)) - require.Equal(9930*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) var ( - utxosKey = testKeys[1] - utxoAddr = utxosKey.PublicKey().Address() - utxos, avaxAssetID = testUTXOsList(utxosKey) + // backend + utxosKey = testKeys[1] + utxos = makeTestUTXOs(utxosKey) + genericBackend = newChainUTXOs( + require, + map[ids.ID][]*avax.UTXO{ + xChainID: utxos, + }, + ) + backend = NewBackend(testCtx, genericBackend) - be = mocks.NewMockBuilderBackend(ctrl) - kc = secp256k1fx.NewKeychain(utxosKey) - sbe = mocks.NewMockSignerBackend(ctrl) - s = NewSigner(kc, sbe) + // builder and signer + utxoAddr = utxosKey.Address() + builder = NewBuilder(set.Of(utxoAddr), backend) + kc = secp256k1fx.NewKeychain(utxosKey) + s = NewSigner(kc, genericBackend) + // data to build the transaction assetName = "Team Rocket" symbol = "TR" denomination uint8 = 0 @@ -184,69 +246,112 @@ func TestCreateAssetTx(t *testing.T) { } ) - // set expectations - 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) - for _, utxo := range utxos { - sbe.EXPECT().GetUTXO(gomock.Any(), gomock.Any(), utxo.InputID()).Return(utxo, nil).AnyTimes() - } - - b := NewBuilder(set.Of(utxoAddr), be) + { + // Post E-Upgrade + feeCalc := &fees.Calculator{ + IsEUpgradeActive: true, + FeeManager: commonfees.NewManager(testUnitFees), + ConsumedUnitsCap: testBlockMaxConsumedUnits, + Codec: Parser.Codec(), + } - // Post E-Upgrade - feeCalc := &fees.Calculator{ - IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees), - ConsumedUnitsCap: testBlockMaxConsumedUnits, - Codec: Parser.Codec(), + utx, err := builder.NewCreateAssetTx( + assetName, + symbol, + denomination, + initialState, + feeCalc, + ) + require.NoError(err) + + tx, err := SignUnsigned(stdcontext.Background(), s, utx) + require.NoError(err) + + fc := &fees.Calculator{ + IsEUpgradeActive: true, + FeeManager: commonfees.NewManager(testUnitFees), + ConsumedUnitsCap: testBlockMaxConsumedUnits, + Codec: Parser.Codec(), + Credentials: tx.Creds, + } + require.NoError(utx.Visit(fc)) + require.Equal(9898*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()) } - utx, err := b.NewCreateAssetTx( - assetName, - symbol, - denomination, - initialState, - feeCalc, - ) - require.NoError(err) - - tx, err := SignUnsigned(stdcontext.Background(), s, utx) - require.NoError(err) + { + // Pre E-Upgrade + feeCalc := &fees.Calculator{ + IsEUpgradeActive: false, + Config: &config.Config{ + CreateAssetTxFee: testCtx.CreateAssetTxFee(), + }, + FeeManager: commonfees.NewManager(commonfees.Empty), + ConsumedUnitsCap: commonfees.Max, + Codec: Parser.Codec(), + } - fc := &fees.Calculator{ - IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees), - ConsumedUnitsCap: testBlockMaxConsumedUnits, - Codec: Parser.Codec(), - Credentials: tx.Creds, + utx, err := builder.NewCreateAssetTx( + assetName, + symbol, + denomination, + initialState, + feeCalc, + ) + require.NoError(err) + + tx, err := SignUnsigned(stdcontext.Background(), s, utx) + require.NoError(err) + + fc := &fees.Calculator{ + IsEUpgradeActive: false, + Config: &config.Config{ + CreateAssetTxFee: testCtx.CreateAssetTxFee(), + }, + Credentials: tx.Creds, + } + require.NoError(utx.Visit(fc)) + require.Equal(99*units.MilliAvax, 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()) } - require.NoError(utx.Visit(fc)) - require.Equal(9898*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) - var ( - utxosKey = testKeys[1] - utxoAddr = utxosKey.PublicKey().Address() - sourceChainID = ids.GenerateTestID() - utxos, avaxAssetID = testUTXOsList(utxosKey) + require = require.New(t) + + // backend + utxosKey = testKeys[1] + utxos = makeTestUTXOs(utxosKey) + sourceChainID = ids.GenerateTestID() + importedUTXOs = utxos[:1] + genericBackend = newChainUTXOs( + require, + map[ids.ID][]*avax.UTXO{ + xChainID: utxos, + sourceChainID: importedUTXOs, + }, + ) + + backend = NewBackend(testCtx, genericBackend) - be = mocks.NewMockBuilderBackend(ctrl) - kc = secp256k1fx.NewKeychain(utxosKey) - sbe = mocks.NewMockSignerBackend(ctrl) - s = NewSigner(kc, sbe) + // builder and signer + utxoAddr = utxosKey.Address() + builder = NewBuilder(set.Of(utxoAddr), backend) + kc = secp256k1fx.NewKeychain(utxosKey) + s = NewSigner(kc, genericBackend) + // data to build the transaction importKey = testKeys[0] importTo = &secp256k1fx.OutputOwners{ Threshold: 1, @@ -255,224 +360,328 @@ func TestImportTx(t *testing.T) { }, } ) - importedUtxo := utxos[0] - utxos = utxos[1:] - - 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) - 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() - } - - b := NewBuilder(set.Of(utxoAddr), be) - // Post E-Upgrade - feeCalc := &fees.Calculator{ - IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees), - ConsumedUnitsCap: testBlockMaxConsumedUnits, - Codec: Parser.Codec(), + { // Post E-Upgrade + feeCalc := &fees.Calculator{ + IsEUpgradeActive: true, + FeeManager: commonfees.NewManager(testUnitFees), + ConsumedUnitsCap: testBlockMaxConsumedUnits, + Codec: Parser.Codec(), + } + utx, err := builder.NewImportTx( + sourceChainID, + importTo, + feeCalc, + ) + require.NoError(err) + + tx, err := SignUnsigned(stdcontext.Background(), s, utx) + require.NoError(err) + + fc := &fees.Calculator{ + IsEUpgradeActive: true, + FeeManager: commonfees.NewManager(testUnitFees), + ConsumedUnitsCap: testBlockMaxConsumedUnits, + Credentials: tx.Creds, + Codec: Parser.Codec(), + } + require.NoError(utx.Visit(fc)) + require.Equal(14251*units.MicroAvax, fc.Fee) + + // check UTXOs selection and fee financing + ins := utx.Ins + outs := utx.Outs + importedIns := utx.ImportedIns + require.Len(ins, 2) + require.Len(importedIns, 1) + require.Len(outs, 1) + + expectedConsumed := fc.Fee + consumed := importedIns[0].In.Amount() + ins[0].In.Amount() + ins[1].In.Amount() - outs[0].Out.Amount() + require.Equal(expectedConsumed, consumed) } - utx, err := b.NewImportTx( - sourceChainID, - importTo, - feeCalc, - ) - require.NoError(err) - - tx, err := SignUnsigned(stdcontext.Background(), s, utx) - require.NoError(err) - - fc := &fees.Calculator{ - IsEUpgradeActive: true, - Codec: Parser.Codec(), - FeeManager: commonfees.NewManager(testUnitFees), - ConsumedUnitsCap: testBlockMaxConsumedUnits, - Credentials: tx.Creds, + { // Pre E-Upgrade + feeCalc := &fees.Calculator{ + IsEUpgradeActive: false, + Config: &config.Config{ + TxFee: testCtx.BaseTxFee(), + }, + FeeManager: commonfees.NewManager(commonfees.Empty), + ConsumedUnitsCap: commonfees.Max, + Codec: Parser.Codec(), + } + utx, err := builder.NewImportTx( + sourceChainID, + importTo, + feeCalc, + ) + require.NoError(err) + + tx, err := SignUnsigned(stdcontext.Background(), s, utx) + require.NoError(err) + + fc := &fees.Calculator{ + IsEUpgradeActive: false, + Config: &config.Config{ + TxFee: testCtx.BaseTxFee(), + }, + FeeManager: commonfees.NewManager(commonfees.Empty), + ConsumedUnitsCap: commonfees.Max, + Credentials: tx.Creds, + Codec: Parser.Codec(), + } + require.NoError(utx.Visit(fc)) + require.Equal(testCtx.BaseTxFee(), fc.Fee) + + // check UTXOs selection and fee financing + ins := utx.Ins + outs := utx.Outs + importedIns := utx.ImportedIns + require.Empty(ins) + require.Len(importedIns, 1) + require.Len(outs, 1) + + expectedConsumed := fc.Fee + consumed := importedIns[0].In.Amount() - outs[0].Out.Amount() + require.Equal(expectedConsumed, consumed) } - require.NoError(utx.Visit(fc)) - require.Equal(9640*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) - var ( - utxosKey = testKeys[1] - utxoAddr = utxosKey.PublicKey().Address() - subnetID = ids.GenerateTestID() - utxos, avaxAssetID = testUTXOsList(utxosKey) + require = require.New(t) + + // backend + utxosKey = testKeys[1] + utxos = makeTestUTXOs(utxosKey) + genericBackend = newChainUTXOs( + require, + map[ids.ID][]*avax.UTXO{ + xChainID: utxos, + }, + ) + backend = NewBackend(testCtx, genericBackend) - be = mocks.NewMockBuilderBackend(ctrl) - kc = secp256k1fx.NewKeychain(utxosKey) - sbe = mocks.NewMockSignerBackend(ctrl) - s = NewSigner(kc, sbe) + // builder and signer + utxoAddr = utxosKey.Address() + builder = NewBuilder(set.Of(utxoAddr), backend) + kc = secp256k1fx.NewKeychain(utxosKey) + s = NewSigner(kc, genericBackend) + // data to build the transaction + subnetID = ids.GenerateTestID() 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()}, + Addrs: []ids.ShortID{utxoAddr}, }, }, }} ) - 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) - for _, utxo := range utxos { - sbe.EXPECT().GetUTXO(gomock.Any(), gomock.Any(), utxo.InputID()).Return(utxo, nil).AnyTimes() - } - - b := NewBuilder(set.Of(utxoAddr), be) - - // Post E-Upgrade - feeCalc := &fees.Calculator{ - IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees), - ConsumedUnitsCap: testBlockMaxConsumedUnits, - Codec: Parser.Codec(), + { // Post E-Upgrade + feeCalc := &fees.Calculator{ + IsEUpgradeActive: true, + FeeManager: commonfees.NewManager(testUnitFees), + ConsumedUnitsCap: testBlockMaxConsumedUnits, + Codec: Parser.Codec(), + } + utx, err := builder.NewExportTx( + subnetID, + exportedOutputs, + feeCalc, + ) + require.NoError(err) + + tx, err := SignUnsigned(stdcontext.Background(), s, utx) + require.NoError(err) + + fc := &fees.Calculator{ + IsEUpgradeActive: true, + FeeManager: commonfees.NewManager(testUnitFees), + ConsumedUnitsCap: testBlockMaxConsumedUnits, + Credentials: tx.Creds, + Codec: Parser.Codec(), + } + require.NoError(utx.Visit(fc)) + require.Equal(9966*units.MicroAvax, fc.Fee) + + // check UTXOs selection and fee financing + ins := utx.Ins + outs := utx.Outs + require.Len(ins, 2) + require.Len(outs, 1) + + expectedConsumed := fc.Fee + exportedOutputs[0].Out.Amount() + consumed := ins[0].In.Amount() + ins[1].In.Amount() - outs[0].Out.Amount() + require.Equal(expectedConsumed, consumed) + require.Equal(utx.ExportedOuts, exportedOutputs) } - utx, err := b.NewExportTx( - subnetID, - exportedOutputs, - feeCalc, - ) - require.NoError(err) - - tx, err := SignUnsigned(stdcontext.Background(), s, utx) - require.NoError(err) - - fc := &fees.Calculator{ - IsEUpgradeActive: true, - Codec: Parser.Codec(), - FeeManager: commonfees.NewManager(testUnitFees), - ConsumedUnitsCap: testBlockMaxConsumedUnits, - Credentials: tx.Creds, + { // Pre E-Upgrade + feeCalc := &fees.Calculator{ + IsEUpgradeActive: false, + Config: &config.Config{ + TxFee: testCtx.BaseTxFee(), + }, + FeeManager: commonfees.NewManager(commonfees.Empty), + ConsumedUnitsCap: commonfees.Max, + Codec: Parser.Codec(), + } + utx, err := builder.NewExportTx( + subnetID, + exportedOutputs, + feeCalc, + ) + require.NoError(err) + + tx, err := SignUnsigned(stdcontext.Background(), s, utx) + require.NoError(err) + + fc := &fees.Calculator{ + IsEUpgradeActive: false, + Config: &config.Config{ + TxFee: testCtx.BaseTxFee(), + }, + FeeManager: commonfees.NewManager(commonfees.Empty), + ConsumedUnitsCap: commonfees.Max, + Credentials: tx.Creds, + Codec: Parser.Codec(), + } + require.NoError(utx.Visit(fc)) + require.Equal(testCtx.BaseTxFee(), fc.Fee) + + // check UTXOs selection and fee financing + ins := utx.Ins + outs := utx.Outs + require.Len(ins, 2) + require.Len(outs, 1) + + expectedConsumed := fc.Fee + exportedOutputs[0].Out.Amount() + consumed := ins[0].In.Amount() + ins[1].In.Amount() - outs[0].Out.Amount() + require.Equal(expectedConsumed, consumed) + require.Equal(utx.ExportedOuts, exportedOutputs) } - require.NoError(utx.Visit(fc)) - require.Equal(9966*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, -) { +func makeTestUTXOs(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) - - var ( - avaxAssetID = ids.Empty.Prefix(utxosOffset) - subnetAssetID = ids.Empty.Prefix(utxosOffset + 1) - ) + const 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), + { // 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, }, - Asset: avax.Asset{ID: avaxAssetID}, - Out: &secp256k1fx.TransferOutput{ - Amt: 2 * units.MilliAvax, + }, + }, + { // 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{ - Locktime: 0, - Addrs: []ids.ShortID{utxosKey.PublicKey().Address()}, Threshold: 1, + Addrs: []ids.ShortID{utxosKey.PublicKey().Address()}, }, }, }, - { // 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), }, - { // 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, }, - Asset: avax.Asset{ID: subnetAssetID}, - Out: &secp256k1fx.TransferOutput{ - Amt: 99 * units.MegaAvax, + }, + }, + { // 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{ - Locktime: 0, - Addrs: []ids.ShortID{utxosKey.PublicKey().Address()}, Threshold: 1, + Addrs: []ids.ShortID{utxosKey.PublicKey().Address()}, }, }, }, - { // 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), }, - { // 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, - }, + 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 + } +} + +func newChainUTXOs(require *require.Assertions, utxoSets map[ids.ID][]*avax.UTXO) common.ChainUTXOs { + globalUTXOs := common.NewUTXOs() + for subnetID, utxos := range utxoSets { + for _, utxo := range utxos { + require.NoError( + globalUTXOs.AddUTXO(stdcontext.Background(), subnetID, constants.PlatformChainID, utxo), + ) + } + } + return &deterministicChainUTXOs{ + ChainUTXOs: common.NewChainUTXOs(constants.PlatformChainID, globalUTXOs), + } +} + +type deterministicChainUTXOs struct { + common.ChainUTXOs +} + +func (c *deterministicChainUTXOs) UTXOs(ctx stdcontext.Context, sourceChainID ids.ID) ([]*avax.UTXO, error) { + utxos, err := c.ChainUTXOs.UTXOs(ctx, sourceChainID) + if err != nil { + return nil, err + } + + slices.SortFunc(utxos, func(a, b *avax.UTXO) int { + return a.Compare(&b.UTXOID) + }) + return utxos, nil } From 5655a614f14f77cb044e6aead596ff56145fef70 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Fri, 23 Feb 2024 14:15:46 +0100 Subject: [PATCH 107/132] fixed avm client calls --- vms/avm/client.go | 4 ++-- vms/avm/service.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/vms/avm/client.go b/vms/avm/client.go index b49006b1c920..b024fd8638c0 100644 --- a/vms/avm/client.go +++ b/vms/avm/client.go @@ -414,13 +414,13 @@ func (c *client) GetAllBalances( 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...) + err := c.requester.SendRequest(ctx, "avm.getUnitFees", struct{}{}, res, options...) return res.UnitFees, 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...) + err := c.requester.SendRequest(ctx, "avm.getFeeWindows", struct{}{}, res, options...) return res.FeeWindows, err } diff --git a/vms/avm/service.go b/vms/avm/service.go index 78914c5b302e..d4152fcd90ea 100644 --- a/vms/avm/service.go +++ b/vms/avm/service.go @@ -683,7 +683,7 @@ type GetUnitFeesReply struct { // 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("service", "avm"), zap.String("method", "getUnitFees"), ) @@ -704,7 +704,7 @@ type GetFeeWindowsReply struct { // 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("service", "avm"), zap.String("method", "getBlockUnitsCap"), ) From a070817a71224ab93c4596b3df92abccfbf5a083 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 29 Feb 2024 10:48:24 +0100 Subject: [PATCH 108/132] fixed changeDenom --- 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 0d3a382275284fbc55207aa5bb6964031465de96 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Sun, 10 Mar 2024 20:34:43 +0100 Subject: [PATCH 109/132] exponential fees update --- vms/avm/config/dynamic_fees_config.go | 33 +++++------------- vms/components/fees/dimensions.go | 23 ++++++++++++ vms/components/fees/manager.go | 47 +++++++------------------ vms/components/fees/manager_test.go | 50 +++++++++++++-------------- 4 files changed, 68 insertions(+), 85 deletions(-) diff --git a/vms/avm/config/dynamic_fees_config.go b/vms/avm/config/dynamic_fees_config.go index 7beef6e24d5a..8cdd7c19c1cf 100644 --- a/vms/avm/config/dynamic_fees_config.go +++ b/vms/avm/config/dynamic_fees_config.go @@ -5,7 +5,6 @@ package config import ( "fmt" - "math" "github.com/ava-labs/avalanchego/utils/units" @@ -34,31 +33,18 @@ var ( 3 * units.NanoAvax, 4 * units.NanoAvax, }, - MinUnitFees: commonfees.Dimensions{}, - - FeesChangeDenominator: commonfees.Dimensions{ - 1 * units.NanoAvax, - 1 * units.NanoAvax, - 1 * units.NanoAvax, - 1 * units.NanoAvax, - }, - - BlockUnitsCap: commonfees.Dimensions{ - math.MaxUint64, - math.MaxUint64, - math.MaxUint64, - math.MaxUint64, - }, - - BlockUnitsTarget: commonfees.Dimensions{ + UpdateCoefficient: commonfees.Dimensions{ 1, 1, 1, 1, }, + BlockUnitsCap: commonfees.Max, + BlockUnitsTarget: commonfees.Dimensions{1, 1, 1, 1}, } + // TODO ABENEGIA: decide if and how to validate PreEUpgradeDynamicFeesConfig PreEUpgradeDynamicFeesConfig = DynamicFeesConfig{ InitialUnitFees: commonfees.Empty, BlockUnitsCap: commonfees.Max, @@ -75,9 +61,10 @@ 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. Setting an entry to 0 makes + // the corresponding fee rate constant. + UpdateCoefficient commonfees.Dimensions // BlockUnitsCap contains, per each fee dimension, the // maximal complexity a valid P-chain block can host @@ -99,10 +86,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, diff --git a/vms/components/fees/dimensions.go b/vms/components/fees/dimensions.go index 9095b32e43a4..05171ec3c0ff 100644 --- a/vms/components/fees/dimensions.go +++ b/vms/components/fees/dimensions.go @@ -5,6 +5,7 @@ package fees import ( "encoding/binary" + "errors" "fmt" "math" @@ -17,12 +18,19 @@ 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") + Empty = Dimensions{} Max = Dimensions{ math.MaxUint64, @@ -30,6 +38,13 @@ var ( math.MaxUint64, math.MaxUint64, } + + DimensionStrings = []string{ + bandwidthString, + utxosReadString, + utxosWriteString, + computeString, + } ) type ( @@ -37,6 +52,14 @@ 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++ { diff --git a/vms/components/fees/manager.go b/vms/components/fees/manager.go index 10f06bbde1b7..07b1e2d12e10 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..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{1, 1, 2, 10} - minUnitFees = Dimensions{0, 0, 0, 0} + updateCoefficient = Dimensions{1, 2, 5, 10} + minUnitFees = Dimensions{0, 0, 0, 0} ) m := &Manager{ @@ -36,7 +36,7 @@ func TestComputeNextEmptyWindows(t *testing.T) { lastBlkTime.Unix(), currBlkTime.Unix(), targetComplexity, - priceChangeDenominator, + updateCoefficient, minUnitFees, ) @@ -46,11 +46,11 @@ func TestComputeNextEmptyWindows(t *testing.T) { // 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]) + // 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 - require.Equal(initialUnitFees[Compute]+9, next.unitFees[Compute]) + // 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 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{1, 2, 5, 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(initialUnitFees[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]) + 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(1739274941520500992), next.unitFees[UTXOWrite]) - // Compute units are above target, next unit fees increased, proportionally to priceChangeDenominator - require.Equal(uint64(73786976294838207), next.unitFees[Compute]) + // Compute units are above target, next unit fees are increased. + require.Equal(uint64(math.MaxUint64), next.unitFees[Compute]) // next cumulated units are zeroed require.Equal(Dimensions{}, next.cumulatedUnits) @@ -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(minUnitFees[UTXOWrite], 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(minUnitFees[Compute], 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) From 14ce0361a8eaeb4b6b893fe565a7367c0abc4aa7 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Sun, 10 Mar 2024 22:29:38 +0100 Subject: [PATCH 110/132] fixed update fee rates calls --- vms/avm/block/builder/builder.go | 38 ++++++++++++---- vms/avm/block/builder/builder_test.go | 25 ++++++++--- vms/avm/block/executor/block.go | 19 ++++++-- vms/avm/block/executor/block_test.go | 62 +++++++++++++++++--------- vms/avm/block/executor/helpers.go | 20 +++++++++ vms/avm/block/executor/manager.go | 31 ++++++++++--- vms/avm/block/executor/manager_test.go | 35 ++++++++++++--- 7 files changed, 178 insertions(+), 52 deletions(-) create mode 100644 vms/avm/block/executor/helpers.go diff --git a/vms/avm/block/builder/builder.go b/vms/avm/block/builder/builder.go index ea74f6eeb551..6cbc093a81cc 100644 --- a/vms/avm/block/builder/builder.go +++ b/vms/avm/block/builder/builder.go @@ -6,6 +6,7 @@ package builder import ( "context" "errors" + "fmt" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/snow/consensus/snowman" @@ -75,13 +76,10 @@ func (b *builder) BuildBlock(context.Context) (snowman.Block, error) { } preferredHeight := preferred.Height() - preferredTimestamp := preferred.Timestamp() - nextHeight := preferredHeight + 1 - nextTimestamp := b.clk.Time() // [timestamp] = max(now, parentTime) - if preferredTimestamp.After(nextTimestamp) { - nextTimestamp = preferredTimestamp - } + + preferredTimestamp := preferred.Timestamp() + nextTimestamp := blockexecutor.NextBlockTime(preferredTimestamp, b.clk) stateDiff, err := state.NewDiff(preferredID, b.manager) if err != nil { @@ -93,9 +91,31 @@ func (b *builder) BuildBlock(context.Context) (snowman.Block, error) { inputs set.Set[ids.ID] remainingSize = targetBlockSize - feeCfg = b.backend.Config.GetDynamicFeesConfig(nextTimestamp) - feeManager = fees.NewManager(feeCfg.InitialUnitFees, fees.EmptyWindows) + chainTime = stateDiff.GetTimestamp() + isEForkActive = b.backend.Config.IsEUpgradeActivated(chainTime) + feesCfg = b.backend.Config.GetDynamicFeesConfig(chainTime) ) + + unitFees, err := stateDiff.GetUnitFees() + if err != nil { + return nil, fmt.Errorf("failed retrieving unit fees: %w", err) + } + feeWindows, err := stateDiff.GetFeeWindows() + if err != nil { + return nil, fmt.Errorf("failed retrieving fee windows: %w", err) + } + + feeManager := fees.NewManager(unitFees, feeWindows) + if isEForkActive { + feeManager = feeManager.ComputeNext( + chainTime.Unix(), + nextTimestamp.Unix(), + feesCfg.BlockUnitsTarget, + feesCfg.UpdateCoefficient, + feesCfg.MinUnitFees, + ) + } + for { tx, exists := b.mempool.Peek() // Invariant: [mempool.MaxTxSize] < [targetBlockSize]. This guarantees @@ -117,7 +137,7 @@ func (b *builder) BuildBlock(context.Context) (snowman.Block, error) { err = tx.Unsigned.Visit(&txexecutor.SemanticVerifier{ Backend: b.backend, BlkFeeManager: feeManager, - UnitCaps: feeCfg.BlockUnitsCap, + UnitCaps: feesCfg.BlockUnitsCap, State: txDiff, Tx: tx, }) diff --git a/vms/avm/block/builder/builder_test.go b/vms/avm/block/builder/builder_test.go index 4c34643fd9b4..e6eb3db048ea 100644 --- a/vms/avm/block/builder/builder_test.go +++ b/vms/avm/block/builder/builder_test.go @@ -36,6 +36,7 @@ import ( blkexecutor "github.com/ava-labs/avalanchego/vms/avm/block/executor" txexecutor "github.com/ava-labs/avalanchego/vms/avm/txs/executor" + commonfees "github.com/ava-labs/avalanchego/vms/components/fees" ) const trackChecksums = false @@ -122,11 +123,13 @@ func TestBuilderBuildBlock(t *testing.T) { preferredState := state.NewMockChain(ctrl) preferredState.EXPECT().GetLastAccepted().Return(preferredID) preferredState.EXPECT().GetTimestamp().Return(preferredTimestamp) + preferredState.EXPECT().GetUnitFees().Return(commonfees.Empty, nil) + preferredState.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows, nil) manager := blkexecutor.NewMockManager(ctrl) manager.EXPECT().Preferred().Return(preferredID) manager.EXPECT().GetStatelessBlock(preferredID).Return(preferredBlock, nil) - manager.EXPECT().GetState(preferredID).Return(preferredState, true) + manager.EXPECT().GetState(preferredID).Return(preferredState, true).AnyTimes() unsignedTx := txs.NewMockUnsignedTx(ctrl) unsignedTx.EXPECT().Visit(gomock.Any()).Return(errTest) // Fail semantic verification @@ -169,11 +172,13 @@ func TestBuilderBuildBlock(t *testing.T) { preferredState := state.NewMockChain(ctrl) preferredState.EXPECT().GetLastAccepted().Return(preferredID) preferredState.EXPECT().GetTimestamp().Return(preferredTimestamp) + preferredState.EXPECT().GetUnitFees().Return(commonfees.Empty, nil) + preferredState.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows, nil) manager := blkexecutor.NewMockManager(ctrl) manager.EXPECT().Preferred().Return(preferredID) manager.EXPECT().GetStatelessBlock(preferredID).Return(preferredBlock, nil) - manager.EXPECT().GetState(preferredID).Return(preferredState, true) + manager.EXPECT().GetState(preferredID).Return(preferredState, true).AnyTimes() unsignedTx := txs.NewMockUnsignedTx(ctrl) unsignedTx.EXPECT().Visit(gomock.Any()).Return(nil) // Pass semantic verification @@ -217,11 +222,13 @@ func TestBuilderBuildBlock(t *testing.T) { preferredState := state.NewMockChain(ctrl) preferredState.EXPECT().GetLastAccepted().Return(preferredID) preferredState.EXPECT().GetTimestamp().Return(preferredTimestamp) + preferredState.EXPECT().GetUnitFees().Return(commonfees.Empty, nil) + preferredState.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows, nil) manager := blkexecutor.NewMockManager(ctrl) manager.EXPECT().Preferred().Return(preferredID) manager.EXPECT().GetStatelessBlock(preferredID).Return(preferredBlock, nil) - manager.EXPECT().GetState(preferredID).Return(preferredState, true) + manager.EXPECT().GetState(preferredID).Return(preferredState, true).AnyTimes() manager.EXPECT().VerifyUniqueInputs(preferredID, gomock.Any()).Return(errTest) unsignedTx := txs.NewMockUnsignedTx(ctrl) @@ -266,6 +273,8 @@ func TestBuilderBuildBlock(t *testing.T) { preferredState := state.NewMockChain(ctrl) preferredState.EXPECT().GetLastAccepted().Return(preferredID) preferredState.EXPECT().GetTimestamp().Return(preferredTimestamp) + preferredState.EXPECT().GetUnitFees().Return(commonfees.Empty, nil) + preferredState.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows, nil) // tx1 and tx2 both consume [inputID]. // tx1 is added to the block first, so tx2 should be dropped. @@ -302,7 +311,7 @@ func TestBuilderBuildBlock(t *testing.T) { manager := blkexecutor.NewMockManager(ctrl) manager.EXPECT().Preferred().Return(preferredID) manager.EXPECT().GetStatelessBlock(preferredID).Return(preferredBlock, nil) - manager.EXPECT().GetState(preferredID).Return(preferredState, true) + manager.EXPECT().GetState(preferredID).Return(preferredState, true).AnyTimes() manager.EXPECT().VerifyUniqueInputs(preferredID, gomock.Any()).Return(nil) // Assert created block has one tx, tx1, // and other fields are set correctly. @@ -367,11 +376,13 @@ func TestBuilderBuildBlock(t *testing.T) { preferredState := state.NewMockChain(ctrl) preferredState.EXPECT().GetLastAccepted().Return(preferredID) preferredState.EXPECT().GetTimestamp().Return(preferredTimestamp) + preferredState.EXPECT().GetUnitFees().Return(commonfees.Empty, nil) + preferredState.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows, nil) manager := blkexecutor.NewMockManager(ctrl) manager.EXPECT().Preferred().Return(preferredID) manager.EXPECT().GetStatelessBlock(preferredID).Return(preferredBlock, nil) - manager.EXPECT().GetState(preferredID).Return(preferredState, true) + manager.EXPECT().GetState(preferredID).Return(preferredState, true).AnyTimes() manager.EXPECT().VerifyUniqueInputs(preferredID, gomock.Any()).Return(nil) // Assert that the created block has the right timestamp manager.EXPECT().NewBlock(gomock.Any()).DoAndReturn( @@ -444,11 +455,13 @@ func TestBuilderBuildBlock(t *testing.T) { preferredState := state.NewMockChain(ctrl) preferredState.EXPECT().GetLastAccepted().Return(preferredID) preferredState.EXPECT().GetTimestamp().Return(preferredTimestamp) + preferredState.EXPECT().GetUnitFees().Return(commonfees.Empty, nil) + preferredState.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows, nil) manager := blkexecutor.NewMockManager(ctrl) manager.EXPECT().Preferred().Return(preferredID) manager.EXPECT().GetStatelessBlock(preferredID).Return(preferredBlock, nil) - manager.EXPECT().GetState(preferredID).Return(preferredState, true) + manager.EXPECT().GetState(preferredID).Return(preferredState, true).AnyTimes() manager.EXPECT().VerifyUniqueInputs(preferredID, gomock.Any()).Return(nil) // Assert that the created block has the right timestamp manager.EXPECT().NewBlock(gomock.Any()).DoAndReturn( diff --git a/vms/avm/block/executor/block.go b/vms/avm/block/executor/block.go index d9cbe16a2f2c..85dd57b2701a 100644 --- a/vms/avm/block/executor/block.go +++ b/vms/avm/block/executor/block.go @@ -137,21 +137,32 @@ func (b *Block) Verify(context.Context) error { } feeWindows, err := stateDiff.GetFeeWindows() if err != nil { - return err + return fmt.Errorf("failed retrieving fee windows: %w", err) } var ( - feeCfg = b.manager.backend.Config.GetDynamicFeesConfig(b.Timestamp()) - feeManager = fees.NewManager(unitFees, feeWindows) + isEForkActive = b.manager.backend.Config.IsEUpgradeActivated(parentChainTime) + feesCfg = b.manager.backend.Config.GetDynamicFeesConfig(parentChainTime) ) + feeManager := fees.NewManager(unitFees, feeWindows) + if isEForkActive { + feeManager = feeManager.ComputeNext( + parentChainTime.Unix(), + newChainTime.Unix(), + feesCfg.BlockUnitsTarget, + feesCfg.UpdateCoefficient, + feesCfg.MinUnitFees, + ) + } + for _, tx := range txs { // Verify that the tx is valid according to the current state of the // chain. err := tx.Unsigned.Visit(&executor.SemanticVerifier{ Backend: b.manager.backend, BlkFeeManager: feeManager, - UnitCaps: feeCfg.BlockUnitsCap, + UnitCaps: feesCfg.BlockUnitsCap, State: stateDiff, Tx: tx, }) diff --git a/vms/avm/block/executor/block_test.go b/vms/avm/block/executor/block_test.go index 31b8b3f2a9f4..d3230bb81646 100644 --- a/vms/avm/block/executor/block_test.go +++ b/vms/avm/block/executor/block_test.go @@ -901,25 +901,34 @@ func TestBlockReject(t *testing.T) { mempool.EXPECT().RequestBuildBlock() lastAcceptedID := ids.GenerateTestID() + lastAcceptedMockBlock := block.NewMockBlock(ctrl) + lastAcceptedMockBlock.EXPECT().ID().Return(lastAcceptedID).AnyTimes() + lastAcceptedMockBlock.EXPECT().Timestamp().Return(time.Now().Truncate(time.Second)).AnyTimes() + mockState := state.NewMockState(ctrl) mockState.EXPECT().GetLastAccepted().Return(lastAcceptedID).AnyTimes() + mockState.EXPECT().GetBlock(lastAcceptedID).Return(lastAcceptedMockBlock, nil).AnyTimes() mockState.EXPECT().GetTimestamp().Return(time.Now()).AnyTimes() mockState.EXPECT().GetUnitFees().Return(commonfees.Empty, nil).AnyTimes() mockState.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows, nil).AnyTimes() - return &Block{ - Block: mockBlock, - manager: &manager{ - lastAccepted: lastAcceptedID, - mempool: mempool, - metrics: metrics.NewMockMetrics(ctrl), - backend: defaultTestBackend(true, nil), - state: mockState, - blkIDToState: map[ids.ID]*blockState{ - blockID: {}, - }, + manager := &manager{ + lastAccepted: lastAcceptedID, + mempool: mempool, + clk: &mockable.Clock{}, + metrics: metrics.NewMockMetrics(ctrl), + backend: defaultTestBackend(true, nil), + state: mockState, + blkIDToState: map[ids.ID]*blockState{ + blockID: {}, }, } + manager.SetPreference(lastAcceptedID) + + return &Block{ + Block: mockBlock, + manager: manager, + } }, }, { @@ -956,25 +965,34 @@ func TestBlockReject(t *testing.T) { mempool.EXPECT().RequestBuildBlock() lastAcceptedID := ids.GenerateTestID() + lastAcceptedMockBlock := block.NewMockBlock(ctrl) + lastAcceptedMockBlock.EXPECT().ID().Return(lastAcceptedID).AnyTimes() + lastAcceptedMockBlock.EXPECT().Timestamp().Return(time.Now().Truncate(time.Second)).AnyTimes() + mockState := state.NewMockState(ctrl) mockState.EXPECT().GetLastAccepted().Return(lastAcceptedID).AnyTimes() + mockState.EXPECT().GetBlock(lastAcceptedID).Return(lastAcceptedMockBlock, nil).AnyTimes() mockState.EXPECT().GetTimestamp().Return(time.Now()).AnyTimes() mockState.EXPECT().GetUnitFees().Return(commonfees.Empty, nil).AnyTimes() mockState.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows, nil).AnyTimes() - return &Block{ - Block: mockBlock, - manager: &manager{ - lastAccepted: lastAcceptedID, - mempool: mempool, - metrics: metrics.NewMockMetrics(ctrl), - backend: defaultTestBackend(true, nil), - state: mockState, - blkIDToState: map[ids.ID]*blockState{ - blockID: {}, - }, + manager := &manager{ + lastAccepted: lastAcceptedID, + mempool: mempool, + clk: &mockable.Clock{}, + metrics: metrics.NewMockMetrics(ctrl), + backend: defaultTestBackend(true, nil), + state: mockState, + blkIDToState: map[ids.ID]*blockState{ + blockID: {}, }, } + manager.SetPreference(lastAcceptedID) + + return &Block{ + Block: mockBlock, + manager: manager, + } }, }, } diff --git a/vms/avm/block/executor/helpers.go b/vms/avm/block/executor/helpers.go new file mode 100644 index 000000000000..9a60a24c1982 --- /dev/null +++ b/vms/avm/block/executor/helpers.go @@ -0,0 +1,20 @@ +// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package executor + +import ( + "time" + + "github.com/ava-labs/avalanchego/utils/timer/mockable" +) + +func NextBlockTime(parentTime time.Time, clk *mockable.Clock) time.Time { + // [timestamp] = max(now, parentTime) + + timestamp := clk.Time() + if parentTime.After(timestamp) { + timestamp = parentTime + } + return timestamp +} diff --git a/vms/avm/block/executor/manager.go b/vms/avm/block/executor/manager.go index c09d7ef20551..dd430345ec88 100644 --- a/vms/avm/block/executor/manager.go +++ b/vms/avm/block/executor/manager.go @@ -5,6 +5,7 @@ package executor import ( "errors" + "fmt" "github.com/ava-labs/avalanchego/chains/atomic" "github.com/ava-labs/avalanchego/ids" @@ -156,6 +157,13 @@ func (m *manager) VerifyTx(tx *txs.Tx) error { return err } + preferredID := m.Preferred() + preferred, err := m.GetStatelessBlock(preferredID) + if err != nil { + return err + } + nextBlkTime := NextBlockTime(preferred.Timestamp(), m.clk) + stateDiff, err := state.NewDiff(m.lastAccepted, m) if err != nil { return err @@ -163,21 +171,34 @@ func (m *manager) VerifyTx(tx *txs.Tx) error { unitFees, err := stateDiff.GetUnitFees() if err != nil { - return err + return fmt.Errorf("failed retrieving unit fees: %w", err) } feeWindows, err := stateDiff.GetFeeWindows() if err != nil { - return err + return fmt.Errorf("failed retrieving fee windows: %w", err) } var ( - feeCfg = m.backend.Config.GetDynamicFeesConfig(m.state.GetTimestamp()) - feeManager = fees.NewManager(unitFees, feeWindows) + chainTime = stateDiff.GetTimestamp() + isEForkActive = m.backend.Config.IsEUpgradeActivated(chainTime) + feesCfg = m.backend.Config.GetDynamicFeesConfig(chainTime) ) + + feeManager := fees.NewManager(unitFees, feeWindows) + if isEForkActive { + feeManager = feeManager.ComputeNext( + chainTime.Unix(), + nextBlkTime.Unix(), + feesCfg.BlockUnitsTarget, + feesCfg.UpdateCoefficient, + feesCfg.MinUnitFees, + ) + } + err = tx.Unsigned.Visit(&executor.SemanticVerifier{ Backend: m.backend, BlkFeeManager: feeManager, - UnitCaps: feeCfg.BlockUnitsCap, + UnitCaps: feesCfg.BlockUnitsCap, State: stateDiff, Tx: tx, }) diff --git a/vms/avm/block/executor/manager_test.go b/vms/avm/block/executor/manager_test.go index b65e89131a14..697f4fc4c6da 100644 --- a/vms/avm/block/executor/manager_test.go +++ b/vms/avm/block/executor/manager_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/timer/mockable" "github.com/ava-labs/avalanchego/vms/avm/block" "github.com/ava-labs/avalanchego/vms/avm/state" "github.com/ava-labs/avalanchego/vms/avm/txs" @@ -165,19 +166,27 @@ func TestManagerVerifyTx(t *testing.T) { }, managerF: func(ctrl *gomock.Controller) *manager { lastAcceptedID := ids.GenerateTestID() + lastAcceptedMockBlock := block.NewMockBlock(ctrl) + lastAcceptedMockBlock.EXPECT().ID().Return(lastAcceptedID).AnyTimes() + lastAcceptedMockBlock.EXPECT().Timestamp().Return(time.Now().Truncate(time.Second)).AnyTimes() // These values don't matter for this test state := state.NewMockState(ctrl) - state.EXPECT().GetLastAccepted().Return(lastAcceptedID) + state.EXPECT().GetLastAccepted().Return(lastAcceptedID).AnyTimes() + state.EXPECT().GetBlock(lastAcceptedID).Return(lastAcceptedMockBlock, nil).AnyTimes() state.EXPECT().GetTimestamp().Return(time.Time{}).AnyTimes() state.EXPECT().GetUnitFees().Return(commonfees.Empty, nil).AnyTimes() state.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows, nil).AnyTimes() - return &manager{ + m := &manager{ backend: defaultTestBackend(true, nil), + clk: &mockable.Clock{}, state: state, lastAccepted: lastAcceptedID, } + m.SetPreference(lastAcceptedID) + + return m }, expectedErr: errTestSemanticVerifyFail, }, @@ -197,19 +206,26 @@ func TestManagerVerifyTx(t *testing.T) { }, managerF: func(ctrl *gomock.Controller) *manager { lastAcceptedID := ids.GenerateTestID() + lastAcceptedMockBlock := block.NewMockBlock(ctrl) + lastAcceptedMockBlock.EXPECT().ID().Return(lastAcceptedID).AnyTimes() + lastAcceptedMockBlock.EXPECT().Timestamp().Return(time.Now().Truncate(time.Second)).AnyTimes() // These values don't matter for this test state := state.NewMockState(ctrl) - state.EXPECT().GetLastAccepted().Return(lastAcceptedID) + state.EXPECT().GetLastAccepted().Return(lastAcceptedID).AnyTimes() + state.EXPECT().GetBlock(lastAcceptedID).Return(lastAcceptedMockBlock, nil).AnyTimes() state.EXPECT().GetTimestamp().Return(time.Time{}).AnyTimes() state.EXPECT().GetUnitFees().Return(commonfees.Empty, nil).AnyTimes() state.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows, nil).AnyTimes() - return &manager{ + m := &manager{ backend: defaultTestBackend(true, nil), + clk: &mockable.Clock{}, state: state, lastAccepted: lastAcceptedID, } + m.SetPreference(lastAcceptedID) + return m }, expectedErr: errTestExecutionFail, }, @@ -229,19 +245,26 @@ func TestManagerVerifyTx(t *testing.T) { }, managerF: func(ctrl *gomock.Controller) *manager { lastAcceptedID := ids.GenerateTestID() + lastAcceptedMockBlock := block.NewMockBlock(ctrl) + lastAcceptedMockBlock.EXPECT().ID().Return(lastAcceptedID).AnyTimes() + lastAcceptedMockBlock.EXPECT().Timestamp().Return(time.Now().Truncate(time.Second)).AnyTimes() // These values don't matter for this test state := state.NewMockState(ctrl) - state.EXPECT().GetLastAccepted().Return(lastAcceptedID) + state.EXPECT().GetLastAccepted().Return(lastAcceptedID).AnyTimes() + state.EXPECT().GetBlock(lastAcceptedID).Return(lastAcceptedMockBlock, nil).AnyTimes() state.EXPECT().GetTimestamp().Return(time.Time{}).AnyTimes() state.EXPECT().GetUnitFees().Return(commonfees.Empty, nil).AnyTimes() state.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows, nil).AnyTimes() - return &manager{ + m := &manager{ backend: defaultTestBackend(true, nil), + clk: &mockable.Clock{}, state: state, lastAccepted: lastAcceptedID, } + m.SetPreference(lastAcceptedID) + return m }, expectedErr: nil, }, From e73435bcf8e2449b73c585d697fda09ad7f30fdd Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 11 Mar 2024 01:09:02 +0100 Subject: [PATCH 111/132] another fee rate 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 dac2f0d5093f..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(1739274941520500992), 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 4b8531e695cc50818c51cf1f2cfeca94e31e4b90 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 11 Mar 2024 14:02:18 +0100 Subject: [PATCH 112/132] fixed build blocks for e upgrade --- vms/avm/block/builder/builder.go | 19 +++++++++++++------ vms/avm/block/builder/builder_test.go | 10 ++++++++++ vms/components/fees/dimensions.go | 9 +++++++++ vms/components/fees/manager.go | 4 ++-- 4 files changed, 34 insertions(+), 8 deletions(-) diff --git a/vms/avm/block/builder/builder.go b/vms/avm/block/builder/builder.go index 6cbc093a81cc..28ae4899e557 100644 --- a/vms/avm/block/builder/builder.go +++ b/vms/avm/block/builder/builder.go @@ -118,11 +118,16 @@ func (b *builder) BuildBlock(context.Context) (snowman.Block, error) { for { tx, exists := b.mempool.Peek() - // Invariant: [mempool.MaxTxSize] < [targetBlockSize]. This guarantees - // that we will only stop building a block once there are no - // transactions in the mempool or the block is at least - // [targetBlockSize - mempool.MaxTxSize] bytes full. - if !exists || len(tx.Bytes()) > remainingSize { + if !exists { + break + } + 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 + done := (!isEForkActive && txSize > remainingSize) || + (isEForkActive && !fees.Compare(feeManager.GetCumulatedUnits(), feesCfg.BlockUnitsTarget)) + if done { break } b.mempool.Remove(tx) @@ -177,7 +182,9 @@ func (b *builder) BuildBlock(context.Context) (snowman.Block, error) { txDiff.SetFeeWindows(feeManager.GetFeeWindows()) txDiff.Apply(stateDiff) - remainingSize -= len(tx.Bytes()) + if isEForkActive { + remainingSize -= txSize + } blockTxs = append(blockTxs, tx) } diff --git a/vms/avm/block/builder/builder_test.go b/vms/avm/block/builder/builder_test.go index e6eb3db048ea..725f702df49c 100644 --- a/vms/avm/block/builder/builder_test.go +++ b/vms/avm/block/builder/builder_test.go @@ -133,7 +133,9 @@ func TestBuilderBuildBlock(t *testing.T) { unsignedTx := txs.NewMockUnsignedTx(ctrl) unsignedTx.EXPECT().Visit(gomock.Any()).Return(errTest) // Fail semantic verification + unsignedTx.EXPECT().SetBytes(gomock.Any()) // needed for the SetBytes below tx := &txs.Tx{Unsigned: unsignedTx} + tx.SetBytes([]byte{0x0, 0x1}, []byte{0xff, 0xff}) mempool := mempool.NewMockMempool(ctrl) mempool.EXPECT().Peek().Return(tx, true) @@ -182,8 +184,10 @@ func TestBuilderBuildBlock(t *testing.T) { unsignedTx := txs.NewMockUnsignedTx(ctrl) unsignedTx.EXPECT().Visit(gomock.Any()).Return(nil) // Pass semantic verification + unsignedTx.EXPECT().SetBytes(gomock.Any()) // needed for the SetBytes below unsignedTx.EXPECT().Visit(gomock.Any()).Return(errTest) // Fail execution tx := &txs.Tx{Unsigned: unsignedTx} + tx.SetBytes([]byte{0x0, 0x1}, []byte{0xff, 0xff}) mempool := mempool.NewMockMempool(ctrl) mempool.EXPECT().Peek().Return(tx, true) @@ -234,7 +238,9 @@ func TestBuilderBuildBlock(t *testing.T) { unsignedTx := txs.NewMockUnsignedTx(ctrl) unsignedTx.EXPECT().Visit(gomock.Any()).Return(nil) // Pass semantic verification unsignedTx.EXPECT().Visit(gomock.Any()).Return(nil) // Pass execution + unsignedTx.EXPECT().SetBytes(gomock.Any()) // needed for the SetBytes below tx := &txs.Tx{Unsigned: unsignedTx} + tx.SetBytes([]byte{0x0, 0x1}, []byte{0xff, 0xff}) mempool := mempool.NewMockMempool(ctrl) mempool.EXPECT().Peek().Return(tx, true) @@ -394,6 +400,7 @@ func TestBuilderBuildBlock(t *testing.T) { inputID := ids.GenerateTestID() unsignedTx := txs.NewMockUnsignedTx(ctrl) + unsignedTx.EXPECT().SetBytes(gomock.Any()) // needed for the SetBytes below unsignedTx.EXPECT().Visit(gomock.Any()).Return(nil) // Pass semantic verification unsignedTx.EXPECT().Visit(gomock.Any()).DoAndReturn( // Pass execution func(visitor txs.Visitor) error { @@ -405,6 +412,7 @@ func TestBuilderBuildBlock(t *testing.T) { ) unsignedTx.EXPECT().SetBytes(gomock.Any()).AnyTimes() tx := &txs.Tx{Unsigned: unsignedTx} + tx.SetBytes([]byte{0x0, 0x1}, []byte{0xff, 0xff}) mempool := mempool.NewMockMempool(ctrl) mempool.EXPECT().Peek().Return(tx, true) @@ -473,6 +481,7 @@ func TestBuilderBuildBlock(t *testing.T) { inputID := ids.GenerateTestID() unsignedTx := txs.NewMockUnsignedTx(ctrl) + unsignedTx.EXPECT().SetBytes(gomock.Any()) // needed for the SetBytes below unsignedTx.EXPECT().Visit(gomock.Any()).Return(nil) // Pass semantic verification unsignedTx.EXPECT().Visit(gomock.Any()).DoAndReturn( // Pass execution func(visitor txs.Visitor) error { @@ -484,6 +493,7 @@ func TestBuilderBuildBlock(t *testing.T) { ) unsignedTx.EXPECT().SetBytes(gomock.Any()).AnyTimes() tx := &txs.Tx{Unsigned: unsignedTx} + tx.SetBytes([]byte{0x0, 0x1}, []byte{0xff, 0xff}) mempool := mempool.NewMockMempool(ctrl) mempool.EXPECT().Peek().Return(tx, true) 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: From 13e8b9072a5c88cd381820462580058f56981dea Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 11 Mar 2024 14:55:12 +0100 Subject: [PATCH 113/132] exponential fee update stability test --- 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 cb6aae10e5e2a59cd5ac97eab61db8a4108c7614 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 11 Mar 2024 17:06:03 +0100 Subject: [PATCH 114/132] fixed merge --- vms/avm/block/builder/builder.go | 2 +- vms/avm/block/executor/block.go | 2 +- vms/avm/block/executor/manager.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/vms/avm/block/builder/builder.go b/vms/avm/block/builder/builder.go index 28ae4899e557..44007e0f4d80 100644 --- a/vms/avm/block/builder/builder.go +++ b/vms/avm/block/builder/builder.go @@ -92,7 +92,7 @@ func (b *builder) BuildBlock(context.Context) (snowman.Block, error) { remainingSize = targetBlockSize chainTime = stateDiff.GetTimestamp() - isEForkActive = b.backend.Config.IsEUpgradeActivated(chainTime) + isEForkActive = b.backend.Config.IsEUActivated(chainTime) feesCfg = b.backend.Config.GetDynamicFeesConfig(chainTime) ) diff --git a/vms/avm/block/executor/block.go b/vms/avm/block/executor/block.go index 85dd57b2701a..e8899f650873 100644 --- a/vms/avm/block/executor/block.go +++ b/vms/avm/block/executor/block.go @@ -141,7 +141,7 @@ func (b *Block) Verify(context.Context) error { } var ( - isEForkActive = b.manager.backend.Config.IsEUpgradeActivated(parentChainTime) + isEForkActive = b.manager.backend.Config.IsEUActivated(parentChainTime) feesCfg = b.manager.backend.Config.GetDynamicFeesConfig(parentChainTime) ) diff --git a/vms/avm/block/executor/manager.go b/vms/avm/block/executor/manager.go index dd430345ec88..0df2adb44053 100644 --- a/vms/avm/block/executor/manager.go +++ b/vms/avm/block/executor/manager.go @@ -180,7 +180,7 @@ func (m *manager) VerifyTx(tx *txs.Tx) error { var ( chainTime = stateDiff.GetTimestamp() - isEForkActive = m.backend.Config.IsEUpgradeActivated(chainTime) + isEForkActive = m.backend.Config.IsEUActivated(chainTime) feesCfg = m.backend.Config.GetDynamicFeesConfig(chainTime) ) From 0a5c32c5ce62c7dfcb5fd6cf15980876d3f7e964 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Fri, 15 Mar 2024 11:02:51 +0100 Subject: [PATCH 115/132] simplified fee manager --- tests/e2e/p/workflow.go | 4 +- tests/e2e/x/transfer/virtuous.go | 4 +- vms/avm/block/builder/builder.go | 11 +- vms/avm/block/executor/block.go | 9 +- vms/avm/block/executor/manager.go | 9 +- vms/avm/config/config.go | 8 +- vms/avm/config/dynamic_fees_config.go | 59 +----- vms/avm/service_test.go | 2 +- vms/avm/tx.go | 6 +- vms/avm/tx_builders.go | 42 +--- .../txs/executor/semantic_verifier_test.go | 8 +- vms/avm/txs/fees/calculator_test.go | 10 +- vms/components/fees/config.go | 60 ++++++ vms/components/fees/manager.go | 74 ++----- vms/components/fees/manager_test.go | 198 ++++++++++-------- wallet/chain/x/builder_test.go | 64 +++--- wallet/chain/x/wallet.go | 24 +-- 17 files changed, 271 insertions(+), 321 deletions(-) create mode 100644 vms/components/fees/config.go diff --git a/tests/e2e/p/workflow.go b/tests/e2e/p/workflow.go index 8ebda62d8fb7..6607fb13704a 100644 --- a/tests/e2e/p/workflow.go +++ b/tests/e2e/p/workflow.go @@ -188,12 +188,10 @@ var _ = e2e.DescribePChain("[Workflow]", func() { feeCfg := config.EUpgradeDynamicFeesConfig unitFees, err := xChainClient.GetUnitFees(e2e.DefaultContext()) require.NoError(err) - feeWindows, err := xChainClient.GetFeeWindows(e2e.DefaultContext()) - require.NoError(err) feeCalc := fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(unitFees, feeWindows), + FeeManager: commonfees.NewManager(unitFees), ConsumedUnitsCap: feeCfg.BlockUnitsCap, Codec: xbackends.Parser.Codec(), Credentials: tx.Creds, diff --git a/tests/e2e/x/transfer/virtuous.go b/tests/e2e/x/transfer/virtuous.go index dbb953a7d1e5..9ab2c3f7869b 100644 --- a/tests/e2e/x/transfer/virtuous.go +++ b/tests/e2e/x/transfer/virtuous.go @@ -192,11 +192,9 @@ var _ = e2e.DescribeXChainSerial("[Virtuous Transfer Tx AVAX]", func() { xChainClient := avm.NewClient(nodeURI.URI, "X") unitFees, err := xChainClient.GetUnitFees(e2e.DefaultContext()) require.NoError(err) - feeWindows, err := xChainClient.GetFeeWindows(e2e.DefaultContext()) - require.NoError(err) feeCalc := fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(unitFees, feeWindows), + FeeManager: commonfees.NewManager(unitFees), ConsumedUnitsCap: feeCfg.BlockUnitsCap, Codec: xbackends.Parser.Codec(), Credentials: tx.Creds, diff --git a/vms/avm/block/builder/builder.go b/vms/avm/block/builder/builder.go index 44007e0f4d80..af7312983948 100644 --- a/vms/avm/block/builder/builder.go +++ b/vms/avm/block/builder/builder.go @@ -105,14 +105,13 @@ func (b *builder) BuildBlock(context.Context) (snowman.Block, error) { return nil, fmt.Errorf("failed retrieving fee windows: %w", err) } - feeManager := fees.NewManager(unitFees, feeWindows) + feeManager := fees.NewManager(unitFees) if isEForkActive { - feeManager = feeManager.ComputeNext( + feeManager.UpdateUnitFees( + feesCfg, + feeWindows, chainTime.Unix(), nextTimestamp.Unix(), - feesCfg.BlockUnitsTarget, - feesCfg.UpdateCoefficient, - feesCfg.MinUnitFees, ) } @@ -179,7 +178,7 @@ func (b *builder) BuildBlock(context.Context) (snowman.Block, error) { txDiff.AddTx(tx) txDiff.SetUnitFees(feeManager.GetUnitFees()) - txDiff.SetFeeWindows(feeManager.GetFeeWindows()) + txDiff.SetFeeWindows(feeWindows) txDiff.Apply(stateDiff) if isEForkActive { diff --git a/vms/avm/block/executor/block.go b/vms/avm/block/executor/block.go index e8899f650873..c26a4af93708 100644 --- a/vms/avm/block/executor/block.go +++ b/vms/avm/block/executor/block.go @@ -145,14 +145,13 @@ func (b *Block) Verify(context.Context) error { feesCfg = b.manager.backend.Config.GetDynamicFeesConfig(parentChainTime) ) - feeManager := fees.NewManager(unitFees, feeWindows) + feeManager := fees.NewManager(unitFees) if isEForkActive { - feeManager = feeManager.ComputeNext( + feeManager.UpdateUnitFees( + feesCfg, + feeWindows, parentChainTime.Unix(), newChainTime.Unix(), - feesCfg.BlockUnitsTarget, - feesCfg.UpdateCoefficient, - feesCfg.MinUnitFees, ) } diff --git a/vms/avm/block/executor/manager.go b/vms/avm/block/executor/manager.go index 0df2adb44053..e27eccf9a1d0 100644 --- a/vms/avm/block/executor/manager.go +++ b/vms/avm/block/executor/manager.go @@ -184,14 +184,13 @@ func (m *manager) VerifyTx(tx *txs.Tx) error { feesCfg = m.backend.Config.GetDynamicFeesConfig(chainTime) ) - feeManager := fees.NewManager(unitFees, feeWindows) + feeManager := fees.NewManager(unitFees) if isEForkActive { - feeManager = feeManager.ComputeNext( + feeManager.UpdateUnitFees( + feesCfg, + feeWindows, chainTime.Unix(), nextBlkTime.Unix(), - feesCfg.BlockUnitsTarget, - feesCfg.UpdateCoefficient, - feesCfg.MinUnitFees, ) } diff --git a/vms/avm/config/config.go b/vms/avm/config/config.go index 4a5db5818355..db40903ed1e3 100644 --- a/vms/avm/config/config.go +++ b/vms/avm/config/config.go @@ -3,7 +3,11 @@ package config -import "time" +import ( + "time" + + commonfees "github.com/ava-labs/avalanchego/vms/components/fees" +) // Struct collecting all the foundational parameters of the AVM type Config struct { @@ -24,7 +28,7 @@ func (c *Config) IsEUActivated(timestamp time.Time) bool { return !timestamp.Before(c.EUpgradeTime) } -func (c *Config) GetDynamicFeesConfig(timestamp time.Time) DynamicFeesConfig { +func (c *Config) GetDynamicFeesConfig(timestamp time.Time) commonfees.DynamicFeesConfig { if !c.IsEUActivated(timestamp) { return PreEUpgradeDynamicFeesConfig } diff --git a/vms/avm/config/dynamic_fees_config.go b/vms/avm/config/dynamic_fees_config.go index 8cdd7c19c1cf..32ed6511ee52 100644 --- a/vms/avm/config/dynamic_fees_config.go +++ b/vms/avm/config/dynamic_fees_config.go @@ -4,8 +4,6 @@ package config import ( - "fmt" - "github.com/ava-labs/avalanchego/utils/units" commonfees "github.com/ava-labs/avalanchego/vms/components/fees" @@ -19,14 +17,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 var ( - EUpgradeDynamicFeesConfig = DynamicFeesConfig{ + EUpgradeDynamicFeesConfig = commonfees.DynamicFeesConfig{ InitialUnitFees: commonfees.Dimensions{ 1 * units.NanoAvax, 2 * units.NanoAvax, @@ -45,59 +43,8 @@ var ( } // TODO ABENEGIA: decide if and how to validate PreEUpgradeDynamicFeesConfig - PreEUpgradeDynamicFeesConfig = DynamicFeesConfig{ + PreEUpgradeDynamicFeesConfig = commonfees.DynamicFeesConfig{ InitialUnitFees: commonfees.Empty, BlockUnitsCap: commonfees.Max, } ) - -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 - - // UpdateCoefficient contains, per each fee dimension, the - // exponential update coefficient. Setting an entry to 0 makes - // the corresponding fee rate constant. - UpdateCoefficient 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/avm/service_test.go b/vms/avm/service_test.go index 013e40afe289..0b428fec7208 100644 --- a/vms/avm/service_test.go +++ b/vms/avm/service_test.go @@ -2673,7 +2673,7 @@ func TestNFTWorkflow(t *testing.T) { feeCalc := &fees.Calculator{ IsEUpgradeActive: true, Config: &env.vm.Config, - FeeManager: commonfees.NewManager(feesCfg.InitialUnitFees, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(feesCfg.InitialUnitFees), ConsumedUnitsCap: feesCfg.BlockUnitsCap, Codec: env.service.txBuilderBackend.codec, Credentials: createAssetTx.Creds, diff --git a/vms/avm/tx.go b/vms/avm/tx.go index 2c7702250195..935847f07c93 100644 --- a/vms/avm/tx.go +++ b/vms/avm/tx.go @@ -131,14 +131,10 @@ func (tx *Tx) Verify(context.Context) error { if err != nil { return fmt.Errorf("failed retrieving unit fees: %w", err) } - feeWindows, err := tx.vm.state.GetFeeWindows() - if err != nil { - return fmt.Errorf("failed retrieving fee windows: %w", err) - } var ( feeCfg = tx.vm.txExecutorBackend.Config.GetDynamicFeesConfig(tx.vm.state.GetTimestamp()) - feeManager = fees.NewManager(unitFees, feeWindows) + feeManager = fees.NewManager(unitFees) ) return tx.tx.Unsigned.Visit(&executor.SemanticVerifier{ Backend: tx.vm.txExecutorBackend, diff --git a/vms/avm/tx_builders.go b/vms/avm/tx_builders.go index 5d1b9183a070..bdf475ea6e21 100644 --- a/vms/avm/tx_builders.go +++ b/vms/avm/tx_builders.go @@ -45,17 +45,13 @@ func buildCreateAssetTx( if err != nil { return nil, ids.ShortEmpty, fmt.Errorf("failed retrieving unit fees: %w", err) } - feeWindows, err := backend.State().GetFeeWindows() - if err != nil { - return nil, ids.ShortEmpty, fmt.Errorf("failed retrieving fee windows: %w", err) - } var ( pBuilder, pSigner = builders(backend, kc) chainTime = backend.State().GetTimestamp() cfg = backend.Config() feeCfg = cfg.GetDynamicFeesConfig(chainTime) - feeMan = commonfees.NewManager(unitFees, feeWindows) + feeMan = commonfees.NewManager(unitFees) feeCalc = &fees.Calculator{ IsEUpgradeActive: cfg.IsEUActivated(chainTime), Config: cfg, @@ -96,17 +92,13 @@ func buildBaseTx( if err != nil { return nil, ids.ShortEmpty, fmt.Errorf("failed retrieving unit fees: %w", err) } - feeWindows, err := backend.State().GetFeeWindows() - if err != nil { - return nil, ids.ShortEmpty, fmt.Errorf("failed retrieving fee windows: %w", err) - } var ( pBuilder, pSigner = builders(backend, kc) chainTime = backend.State().GetTimestamp() cfg = backend.Config() feeCfg = cfg.GetDynamicFeesConfig(chainTime) - feeMan = commonfees.NewManager(unitFees, feeWindows) + feeMan = commonfees.NewManager(unitFees) feeCalc = &fees.Calculator{ IsEUpgradeActive: cfg.IsEUActivated(chainTime), Config: cfg, @@ -145,17 +137,13 @@ func mintNFT( if err != nil { return nil, fmt.Errorf("failed retrieving unit fees: %w", err) } - feeWindows, err := backend.State().GetFeeWindows() - if err != nil { - return nil, fmt.Errorf("failed retrieving fee windows: %w", err) - } var ( pBuilder, pSigner = builders(backend, kc) chainTime = backend.State().GetTimestamp() cfg = backend.Config() feeCfg = cfg.GetDynamicFeesConfig(chainTime) - feeMan = commonfees.NewManager(unitFees, feeWindows) + feeMan = commonfees.NewManager(unitFees) feeCalc = &fees.Calculator{ IsEUpgradeActive: cfg.IsEUActivated(chainTime), Config: cfg, @@ -189,17 +177,13 @@ func mintFTs( if err != nil { return nil, fmt.Errorf("failed retrieving unit fees: %w", err) } - feeWindows, err := backend.State().GetFeeWindows() - if err != nil { - return nil, fmt.Errorf("failed retrieving fee windows: %w", err) - } var ( pBuilder, pSigner = builders(backend, kc) chainTime = backend.State().GetTimestamp() cfg = backend.Config() feeCfg = cfg.GetDynamicFeesConfig(chainTime) - feeMan = commonfees.NewManager(unitFees, feeWindows) + feeMan = commonfees.NewManager(unitFees) feeCalc = &fees.Calculator{ IsEUpgradeActive: cfg.IsEUActivated(chainTime), Config: cfg, @@ -230,17 +214,13 @@ func buildOperation( if err != nil { return nil, fmt.Errorf("failed retrieving unit fees: %w", err) } - feeWindows, err := backend.State().GetFeeWindows() - if err != nil { - return nil, fmt.Errorf("failed retrieving fee windows: %w", err) - } var ( pBuilder, pSigner = builders(backend, kc) chainTime = backend.State().GetTimestamp() cfg = backend.Config() feeCfg = cfg.GetDynamicFeesConfig(chainTime) - feeMan = commonfees.NewManager(unitFees, feeWindows) + feeMan = commonfees.NewManager(unitFees) feeCalc = &fees.Calculator{ IsEUpgradeActive: cfg.IsEUActivated(chainTime), Config: cfg, @@ -272,17 +252,13 @@ func buildImportTx( if err != nil { return nil, fmt.Errorf("failed retrieving unit fees: %w", err) } - feeWindows, err := backend.State().GetFeeWindows() - if err != nil { - return nil, fmt.Errorf("failed retrieving fee windows: %w", err) - } var ( pBuilder, pSigner = builders(backend, kc) chainTime = backend.State().GetTimestamp() cfg = backend.Config() feeCfg = cfg.GetDynamicFeesConfig(chainTime) - feeMan = commonfees.NewManager(unitFees, feeWindows) + feeMan = commonfees.NewManager(unitFees) feeCalc = &fees.Calculator{ IsEUpgradeActive: cfg.IsEUActivated(chainTime), Config: cfg, @@ -323,17 +299,13 @@ func buildExportTx( if err != nil { return nil, ids.ShortEmpty, fmt.Errorf("failed retrieving unit fees: %w", err) } - feeWindows, err := backend.State().GetFeeWindows() - if err != nil { - return nil, ids.ShortEmpty, fmt.Errorf("failed retrieving fee windows: %w", err) - } var ( pBuilder, pSigner = builders(backend, kc) chainTime = backend.State().GetTimestamp() cfg = backend.Config() feeCfg = cfg.GetDynamicFeesConfig(chainTime) - feeMan = commonfees.NewManager(unitFees, feeWindows) + feeMan = commonfees.NewManager(unitFees) feeCalc = &fees.Calculator{ IsEUpgradeActive: cfg.IsEUActivated(chainTime), Config: cfg, diff --git a/vms/avm/txs/executor/semantic_verifier_test.go b/vms/avm/txs/executor/semantic_verifier_test.go index 705b3505a5db..3c0793c53969 100644 --- a/vms/avm/txs/executor/semantic_verifier_test.go +++ b/vms/avm/txs/executor/semantic_verifier_test.go @@ -744,7 +744,7 @@ func TestSemanticVerifierBaseTx(t *testing.T) { err = tx.Unsigned.Visit(&SemanticVerifier{ Backend: backend, - BlkFeeManager: fees.NewManager(feeCfg.InitialUnitFees, fees.EmptyWindows), + BlkFeeManager: fees.NewManager(feeCfg.InitialUnitFees), UnitCaps: feeCfg.BlockUnitsCap, State: state, Tx: tx, @@ -1498,7 +1498,7 @@ func TestSemanticVerifierExportTx(t *testing.T) { err = tx.Unsigned.Visit(&SemanticVerifier{ Backend: backend, - BlkFeeManager: fees.NewManager(feeCfg.InitialUnitFees, fees.EmptyWindows), + BlkFeeManager: fees.NewManager(feeCfg.InitialUnitFees), UnitCaps: feeCfg.BlockUnitsCap, State: state, Tx: tx, @@ -1643,7 +1643,7 @@ func TestSemanticVerifierExportTxDifferentSubnet(t *testing.T) { err = tx.Unsigned.Visit(&SemanticVerifier{ Backend: backend, - BlkFeeManager: fees.NewManager(feeCfg.InitialUnitFees, fees.EmptyWindows), + BlkFeeManager: fees.NewManager(feeCfg.InitialUnitFees), UnitCaps: feeCfg.BlockUnitsCap, State: state, Tx: tx, @@ -2181,7 +2181,7 @@ func TestSemanticVerifierImportTx(t *testing.T) { err = tx.Unsigned.Visit(&SemanticVerifier{ Backend: backend, - BlkFeeManager: fees.NewManager(feeCfg.InitialUnitFees, fees.EmptyWindows), + BlkFeeManager: fees.NewManager(feeCfg.InitialUnitFees), UnitCaps: feeCfg.BlockUnitsCap, State: state, Tx: tx, diff --git a/vms/avm/txs/fees/calculator_test.go b/vms/avm/txs/fees/calculator_test.go index 292bb42f2173..4903a01edec2 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) { IsEUpgradeActive: cfg.IsEUActivated(chainTime), Config: cfg, Codec: codec, - FeeManager: fees.NewManager(testUnitFees, fees.EmptyWindows), + FeeManager: fees.NewManager(testUnitFees), ConsumedUnitsCap: consumedUnitCaps, Credentials: sTx.Creds, } @@ -274,7 +274,7 @@ func TestCreateAssetTxFees(t *testing.T) { IsEUpgradeActive: cfg.IsEUActivated(chainTime), Config: cfg, Codec: codec, - FeeManager: fees.NewManager(testUnitFees, fees.EmptyWindows), + FeeManager: fees.NewManager(testUnitFees), ConsumedUnitsCap: consumedUnitCaps, Credentials: sTx.Creds, } @@ -395,7 +395,7 @@ func TestOperationTxFees(t *testing.T) { IsEUpgradeActive: cfg.IsEUActivated(chainTime), Config: cfg, Codec: codec, - FeeManager: fees.NewManager(testUnitFees, fees.EmptyWindows), + FeeManager: fees.NewManager(testUnitFees), ConsumedUnitsCap: consumedUnitCaps, Credentials: sTx.Creds, } @@ -512,7 +512,7 @@ func TestImportTxFees(t *testing.T) { IsEUpgradeActive: cfg.IsEUActivated(chainTime), Config: cfg, Codec: codec, - FeeManager: fees.NewManager(testUnitFees, fees.EmptyWindows), + FeeManager: fees.NewManager(testUnitFees), ConsumedUnitsCap: consumedUnitCaps, Credentials: sTx.Creds, } @@ -619,7 +619,7 @@ func TestExportTxFees(t *testing.T) { IsEUpgradeActive: cfg.IsEUActivated(chainTime), Config: cfg, Codec: codec, - FeeManager: fees.NewManager(testUnitFees, fees.EmptyWindows), + FeeManager: fees.NewManager(testUnitFees), ConsumedUnitsCap: consumedUnitCaps, Credentials: sTx.Creds, } 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 27a6cc049e76..7a28975cea3f 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 } @@ -100,55 +92,33 @@ func (m *Manager) RemoveUnits(unitsToRm Dimensions) error { return nil } -func (m *Manager) ComputeNext( - lastTime, - currTime int64, - targetUnits, - updateCoefficients, - minUnitPrice Dimensions, -) *Manager { +// [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) - nextManager := &Manager{} + idx := 0 + if since < WindowSize { + idx = WindowSize - 1 - since + } + 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 + windows[i] = Roll(windows[i], since) + Update(&windows[i], idx, m.cumulatedUnits[i]) } - 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) +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 } - - 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..d95a7db4aa3a 100644 --- a/vms/components/fees/manager_test.go +++ b/vms/components/fees/manager_test.go @@ -15,145 +15,157 @@ func TestComputeNextEmptyWindows(t *testing.T) { require := require.New(t) var ( - initialUnitFees = Dimensions{1, 1, 1, 1} - consumedUnits = Dimensions{5, 25, 30, 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} + feeWindows = Windows{} // 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, - windows: [FeeDimensions]Window{}, + unitFees: currentUnitFees, cumulatedUnits: consumedUnits, } - next := m.ComputeNext( + m.UpdateUnitFees( + feesCfg, + feeWindows, lastBlkTime.Unix(), currBlkTime.Unix(), - targetComplexity, - updateCoefficient, - minUnitFees, ) // Bandwidth units are below target, next unit fees are pushed to the minimum - require.Equal(minUnitFees[Bandwidth], next.unitFees[Bandwidth]) + require.Equal(feesCfg.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(feesCfg.MinUnitFees[UTXORead], m.unitFees[UTXORead]) // UTXOWrite units are above target, next unit fees increased - require.Equal(uint64(4), next.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(uint64(4*1<<60), next.unitFees[Compute]) + require.Equal(feesCfg.MinUnitFees[Compute], m.unitFees[Compute]) + + m.UpdateWindows(&feeWindows, lastBlkTime.Unix(), currBlkTime.Unix()) + m.UpdateUnitFees( + feesCfg, + feeWindows, + lastBlkTime.Unix(), + currBlkTime.Unix(), + ) + + // 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) { 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} + 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) currBlkTime = lastBlkTime.Add(time.Second) - - updateCoefficient = Dimensions{1, 2, 5, 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 - }, + unitFees: currentUnitFees, cumulatedUnits: consumedUnits, } - next := m.ComputeNext( + m.UpdateUnitFees( + feesCfg, + feeWindows, lastBlkTime.Unix(), currBlkTime.Unix(), - targetComplexity, - updateCoefficient, - minUnitFees, ) // Bandwidth units are below target, next unit fees are pushed to the minimum - require.Equal(minUnitFees[Bandwidth], next.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), 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) { 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} + 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) currBlkTime = lastBlkTime.Add(time.Second) - - 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 it hits the small constrain set for this dimension - {}, - {}, - }, + unitFees: currentUnitFees, cumulatedUnits: consumedUnits, } - next := m.ComputeNext( + + m.UpdateUnitFees( + feesCfg, + feeWindows, lastBlkTime.Unix(), currBlkTime.Unix(), - targetComplexity, - updateCoefficient, - minUnitFees, ) // Bandwidth units are below target, next unit fees are pushed to the minimum - require.Equal(minUnitFees[Bandwidth], next.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], next.unitFees[UTXORead]) + require.Equal(currentUnitFees[UTXORead], m.unitFees[UTXORead]) // UTXOWrite units are below target. Unit fees are decreased. - require.Equal(minUnitFees[UTXOWrite], next.unitFees[UTXOWrite]) + require.Equal(feesCfg.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(feesCfg.MinUnitFees[Compute], m.unitFees[Compute]) } func TestComputeNextStability(t *testing.T) { @@ -166,54 +178,56 @@ 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}, + } + 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} + // 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, - windows: [FeeDimensions]Window{}, cumulatedUnits: consumedUnits1, } - next1 := m1.ComputeNext( + m1.UpdateWindows(&feeWindows1, lastBlkTime.Unix(), currBlkTime.Unix()) + m1.UpdateUnitFees( + feesCfg, + feeWindows1, 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]) + 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, - windows: [FeeDimensions]Window{}, + unitFees: m1.unitFees, cumulatedUnits: consumedUnits2, } - next2 := m2.ComputeNext( + m2.UpdateWindows(&feeWindows2, lastBlkTime.Unix(), currBlkTime.Unix()) + m2.UpdateUnitFees( + feesCfg, + feeWindows2, 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]) + 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/wallet/chain/x/builder_test.go b/wallet/chain/x/builder_test.go index 22ea9c7123f3..6316f55722f3 100644 --- a/wallet/chain/x/builder_test.go +++ b/wallet/chain/x/builder_test.go @@ -94,7 +94,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, Codec: backends.Parser.Codec(), } @@ -109,7 +109,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, Codec: backends.Parser.Codec(), @@ -135,7 +135,7 @@ func TestBaseTx(t *testing.T) { Config: &config.Config{ TxFee: testCtx.BaseTxFee(), }, - FeeManager: commonfees.NewManager(commonfees.Empty, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(commonfees.Empty), ConsumedUnitsCap: commonfees.Max, Codec: backends.Parser.Codec(), } @@ -153,7 +153,7 @@ func TestBaseTx(t *testing.T) { Config: &config.Config{ TxFee: testCtx.BaseTxFee(), }, - FeeManager: commonfees.NewManager(commonfees.Empty, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(commonfees.Empty), ConsumedUnitsCap: commonfees.Max, Codec: backends.Parser.Codec(), Credentials: tx.Creds, @@ -250,7 +250,7 @@ func TestCreateAssetTx(t *testing.T) { // Post E-Upgrade feeCalc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(testUnitFees), ConsumedUnitsCap: testBlockMaxConsumedUnits, Codec: backends.Parser.Codec(), } @@ -269,7 +269,7 @@ func TestCreateAssetTx(t *testing.T) { fc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(testUnitFees), ConsumedUnitsCap: testBlockMaxConsumedUnits, Codec: backends.Parser.Codec(), Credentials: tx.Creds, @@ -295,7 +295,7 @@ func TestCreateAssetTx(t *testing.T) { Config: &config.Config{ CreateAssetTxFee: testCtx.CreateAssetTxFee(), }, - FeeManager: commonfees.NewManager(commonfees.Empty, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(commonfees.Empty), ConsumedUnitsCap: commonfees.Max, Codec: backends.Parser.Codec(), } @@ -317,7 +317,7 @@ func TestCreateAssetTx(t *testing.T) { Config: &config.Config{ CreateAssetTxFee: testCtx.CreateAssetTxFee(), }, - FeeManager: commonfees.NewManager(commonfees.Empty, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(commonfees.Empty), ConsumedUnitsCap: commonfees.Max, Codec: backends.Parser.Codec(), Credentials: tx.Creds, @@ -368,7 +368,7 @@ func TestMintNFTOperation(t *testing.T) { // Post E-Upgrade feeCalc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(testUnitFees), ConsumedUnitsCap: testBlockMaxConsumedUnits, Codec: backends.Parser.Codec(), } @@ -386,7 +386,7 @@ func TestMintNFTOperation(t *testing.T) { fc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(testUnitFees), ConsumedUnitsCap: testBlockMaxConsumedUnits, Codec: backends.Parser.Codec(), Credentials: tx.Creds, @@ -412,7 +412,7 @@ func TestMintNFTOperation(t *testing.T) { Config: &config.Config{ TxFee: testCtx.BaseTxFee(), }, - FeeManager: commonfees.NewManager(commonfees.Empty, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(commonfees.Empty), ConsumedUnitsCap: commonfees.Max, Codec: backends.Parser.Codec(), } @@ -433,7 +433,7 @@ func TestMintNFTOperation(t *testing.T) { Config: &config.Config{ TxFee: testCtx.BaseTxFee(), }, - FeeManager: commonfees.NewManager(commonfees.Empty, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(commonfees.Empty), ConsumedUnitsCap: commonfees.Max, Codec: backends.Parser.Codec(), Credentials: tx.Creds, @@ -490,7 +490,7 @@ func TestMintFTOperation(t *testing.T) { // Post E-Upgrade feeCalc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(testUnitFees), ConsumedUnitsCap: testBlockMaxConsumedUnits, Codec: backends.Parser.Codec(), } @@ -506,7 +506,7 @@ func TestMintFTOperation(t *testing.T) { fc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(testUnitFees), ConsumedUnitsCap: testBlockMaxConsumedUnits, Codec: backends.Parser.Codec(), Credentials: tx.Creds, @@ -532,7 +532,7 @@ func TestMintFTOperation(t *testing.T) { Config: &config.Config{ TxFee: testCtx.BaseTxFee(), }, - FeeManager: commonfees.NewManager(commonfees.Empty, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(commonfees.Empty), ConsumedUnitsCap: commonfees.Max, Codec: backends.Parser.Codec(), } @@ -551,7 +551,7 @@ func TestMintFTOperation(t *testing.T) { Config: &config.Config{ TxFee: testCtx.BaseTxFee(), }, - FeeManager: commonfees.NewManager(commonfees.Empty, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(commonfees.Empty), ConsumedUnitsCap: commonfees.Max, Codec: backends.Parser.Codec(), Credentials: tx.Creds, @@ -603,7 +603,7 @@ func TestMintPropertyOperation(t *testing.T) { // Post E-Upgrade feeCalc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(testUnitFees), ConsumedUnitsCap: testBlockMaxConsumedUnits, Codec: backends.Parser.Codec(), } @@ -620,7 +620,7 @@ func TestMintPropertyOperation(t *testing.T) { fc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(testUnitFees), ConsumedUnitsCap: testBlockMaxConsumedUnits, Codec: backends.Parser.Codec(), Credentials: tx.Creds, @@ -646,7 +646,7 @@ func TestMintPropertyOperation(t *testing.T) { Config: &config.Config{ TxFee: testCtx.BaseTxFee(), }, - FeeManager: commonfees.NewManager(commonfees.Empty, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(commonfees.Empty), ConsumedUnitsCap: commonfees.Max, Codec: backends.Parser.Codec(), } @@ -666,7 +666,7 @@ func TestMintPropertyOperation(t *testing.T) { Config: &config.Config{ TxFee: testCtx.BaseTxFee(), }, - FeeManager: commonfees.NewManager(commonfees.Empty, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(commonfees.Empty), ConsumedUnitsCap: commonfees.Max, Codec: backends.Parser.Codec(), Credentials: tx.Creds, @@ -712,7 +712,7 @@ func TestBurnPropertyOperation(t *testing.T) { // Post E-Upgrade feeCalc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(testUnitFees), ConsumedUnitsCap: testBlockMaxConsumedUnits, Codec: backends.Parser.Codec(), } @@ -728,7 +728,7 @@ func TestBurnPropertyOperation(t *testing.T) { fc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(testUnitFees), ConsumedUnitsCap: testBlockMaxConsumedUnits, Codec: backends.Parser.Codec(), Credentials: tx.Creds, @@ -754,7 +754,7 @@ func TestBurnPropertyOperation(t *testing.T) { Config: &config.Config{ TxFee: testCtx.BaseTxFee(), }, - FeeManager: commonfees.NewManager(commonfees.Empty, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(commonfees.Empty), ConsumedUnitsCap: commonfees.Max, Codec: backends.Parser.Codec(), } @@ -773,7 +773,7 @@ func TestBurnPropertyOperation(t *testing.T) { Config: &config.Config{ TxFee: testCtx.BaseTxFee(), }, - FeeManager: commonfees.NewManager(commonfees.Empty, commonfees.EmptyWindows), + FeeManager: commonfees.NewManager(commonfees.Empty), ConsumedUnitsCap: commonfees.Max, Codec: backends.Parser.Codec(), Credentials: tx.Creds, @@ -831,7 +831,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, Codec: backends.Parser.Codec(), } @@ -847,7 +847,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, Codec: backends.Parser.Codec(), @@ -874,7 +874,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, Codec: backends.Parser.Codec(), } @@ -893,7 +893,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, Codec: backends.Parser.Codec(), Credentials: tx.Creds, @@ -953,7 +953,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, Codec: backends.Parser.Codec(), } @@ -969,7 +969,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, Codec: backends.Parser.Codec(), @@ -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, Codec: backends.Parser.Codec(), } @@ -1014,7 +1014,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, Codec: backends.Parser.Codec(), Credentials: tx.Creds, diff --git a/wallet/chain/x/wallet.go b/wallet/chain/x/wallet.go index c89ca4bd2d8f..fec43228b233 100644 --- a/wallet/chain/x/wallet.go +++ b/wallet/chain/x/wallet.go @@ -174,7 +174,6 @@ type wallet struct { isEForkActive bool unitFees, unitCaps commonfees.Dimensions - feeWindows commonfees.Windows } func (w *wallet) Builder() backends.Builder { @@ -194,7 +193,7 @@ func (w *wallet) IssueBaseTx( } var ( - feesMan = commonfees.NewManager(w.unitFees, w.feeWindows) + feesMan = commonfees.NewManager(w.unitFees) feeCalc = &fees.Calculator{ IsEUpgradeActive: w.isEForkActive, Config: &config.Config{ @@ -225,7 +224,7 @@ func (w *wallet) IssueCreateAssetTx( } var ( - feesMan = commonfees.NewManager(w.unitFees, w.feeWindows) + feesMan = commonfees.NewManager(w.unitFees) feeCalc = &fees.Calculator{ IsEUpgradeActive: w.isEForkActive, Config: &config.Config{ @@ -253,7 +252,7 @@ func (w *wallet) IssueOperationTx( } var ( - feesMan = commonfees.NewManager(w.unitFees, w.feeWindows) + feesMan = commonfees.NewManager(w.unitFees) feeCalc = &fees.Calculator{ IsEUpgradeActive: w.isEForkActive, Config: &config.Config{ @@ -281,7 +280,7 @@ func (w *wallet) IssueOperationTxMintFT( } var ( - feesMan = commonfees.NewManager(w.unitFees, w.feeWindows) + feesMan = commonfees.NewManager(w.unitFees) feeCalc = &fees.Calculator{ IsEUpgradeActive: w.isEForkActive, Config: &config.Config{ @@ -311,7 +310,7 @@ func (w *wallet) IssueOperationTxMintNFT( } var ( - feesMan = commonfees.NewManager(w.unitFees, w.feeWindows) + feesMan = commonfees.NewManager(w.unitFees) feeCalc = &fees.Calculator{ IsEUpgradeActive: w.isEForkActive, Config: &config.Config{ @@ -340,7 +339,7 @@ func (w *wallet) IssueOperationTxMintProperty( } var ( - feesMan = commonfees.NewManager(w.unitFees, w.feeWindows) + feesMan = commonfees.NewManager(w.unitFees) feeCalc = &fees.Calculator{ IsEUpgradeActive: w.isEForkActive, Config: &config.Config{ @@ -368,7 +367,7 @@ func (w *wallet) IssueOperationTxBurnProperty( } var ( - feesMan = commonfees.NewManager(w.unitFees, w.feeWindows) + feesMan = commonfees.NewManager(w.unitFees) feeCalc = &fees.Calculator{ IsEUpgradeActive: w.isEForkActive, Config: &config.Config{ @@ -397,7 +396,7 @@ func (w *wallet) IssueImportTx( } var ( - feesMan = commonfees.NewManager(w.unitFees, w.feeWindows) + feesMan = commonfees.NewManager(w.unitFees) feeCalc = &fees.Calculator{ IsEUpgradeActive: w.isEForkActive, Config: &config.Config{ @@ -426,7 +425,7 @@ func (w *wallet) IssueExportTx( } var ( - feesMan = commonfees.NewManager(w.unitFees, w.feeWindows) + feesMan = commonfees.NewManager(w.unitFees) feeCalc = &fees.Calculator{ IsEUpgradeActive: w.isEForkActive, Config: &config.Config{ @@ -511,11 +510,6 @@ func (w *wallet) refreshFork(options ...common.Option) error { return err } - w.feeWindows, err = w.client.GetFeeWindows(ctx) - if err != nil { - return err - } - eUpgradeTime := version.GetEUpgradeTime(w.NetworkID()) // TODO ABENEGIA: consider introducing this method in X-chain as well From a4558ee4611cf81a991ddf0ec267b18fc6f6df8d Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Fri, 15 Mar 2024 11:53:34 +0100 Subject: [PATCH 116/132] simplified dynamic fees config --- tests/e2e/p/workflow.go | 4 +- tests/e2e/x/transfer/virtuous.go | 4 +- vms/avm/block/builder/builder.go | 5 +- vms/avm/block/executor/block.go | 5 +- vms/avm/block/executor/manager.go | 5 +- vms/avm/client.go | 16 ++---- vms/avm/config/config.go | 16 +----- vms/avm/config/dynamic_fees_config.go | 17 ++++-- vms/avm/service.go | 53 ++++++++++++++++--- vms/avm/service_test.go | 3 +- vms/avm/state/state.go | 3 +- vms/avm/tx.go | 6 ++- vms/avm/tx_builders.go | 35 +++++++----- vms/avm/txs/executor/semantic_verifier.go | 2 +- .../txs/executor/semantic_verifier_test.go | 8 +-- vms/avm/txs/fees/calculator_test.go | 10 ++-- wallet/chain/x/wallet.go | 10 +--- 17 files changed, 119 insertions(+), 83 deletions(-) diff --git a/tests/e2e/p/workflow.go b/tests/e2e/p/workflow.go index 6607fb13704a..1c3e6e184a4d 100644 --- a/tests/e2e/p/workflow.go +++ b/tests/e2e/p/workflow.go @@ -185,8 +185,8 @@ var _ = e2e.DescribePChain("[Workflow]", func() { require.NoError(err) // retrieve fees paid for the tx - feeCfg := config.EUpgradeDynamicFeesConfig - unitFees, err := xChainClient.GetUnitFees(e2e.DefaultContext()) + feeCfg := config.GetDynamicFeesConfig(true /*isEActive*/) + _, unitFees, err := xChainClient.GetUnitFees(e2e.DefaultContext()) require.NoError(err) feeCalc := fees.Calculator{ diff --git a/tests/e2e/x/transfer/virtuous.go b/tests/e2e/x/transfer/virtuous.go index 9ab2c3f7869b..9bba436dc0b1 100644 --- a/tests/e2e/x/transfer/virtuous.go +++ b/tests/e2e/x/transfer/virtuous.go @@ -187,10 +187,10 @@ var _ = e2e.DescribeXChainSerial("[Virtuous Transfer Tx AVAX]", func() { require.NoError(err) // retrieve fees paid for the BaseTx - feeCfg := config.EUpgradeDynamicFeesConfig + feeCfg := config.GetDynamicFeesConfig(true /*isEActive*/) nodeURI := e2e.Env.GetRandomNodeURI() xChainClient := avm.NewClient(nodeURI.URI, "X") - unitFees, err := xChainClient.GetUnitFees(e2e.DefaultContext()) + _, unitFees, err := xChainClient.GetUnitFees(e2e.DefaultContext()) require.NoError(err) feeCalc := fees.Calculator{ IsEUpgradeActive: true, diff --git a/vms/avm/block/builder/builder.go b/vms/avm/block/builder/builder.go index af7312983948..c05e8850d9ae 100644 --- a/vms/avm/block/builder/builder.go +++ b/vms/avm/block/builder/builder.go @@ -14,6 +14,7 @@ import ( "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/state" "github.com/ava-labs/avalanchego/vms/avm/txs" "github.com/ava-labs/avalanchego/vms/avm/txs/mempool" @@ -92,8 +93,8 @@ func (b *builder) BuildBlock(context.Context) (snowman.Block, error) { remainingSize = targetBlockSize chainTime = stateDiff.GetTimestamp() - isEForkActive = b.backend.Config.IsEUActivated(chainTime) - feesCfg = b.backend.Config.GetDynamicFeesConfig(chainTime) + isEForkActive = b.backend.Config.IsEActivated(chainTime) + feesCfg = config.GetDynamicFeesConfig(isEForkActive) ) unitFees, err := stateDiff.GetUnitFees() diff --git a/vms/avm/block/executor/block.go b/vms/avm/block/executor/block.go index c26a4af93708..28bdce51213c 100644 --- a/vms/avm/block/executor/block.go +++ b/vms/avm/block/executor/block.go @@ -17,6 +17,7 @@ import ( "github.com/ava-labs/avalanchego/snow/choices" "github.com/ava-labs/avalanchego/snow/consensus/snowman" "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/executor" "github.com/ava-labs/avalanchego/vms/components/fees" @@ -141,8 +142,8 @@ func (b *Block) Verify(context.Context) error { } var ( - isEForkActive = b.manager.backend.Config.IsEUActivated(parentChainTime) - feesCfg = b.manager.backend.Config.GetDynamicFeesConfig(parentChainTime) + isEForkActive = b.manager.backend.Config.IsEActivated(parentChainTime) + feesCfg = config.GetDynamicFeesConfig(isEForkActive) ) feeManager := fees.NewManager(unitFees) diff --git a/vms/avm/block/executor/manager.go b/vms/avm/block/executor/manager.go index e27eccf9a1d0..e004b3d61b2c 100644 --- a/vms/avm/block/executor/manager.go +++ b/vms/avm/block/executor/manager.go @@ -13,6 +13,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" @@ -180,8 +181,8 @@ func (m *manager) VerifyTx(tx *txs.Tx) error { var ( chainTime = stateDiff.GetTimestamp() - isEForkActive = m.backend.Config.IsEUActivated(chainTime) - feesCfg = m.backend.Config.GetDynamicFeesConfig(chainTime) + isEForkActive = m.backend.Config.IsEActivated(chainTime) + feesCfg = config.GetDynamicFeesConfig(isEForkActive) ) feeManager := fees.NewManager(unitFees) diff --git a/vms/avm/client.go b/vms/avm/client.go index b024fd8638c0..1d42112759ad 100644 --- a/vms/avm/client.go +++ b/vms/avm/client.go @@ -76,10 +76,8 @@ type Client interface { // // Deprecated: GetUTXOs should be used instead. GetAllBalances(ctx context.Context, addr ids.ShortID, includePartial bool, options ...rpc.Option) ([]Balance, 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) - // GetFeeWindows returns the fee window needed to calculate next block unit fees - GetFeeWindows(ctx context.Context, options ...rpc.Option) (commonfees.Windows, 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) // CreateAsset creates a new asset and returns its assetID // // Deprecated: Transactions should be issued using the @@ -412,16 +410,10 @@ func (c *client) GetAllBalances( return res.Balances, err } -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, "avm.getUnitFees", struct{}{}, res, options...) - return res.UnitFees, err -} - -func (c *client) GetFeeWindows(ctx context.Context, options ...rpc.Option) (commonfees.Windows, error) { - res := &GetFeeWindowsReply{} - err := c.requester.SendRequest(ctx, "avm.getFeeWindows", struct{}{}, res, options...) - return res.FeeWindows, err + return res.CurrentUnitFees, res.NextUnitFees, err } // ClientHolder describes how much an address owns of an asset diff --git a/vms/avm/config/config.go b/vms/avm/config/config.go index db40903ed1e3..4add91bf286e 100644 --- a/vms/avm/config/config.go +++ b/vms/avm/config/config.go @@ -3,11 +3,7 @@ package config -import ( - "time" - - commonfees "github.com/ava-labs/avalanchego/vms/components/fees" -) +import "time" // Struct collecting all the foundational parameters of the AVM type Config struct { @@ -24,14 +20,6 @@ type Config struct { EUpgradeTime time.Time } -func (c *Config) IsEUActivated(timestamp time.Time) bool { +func (c *Config) IsEActivated(timestamp time.Time) bool { return !timestamp.Before(c.EUpgradeTime) } - -func (c *Config) GetDynamicFeesConfig(timestamp time.Time) commonfees.DynamicFeesConfig { - if !c.IsEUActivated(timestamp) { - return PreEUpgradeDynamicFeesConfig - } - - return EUpgradeDynamicFeesConfig -} diff --git a/vms/avm/config/dynamic_fees_config.go b/vms/avm/config/dynamic_fees_config.go index 32ed6511ee52..d6effc23c740 100644 --- a/vms/avm/config/dynamic_fees_config.go +++ b/vms/avm/config/dynamic_fees_config.go @@ -17,14 +17,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 = commonfees.DynamicFeesConfig{ + eUpgradeDynamicFeesConfig = commonfees.DynamicFeesConfig{ InitialUnitFees: commonfees.Dimensions{ 1 * units.NanoAvax, 2 * units.NanoAvax, @@ -42,9 +42,16 @@ var ( BlockUnitsTarget: commonfees.Dimensions{1, 1, 1, 1}, } - // TODO ABENEGIA: decide if and how to validate PreEUpgradeDynamicFeesConfig - PreEUpgradeDynamicFeesConfig = commonfees.DynamicFeesConfig{ + // TODO ABENEGIA: decide if and how to validate preEUpgradeDynamicFeesConfig + preEUpgradeDynamicFeesConfig = commonfees.DynamicFeesConfig{ InitialUnitFees: commonfees.Empty, BlockUnitsCap: commonfees.Max, } ) + +func GetDynamicFeesConfig(isEActive bool) commonfees.DynamicFeesConfig { + if !isEActive { + return preEUpgradeDynamicFeesConfig + } + return eUpgradeDynamicFeesConfig +} diff --git a/vms/avm/service.go b/vms/avm/service.go index 568faa0f3235..7936a38a6e3b 100644 --- a/vms/avm/service.go +++ b/vms/avm/service.go @@ -21,6 +21,8 @@ import ( "github.com/ava-labs/avalanchego/utils/formatting" "github.com/ava-labs/avalanchego/utils/logging" "github.com/ava-labs/avalanchego/utils/set" + "github.com/ava-labs/avalanchego/vms/avm/block/executor" + "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/keystore" @@ -676,23 +678,62 @@ func (s *Service) GetAllBalances(_ *http.Request, args *GetAllBalancesArgs, repl // 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. func (s *Service) GetUnitFees(_ *http.Request, _ *struct{}, reply *GetUnitFeesReply) error { s.vm.ctx.Log.Debug("API called", - zap.String("service", "avm"), + zap.String("service", "platform"), zap.String("method", "getUnitFees"), ) 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.chainManager.Preferred() + onAccept, ok := s.vm.chainManager.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 := executor.NextBlockTime(onAccept.GetTimestamp(), &s.vm.clock) + 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) + if isEActivated { + feeManager.UpdateUnitFees( + feesCfg, + feeWindows, + currentTimestamp.Unix(), + nextTimestamp.Unix(), + ) + } + reply.NextUnitFees = feeManager.GetUnitFees() + + return nil } // GetBlockUnitsCapReply is the response from GetBlockUnitsCap diff --git a/vms/avm/service_test.go b/vms/avm/service_test.go index 0b428fec7208..6fc5c5a1ec40 100644 --- a/vms/avm/service_test.go +++ b/vms/avm/service_test.go @@ -2669,7 +2669,8 @@ func TestNFTWorkflow(t *testing.T) { require.Len(txs, 1) createAssetTx := txs[0] - feesCfg := env.vm.Config.GetDynamicFeesConfig(env.vm.state.GetTimestamp()) + isEActivated := env.vm.Config.IsEActivated(env.vm.state.GetTimestamp()) + feesCfg := config.GetDynamicFeesConfig(isEActivated) feeCalc := &fees.Calculator{ IsEUpgradeActive: true, Config: &env.vm.Config, diff --git a/vms/avm/state/state.go b/vms/avm/state/state.go index ee436df2ddad..e4128b83d358 100644 --- a/vms/avm/state/state.go +++ b/vms/avm/state/state.go @@ -374,7 +374,8 @@ func (s *state) InitFees() 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 - feeCfg := s.cfg.GetDynamicFeesConfig(s.GetTimestamp()) + isEActivated := s.cfg.IsEActivated(s.GetTimestamp()) + feeCfg := config.GetDynamicFeesConfig(isEActivated) s.unitFees = feeCfg.InitialUnitFees default: diff --git a/vms/avm/tx.go b/vms/avm/tx.go index 935847f07c93..9f7f55f4745c 100644 --- a/vms/avm/tx.go +++ b/vms/avm/tx.go @@ -15,6 +15,7 @@ import ( "github.com/ava-labs/avalanchego/snow/choices" "github.com/ava-labs/avalanchego/snow/consensus/snowstorm" "github.com/ava-labs/avalanchego/utils/set" + "github.com/ava-labs/avalanchego/vms/avm/config" "github.com/ava-labs/avalanchego/vms/avm/txs" "github.com/ava-labs/avalanchego/vms/avm/txs/executor" "github.com/ava-labs/avalanchego/vms/components/fees" @@ -133,8 +134,9 @@ func (tx *Tx) Verify(context.Context) error { } var ( - feeCfg = tx.vm.txExecutorBackend.Config.GetDynamicFeesConfig(tx.vm.state.GetTimestamp()) - feeManager = fees.NewManager(unitFees) + isEActivated = tx.vm.txExecutorBackend.Config.IsEActivated(tx.vm.state.GetTimestamp()) + feeCfg = config.GetDynamicFeesConfig(isEActivated) + feeManager = fees.NewManager(unitFees) ) return tx.tx.Unsigned.Visit(&executor.SemanticVerifier{ Backend: tx.vm.txExecutorBackend, diff --git a/vms/avm/tx_builders.go b/vms/avm/tx_builders.go index bdf475ea6e21..e916c5db4b26 100644 --- a/vms/avm/tx_builders.go +++ b/vms/avm/tx_builders.go @@ -50,10 +50,11 @@ func buildCreateAssetTx( pBuilder, pSigner = builders(backend, kc) chainTime = backend.State().GetTimestamp() cfg = backend.Config() - feeCfg = cfg.GetDynamicFeesConfig(chainTime) + isEUpgradeActive = cfg.IsEActivated(chainTime) + feeCfg = config.GetDynamicFeesConfig(isEUpgradeActive) feeMan = commonfees.NewManager(unitFees) feeCalc = &fees.Calculator{ - IsEUpgradeActive: cfg.IsEUActivated(chainTime), + IsEUpgradeActive: isEUpgradeActive, Config: cfg, FeeManager: feeMan, ConsumedUnitsCap: feeCfg.BlockUnitsCap, @@ -97,10 +98,11 @@ func buildBaseTx( pBuilder, pSigner = builders(backend, kc) chainTime = backend.State().GetTimestamp() cfg = backend.Config() - feeCfg = cfg.GetDynamicFeesConfig(chainTime) + isEUpgradeActive = cfg.IsEActivated(chainTime) + feeCfg = config.GetDynamicFeesConfig(isEUpgradeActive) feeMan = commonfees.NewManager(unitFees) feeCalc = &fees.Calculator{ - IsEUpgradeActive: cfg.IsEUActivated(chainTime), + IsEUpgradeActive: isEUpgradeActive, Config: cfg, FeeManager: feeMan, ConsumedUnitsCap: feeCfg.BlockUnitsCap, @@ -142,10 +144,11 @@ func mintNFT( pBuilder, pSigner = builders(backend, kc) chainTime = backend.State().GetTimestamp() cfg = backend.Config() - feeCfg = cfg.GetDynamicFeesConfig(chainTime) + isEUpgradeActive = cfg.IsEActivated(chainTime) + feeCfg = config.GetDynamicFeesConfig(isEUpgradeActive) feeMan = commonfees.NewManager(unitFees) feeCalc = &fees.Calculator{ - IsEUpgradeActive: cfg.IsEUActivated(chainTime), + IsEUpgradeActive: isEUpgradeActive, Config: cfg, FeeManager: feeMan, ConsumedUnitsCap: feeCfg.BlockUnitsCap, @@ -182,10 +185,11 @@ func mintFTs( pBuilder, pSigner = builders(backend, kc) chainTime = backend.State().GetTimestamp() cfg = backend.Config() - feeCfg = cfg.GetDynamicFeesConfig(chainTime) + isEUpgradeActive = cfg.IsEActivated(chainTime) + feeCfg = config.GetDynamicFeesConfig(isEUpgradeActive) feeMan = commonfees.NewManager(unitFees) feeCalc = &fees.Calculator{ - IsEUpgradeActive: cfg.IsEUActivated(chainTime), + IsEUpgradeActive: isEUpgradeActive, Config: cfg, FeeManager: feeMan, ConsumedUnitsCap: feeCfg.BlockUnitsCap, @@ -219,10 +223,11 @@ func buildOperation( pBuilder, pSigner = builders(backend, kc) chainTime = backend.State().GetTimestamp() cfg = backend.Config() - feeCfg = cfg.GetDynamicFeesConfig(chainTime) + isEUpgradeActive = cfg.IsEActivated(chainTime) + feeCfg = config.GetDynamicFeesConfig(isEUpgradeActive) feeMan = commonfees.NewManager(unitFees) feeCalc = &fees.Calculator{ - IsEUpgradeActive: cfg.IsEUActivated(chainTime), + IsEUpgradeActive: isEUpgradeActive, Config: cfg, FeeManager: feeMan, ConsumedUnitsCap: feeCfg.BlockUnitsCap, @@ -257,10 +262,11 @@ func buildImportTx( pBuilder, pSigner = builders(backend, kc) chainTime = backend.State().GetTimestamp() cfg = backend.Config() - feeCfg = cfg.GetDynamicFeesConfig(chainTime) + isEUpgradeActive = cfg.IsEActivated(chainTime) + feeCfg = config.GetDynamicFeesConfig(isEUpgradeActive) feeMan = commonfees.NewManager(unitFees) feeCalc = &fees.Calculator{ - IsEUpgradeActive: cfg.IsEUActivated(chainTime), + IsEUpgradeActive: isEUpgradeActive, Config: cfg, FeeManager: feeMan, ConsumedUnitsCap: feeCfg.BlockUnitsCap, @@ -304,10 +310,11 @@ func buildExportTx( pBuilder, pSigner = builders(backend, kc) chainTime = backend.State().GetTimestamp() cfg = backend.Config() - feeCfg = cfg.GetDynamicFeesConfig(chainTime) + isEUpgradeActive = cfg.IsEActivated(chainTime) + feeCfg = config.GetDynamicFeesConfig(isEUpgradeActive) feeMan = commonfees.NewManager(unitFees) feeCalc = &fees.Calculator{ - IsEUpgradeActive: cfg.IsEUActivated(chainTime), + IsEUpgradeActive: isEUpgradeActive, Config: cfg, FeeManager: feeMan, ConsumedUnitsCap: feeCfg.BlockUnitsCap, diff --git a/vms/avm/txs/executor/semantic_verifier.go b/vms/avm/txs/executor/semantic_verifier.go index ddc0d6cd5563..ecfb35f04194 100644 --- a/vms/avm/txs/executor/semantic_verifier.go +++ b/vms/avm/txs/executor/semantic_verifier.go @@ -138,7 +138,7 @@ func (v *SemanticVerifier) verifyBaseTx( creds []*fxs.FxCredential, ) error { feeCalculator := fees.Calculator{ - IsEUpgradeActive: v.Config.IsEUActivated(v.State.GetTimestamp()), + IsEUpgradeActive: v.Config.IsEActivated(v.State.GetTimestamp()), Config: v.Config, FeeManager: v.BlkFeeManager, ConsumedUnitsCap: v.UnitCaps, diff --git a/vms/avm/txs/executor/semantic_verifier_test.go b/vms/avm/txs/executor/semantic_verifier_test.go index 3c0793c53969..85975be56641 100644 --- a/vms/avm/txs/executor/semantic_verifier_test.go +++ b/vms/avm/txs/executor/semantic_verifier_test.go @@ -740,7 +740,7 @@ func TestSemanticVerifierBaseTx(t *testing.T) { state := test.stateFunc(ctrl) tx := test.txFunc(require) - feeCfg := config.EUpgradeDynamicFeesConfig + feeCfg := config.GetDynamicFeesConfig(true /*isEActive*/) err = tx.Unsigned.Visit(&SemanticVerifier{ Backend: backend, @@ -1494,7 +1494,7 @@ func TestSemanticVerifierExportTx(t *testing.T) { state := test.stateFunc(ctrl) tx := test.txFunc(require) - feeCfg := config.EUpgradeDynamicFeesConfig + feeCfg := config.GetDynamicFeesConfig(true /*isEActive*/) err = tx.Unsigned.Visit(&SemanticVerifier{ Backend: backend, @@ -1639,7 +1639,7 @@ func TestSemanticVerifierExportTxDifferentSubnet(t *testing.T) { }, )) - feeCfg := config.EUpgradeDynamicFeesConfig + feeCfg := config.GetDynamicFeesConfig(true /*isEActive*/) err = tx.Unsigned.Visit(&SemanticVerifier{ Backend: backend, @@ -2177,7 +2177,7 @@ func TestSemanticVerifierImportTx(t *testing.T) { state := test.stateFunc(ctrl) tx := test.txFunc(require) - feeCfg := config.EUpgradeDynamicFeesConfig + feeCfg := config.GetDynamicFeesConfig(true /*isEActive*/) err = tx.Unsigned.Visit(&SemanticVerifier{ Backend: backend, diff --git a/vms/avm/txs/fees/calculator_test.go b/vms/avm/txs/fees/calculator_test.go index 4903a01edec2..8495078064d7 100644 --- a/vms/avm/txs/fees/calculator_test.go +++ b/vms/avm/txs/fees/calculator_test.go @@ -150,7 +150,7 @@ func TestBaseTxFees(t *testing.T) { } fc := &Calculator{ - IsEUpgradeActive: cfg.IsEUActivated(chainTime), + IsEUpgradeActive: cfg.IsEActivated(chainTime), Config: cfg, Codec: codec, FeeManager: fees.NewManager(testUnitFees), @@ -271,7 +271,7 @@ func TestCreateAssetTxFees(t *testing.T) { } fc := &Calculator{ - IsEUpgradeActive: cfg.IsEUActivated(chainTime), + IsEUpgradeActive: cfg.IsEActivated(chainTime), Config: cfg, Codec: codec, FeeManager: fees.NewManager(testUnitFees), @@ -392,7 +392,7 @@ func TestOperationTxFees(t *testing.T) { } fc := &Calculator{ - IsEUpgradeActive: cfg.IsEUActivated(chainTime), + IsEUpgradeActive: cfg.IsEActivated(chainTime), Config: cfg, Codec: codec, FeeManager: fees.NewManager(testUnitFees), @@ -509,7 +509,7 @@ func TestImportTxFees(t *testing.T) { } fc := &Calculator{ - IsEUpgradeActive: cfg.IsEUActivated(chainTime), + IsEUpgradeActive: cfg.IsEActivated(chainTime), Config: cfg, Codec: codec, FeeManager: fees.NewManager(testUnitFees), @@ -616,7 +616,7 @@ func TestExportTxFees(t *testing.T) { } fc := &Calculator{ - IsEUpgradeActive: cfg.IsEUActivated(chainTime), + IsEUpgradeActive: cfg.IsEActivated(chainTime), Config: cfg, Codec: codec, FeeManager: fees.NewManager(testUnitFees), diff --git a/wallet/chain/x/wallet.go b/wallet/chain/x/wallet.go index fec43228b233..b7729588f8f9 100644 --- a/wallet/chain/x/wallet.go +++ b/wallet/chain/x/wallet.go @@ -505,7 +505,7 @@ func (w *wallet) refreshFork(options ...common.Option) error { err error ) - w.unitFees, err = w.client.GetUnitFees(ctx) + _, w.unitFees, err = w.client.GetUnitFees(ctx) if err != nil { return err } @@ -519,12 +519,6 @@ func (w *wallet) refreshFork(options ...common.Option) error { // } chainTime := mockable.MaxTime // assume fork is already active w.isEForkActive = !chainTime.Before(eUpgradeTime) - - if w.isEForkActive { - w.unitCaps = config.EUpgradeDynamicFeesConfig.BlockUnitsCap - } else { - w.unitCaps = config.PreEUpgradeDynamicFeesConfig.BlockUnitsCap - } - + w.unitCaps = config.GetDynamicFeesConfig(w.isEForkActive).BlockUnitsCap return nil } From 26c75bd405ad6368c98d4365c4d4b53ff073e53a Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 18 Mar 2024 10:55:52 +0100 Subject: [PATCH 117/132] fixed fee update calls --- vms/avm/block/builder/builder.go | 13 +- vms/avm/block/executor/block.go | 6 + vms/avm/block/executor/manager.go | 6 +- vms/avm/index_test.go | 4 +- vms/avm/service_test.go | 240 +++--------------------------- vms/avm/vm_regression_test.go | 2 +- 6 files changed, 36 insertions(+), 235 deletions(-) diff --git a/vms/avm/block/builder/builder.go b/vms/avm/block/builder/builder.go index c05e8850d9ae..cbc148d1db3f 100644 --- a/vms/avm/block/builder/builder.go +++ b/vms/avm/block/builder/builder.go @@ -79,8 +79,8 @@ func (b *builder) BuildBlock(context.Context) (snowman.Block, error) { preferredHeight := preferred.Height() nextHeight := preferredHeight + 1 - preferredTimestamp := preferred.Timestamp() - nextTimestamp := blockexecutor.NextBlockTime(preferredTimestamp, b.clk) + parentBlkTime := preferred.Timestamp() + nextBlkTime := blockexecutor.NextBlockTime(parentBlkTime, b.clk) stateDiff, err := state.NewDiff(preferredID, b.manager) if err != nil { @@ -92,8 +92,7 @@ func (b *builder) BuildBlock(context.Context) (snowman.Block, error) { inputs set.Set[ids.ID] remainingSize = targetBlockSize - chainTime = stateDiff.GetTimestamp() - isEForkActive = b.backend.Config.IsEActivated(chainTime) + isEForkActive = b.backend.Config.IsEActivated(nextBlkTime) feesCfg = config.GetDynamicFeesConfig(isEForkActive) ) @@ -111,8 +110,8 @@ func (b *builder) BuildBlock(context.Context) (snowman.Block, error) { feeManager.UpdateUnitFees( feesCfg, feeWindows, - chainTime.Unix(), - nextTimestamp.Unix(), + parentBlkTime.Unix(), + nextBlkTime.Unix(), ) } @@ -195,7 +194,7 @@ func (b *builder) BuildBlock(context.Context) (snowman.Block, error) { statelessBlk, err := block.NewStandardBlock( preferredID, nextHeight, - nextTimestamp, + nextBlkTime, blockTxs, b.backend.Codec, ) diff --git a/vms/avm/block/executor/block.go b/vms/avm/block/executor/block.go index 28bdce51213c..bb0a8d993847 100644 --- a/vms/avm/block/executor/block.go +++ b/vms/avm/block/executor/block.go @@ -224,6 +224,12 @@ func (b *Block) Verify(context.Context) error { // Now that the block has been executed, we can add the block data to the // state diff. + if isEForkActive { + feeManager.UpdateWindows(&feeWindows, parentChainTime.Unix(), newChainTime.Unix()) + stateDiff.SetUnitFees(feeManager.GetUnitFees()) + stateDiff.SetFeeWindows(feeWindows) + } + stateDiff.SetLastAccepted(blkID) stateDiff.AddBlock(b.Block) diff --git a/vms/avm/block/executor/manager.go b/vms/avm/block/executor/manager.go index e004b3d61b2c..f3556b8ea05f 100644 --- a/vms/avm/block/executor/manager.go +++ b/vms/avm/block/executor/manager.go @@ -163,6 +163,7 @@ func (m *manager) VerifyTx(tx *txs.Tx) error { if err != nil { return err } + parentBlkTime := preferred.Timestamp() nextBlkTime := NextBlockTime(preferred.Timestamp(), m.clk) stateDiff, err := state.NewDiff(m.lastAccepted, m) @@ -180,8 +181,7 @@ func (m *manager) VerifyTx(tx *txs.Tx) error { } var ( - chainTime = stateDiff.GetTimestamp() - isEForkActive = m.backend.Config.IsEActivated(chainTime) + isEForkActive = m.backend.Config.IsEActivated(nextBlkTime) feesCfg = config.GetDynamicFeesConfig(isEForkActive) ) @@ -190,7 +190,7 @@ func (m *manager) VerifyTx(tx *txs.Tx) error { feeManager.UpdateUnitFees( feesCfg, feeWindows, - chainTime.Unix(), + parentBlkTime.Unix(), nextBlkTime.Unix(), ) } diff --git a/vms/avm/index_test.go b/vms/avm/index_test.go index 43749cce2c91..80d7329258e5 100644 --- a/vms/avm/index_test.go +++ b/vms/avm/index_test.go @@ -28,7 +28,7 @@ import ( func TestIndexTransaction_Ordered(t *testing.T) { require := require.New(t) - env := setup(t, &envConfig{fork: eUpgrade}) + env := setup(t, &envConfig{fork: durango}) defer func() { require.NoError(env.vm.Shutdown(context.Background())) env.vm.ctx.Lock.Unlock() @@ -70,7 +70,7 @@ func TestIndexTransaction_Ordered(t *testing.T) { func TestIndexTransaction_MultipleTransactions(t *testing.T) { require := require.New(t) - env := setup(t, &envConfig{fork: eUpgrade}) + env := setup(t, &envConfig{fork: durango}) defer func() { require.NoError(env.vm.Shutdown(context.Background())) env.vm.ctx.Lock.Unlock() diff --git a/vms/avm/service_test.go b/vms/avm/service_test.go index 6fc5c5a1ec40..f691deb6b633 100644 --- a/vms/avm/service_test.go +++ b/vms/avm/service_test.go @@ -978,34 +978,8 @@ func TestServiceGetTxJSON_OperationTxWithNftxMintOp(t *testing.T) { "unsignedTx": { "networkID": 10, "blockchainID": "PLACEHOLDER_BLOCKCHAIN_ID", - "outputs": [ - { - "assetID": "tvLKci3hNoCX4NijS6TfiT6XJJY3gGKd2git6SSVTG5J8Nfby", - "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", - "output": { - "addresses": [ - "X-testing1lnk637g0edwnqc2tn8tel39652fswa3xk4r65e" - ], - "amount": 999989755, - "locktime": 0, - "threshold": 1 - } - } - ], - "inputs": [ - { - "txID": "fmwdbeEvaoZxqQ1CffQbABeKwLhKjHJyY2k7cFhDjmuAX6yCn", - "outputIndex": 0, - "assetID": "tvLKci3hNoCX4NijS6TfiT6XJJY3gGKd2git6SSVTG5J8Nfby", - "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", - "input": { - "amount": 999994889, - "signatureIndices": [ - 0 - ] - } - } - ], + "outputs": null, + "inputs": null, "memo": "0x", "operations": [ { @@ -1039,19 +1013,11 @@ func TestServiceGetTxJSON_OperationTxWithNftxMintOp(t *testing.T) { ] }, "credentials": [ - { - "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", - "credential": { - "signatures": [ - "0xda85a73a3981e5a53c097a1c41ca9900f623b150af4dc745175cecf80ee007a3232f107a76c1b68996c6c9a319036495ec7763fc17dca030d34a43e6e465ccf701" - ] - } - }, { "fxID": "qd2U4HDWUvMrVUeTcCHp6xH3Qpnn1XbU5MDdnBoiifFqvgXwT", "credential": { "signatures": [ - "0xda85a73a3981e5a53c097a1c41ca9900f623b150af4dc745175cecf80ee007a3232f107a76c1b68996c6c9a319036495ec7763fc17dca030d34a43e6e465ccf701" + "0x4c862cf04a2df68cfd1451568d7c08e8015c72c968bbd31f9764397ddef2046e6d1fab7593cc001900807a15a9f481cfcfd116adbf612a9b194332fec361f23e01" ] } } @@ -1063,7 +1029,7 @@ func TestServiceGetTxJSON_OperationTxWithNftxMintOp(t *testing.T) { expectedReplyTxString = strings.Replace(expectedReplyTxString, "PLACEHOLDER_TX_ID", mintNFTTx.ID().String(), 1) expectedReplyTxString = strings.Replace(expectedReplyTxString, "PLACEHOLDER_BLOCKCHAIN_ID", mintNFTTx.Unsigned.(*txs.OperationTx).BlockchainID.String(), 1) - sigStr, err := formatting.Encode(formatting.HexNC, mintNFTTx.Creds[1].Credential.(*nftfx.Credential).Sigs[0][:]) + sigStr, err := formatting.Encode(formatting.HexNC, mintNFTTx.Creds[0].Credential.(*nftfx.Credential).Sigs[0][:]) require.NoError(err) expectedReplyTxString = strings.Replace(expectedReplyTxString, "PLACEHOLDER_SIGNATURE", sigStr, 1) @@ -1132,34 +1098,8 @@ func TestServiceGetTxJSON_OperationTxWithMultipleNftxMintOp(t *testing.T) { "unsignedTx": { "networkID": 10, "blockchainID": "PLACEHOLDER_BLOCKCHAIN_ID", - "outputs": [ - { - "assetID": "tvLKci3hNoCX4NijS6TfiT6XJJY3gGKd2git6SSVTG5J8Nfby", - "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", - "output": { - "addresses": [ - "X-testing1lnk637g0edwnqc2tn8tel39652fswa3xk4r65e" - ], - "amount": 999989610, - "locktime": 0, - "threshold": 1 - } - } - ], - "inputs": [ - { - "txID": "242j2DppY6ivQ9VRpK7K34pFTwvLdDJ8qoR3dKNDuL1299A1tD", - "outputIndex": 0, - "assetID": "tvLKci3hNoCX4NijS6TfiT6XJJY3gGKd2git6SSVTG5J8Nfby", - "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", - "input": { - "amount": 999994881, - "signatureIndices": [ - 0 - ] - } - } - ], + "outputs": null, + "inputs": null, "memo": "0x", "operations": [ { @@ -1221,19 +1161,11 @@ func TestServiceGetTxJSON_OperationTxWithMultipleNftxMintOp(t *testing.T) { ] }, "credentials": [ - { - "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", - "credential": { - "signatures": [ - "PLACEHOLDER_SIGNATURE" - ] - } - }, { "fxID": "qd2U4HDWUvMrVUeTcCHp6xH3Qpnn1XbU5MDdnBoiifFqvgXwT", "credential": { "signatures": [ - "0x7ffa7f3e7e7fd567ca888932fc5f7d3946a168f5b7fe0f03fcc1cece66ef046c15e7e3524b51d38fd6c8aecc7800bd01e8ca122228e513728047ced3f5a18cba00" + "0xb8fe75ee309edda8d03cb6d890774b98a7171ec18da22894c7d760fc66a0d9392aac513bbc2fbddea9702001dbceaf1cd505a0b3b2b25770471ec0590f5fd24701" ] } }, @@ -1316,34 +1248,8 @@ func TestServiceGetTxJSON_OperationTxWithSecpMintOp(t *testing.T) { "unsignedTx": { "networkID": 10, "blockchainID": "PLACEHOLDER_BLOCKCHAIN_ID", - "outputs": [ - { - "assetID": "tvLKci3hNoCX4NijS6TfiT6XJJY3gGKd2git6SSVTG5J8Nfby", - "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", - "output": { - "addresses": [ - "X-testing1lnk637g0edwnqc2tn8tel39652fswa3xk4r65e" - ], - "amount": 999989732, - "locktime": 0, - "threshold": 1 - } - } - ], - "inputs": [ - { - "txID": "2V6JT8iKGj8e8kquziCiJnhq4EbfZpSoy64WTpSPwVoTJN1Nzy", - "outputIndex": 0, - "assetID": "tvLKci3hNoCX4NijS6TfiT6XJJY3gGKd2git6SSVTG5J8Nfby", - "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", - "input": { - "amount": 999994893, - "signatureIndices": [ - 0 - ] - } - } - ], + "outputs": null, + "inputs": null, "memo": "0x", "operations": [ { @@ -1385,15 +1291,7 @@ func TestServiceGetTxJSON_OperationTxWithSecpMintOp(t *testing.T) { "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", "credential": { "signatures": [ - "PLACEHOLDER_SIGNATURE" - ] - } - }, - { - "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", - "credential": { - "signatures": [ - "0x06f4963b62555034c66f5ebd8a654effc9a0a1fce3b13b227e2d71c99fa3630c554ce94754c25cd2e2a16e2c1c09fc9234c902dbf3a7816bfebcf7fb8181baf801" + "0x0be6194c911b5836960ac3c79ed0e1243a1df47913dde4d473ee228daf224b8a310a9b12fb42ecac2406699d75ee86d7046525be79c9f747a4d8ac4b0591300700" ] } } @@ -1472,34 +1370,8 @@ func TestServiceGetTxJSON_OperationTxWithMultipleSecpMintOp(t *testing.T) { "unsignedTx": { "networkID": 10, "blockchainID": "PLACEHOLDER_BLOCKCHAIN_ID", - "outputs": [ - { - "assetID": "tvLKci3hNoCX4NijS6TfiT6XJJY3gGKd2git6SSVTG5J8Nfby", - "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", - "output": { - "addresses": [ - "X-testing1lnk637g0edwnqc2tn8tel39652fswa3xk4r65e" - ], - "amount": 999989564, - "locktime": 0, - "threshold": 1 - } - } - ], - "inputs": [ - { - "txID": "27K46oMaq92J3EbkLxzhqqNAvYyMbHQE5AmbjHa5GGZ6uQ9oqW", - "outputIndex": 0, - "assetID": "tvLKci3hNoCX4NijS6TfiT6XJJY3gGKd2git6SSVTG5J8Nfby", - "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", - "input": { - "amount": 999994889, - "signatureIndices": [ - 0 - ] - } - } - ], + "outputs": null, + "inputs": null, "memo": "0x", "operations": [ { @@ -1581,15 +1453,7 @@ func TestServiceGetTxJSON_OperationTxWithMultipleSecpMintOp(t *testing.T) { "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", "credential": { "signatures": [ - "PLACEHOLDER_SIGNATURE" - ] - } - }, - { - "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", - "credential": { - "signatures": [ - "0x31826158f0f5db02d7ebde9ae2726cfbc5b59693065bce80448f089a31e83d2477cc193ed74e870c643668024a177acf862ba537c46e22c4ef8ed8332f05618401" + "0x4e6eb93c7a744c1c550140b115edf7490a9d94a122c9b7cfaed1dfa75b5da3142637d113d85e6a1cbfd0b383f1b604e74b72422207c4631bb2b78f929632df0c00" ] } } @@ -1659,34 +1523,8 @@ func TestServiceGetTxJSON_OperationTxWithPropertyFxMintOp(t *testing.T) { "unsignedTx": { "networkID": 10, "blockchainID": "PLACEHOLDER_BLOCKCHAIN_ID", - "outputs": [ - { - "assetID": "tvLKci3hNoCX4NijS6TfiT6XJJY3gGKd2git6SSVTG5J8Nfby", - "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", - "output": { - "addresses": [ - "X-testing1lnk637g0edwnqc2tn8tel39652fswa3xk4r65e" - ], - "amount": 999989804, - "locktime": 0, - "threshold": 1 - } - } - ], - "inputs": [ - { - "txID": "2AkCR4agFVbDqhBsmEtdNMW3P4v18v6UqKAJqEounv5ayyKec3", - "outputIndex": 0, - "assetID": "tvLKci3hNoCX4NijS6TfiT6XJJY3gGKd2git6SSVTG5J8Nfby", - "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", - "input": { - "amount": 999994937, - "signatureIndices": [ - 0 - ] - } - } - ], + "outputs": null, + "inputs": null, "memo": "0x", "operations": [ { @@ -1721,14 +1559,6 @@ func TestServiceGetTxJSON_OperationTxWithPropertyFxMintOp(t *testing.T) { ] }, "credentials": [ - { - "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", - "credential": { - "signatures": [ - "0x772626548a885e46e556288f8dfb70b7ba0d160fa43c1b4995649a000deb73a063da7f5162f2379a7aedf192c55069782b0f712523cdaf0bfef6509b71c46f5b00" - ] - } - }, { "fxID": "rXJsCSEYXg2TehWxCEEGj6JU2PWKTkd6cBdNLjoe2SpsKD9cy", "credential": { @@ -1745,7 +1575,7 @@ func TestServiceGetTxJSON_OperationTxWithPropertyFxMintOp(t *testing.T) { expectedReplyTxString = strings.Replace(expectedReplyTxString, "PLACEHOLDER_TX_ID", mintPropertyFxOpTx.ID().String(), 1) expectedReplyTxString = strings.Replace(expectedReplyTxString, "PLACEHOLDER_BLOCKCHAIN_ID", mintPropertyFxOpTx.Unsigned.(*txs.OperationTx).BlockchainID.String(), 1) - sigStr, err := formatting.Encode(formatting.HexNC, mintPropertyFxOpTx.Creds[1].Credential.(*propertyfx.Credential).Sigs[0][:]) + sigStr, err := formatting.Encode(formatting.HexNC, mintPropertyFxOpTx.Creds[0].Credential.(*propertyfx.Credential).Sigs[0][:]) require.NoError(err) expectedReplyTxString = strings.Replace(expectedReplyTxString, "PLACEHOLDER_SIGNATURE", sigStr, 1) @@ -1810,34 +1640,8 @@ func TestServiceGetTxJSON_OperationTxWithPropertyFxMintOpMultiple(t *testing.T) "unsignedTx": { "networkID": 10, "blockchainID": "PLACEHOLDER_BLOCKCHAIN_ID", - "outputs": [ - { - "assetID": "tvLKci3hNoCX4NijS6TfiT6XJJY3gGKd2git6SSVTG5J8Nfby", - "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", - "output": { - "addresses": [ - "X-testing1lnk637g0edwnqc2tn8tel39652fswa3xk4r65e" - ], - "amount": 999989628, - "locktime": 0, - "threshold": 1 - } - } - ], - "inputs": [ - { - "txID": "uxCyRqRgK1MtyxLVw2m4Axti2fZAub8m9d5BJzySpEKX3t39b", - "outputIndex": 0, - "assetID": "tvLKci3hNoCX4NijS6TfiT6XJJY3gGKd2git6SSVTG5J8Nfby", - "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", - "input": { - "amount": 999994897, - "signatureIndices": [ - 0 - ] - } - } - ], + "outputs": null, + "inputs": null, "memo": "0x", "operations": [ { @@ -1901,14 +1705,6 @@ func TestServiceGetTxJSON_OperationTxWithPropertyFxMintOpMultiple(t *testing.T) ] }, "credentials": [ - { - "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", - "credential": { - "signatures": [ - "0x7631837d04fabb247fe13d492bc950890ea5b1617a60d4700c07f199fd66899d05aed813f02bbab55ac50ec0d24a1de8fcafa224b91d8049e9f77d15114ad9e501" - ] - } - }, { "fxID": "rXJsCSEYXg2TehWxCEEGj6JU2PWKTkd6cBdNLjoe2SpsKD9cy", "credential": { diff --git a/vms/avm/vm_regression_test.go b/vms/avm/vm_regression_test.go index db58d0039ab3..473af93355e6 100644 --- a/vms/avm/vm_regression_test.go +++ b/vms/avm/vm_regression_test.go @@ -19,7 +19,7 @@ import ( func TestVerifyFxUsage(t *testing.T) { require := require.New(t) - env := setup(t, &envConfig{fork: eUpgrade}) + env := setup(t, &envConfig{fork: durango}) env.vm.ctx.Lock.Unlock() defer func() { env.vm.ctx.Lock.Lock() From b627cd22bc9ec07e504e38215011a83a1d5a66ae Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 18 Mar 2024 11:07:19 +0100 Subject: [PATCH 118/132] added dynamic fees custom config --- vms/avm/config.go | 4 + vms/avm/config/dynamic_fees_config.go | 20 +++ vms/avm/environment_test.go | 25 +++ vms/avm/index_test.go | 4 +- vms/avm/service_test.go | 248 +++++++++++++++++++++++--- vms/avm/vm.go | 3 + vms/avm/vm_regression_test.go | 2 +- vms/avm/vm_test.go | 6 +- 8 files changed, 284 insertions(+), 28 deletions(-) diff --git a/vms/avm/config.go b/vms/avm/config.go index f7661bbefd18..1c4be12fd03e 100644 --- a/vms/avm/config.go +++ b/vms/avm/config.go @@ -7,6 +7,8 @@ import ( "encoding/json" "github.com/ava-labs/avalanchego/vms/avm/network" + + commonfees "github.com/ava-labs/avalanchego/vms/components/fees" ) var DefaultConfig = Config{ @@ -21,6 +23,8 @@ type Config struct { IndexTransactions bool `json:"index-transactions"` IndexAllowIncomplete bool `json:"index-allow-incomplete"` ChecksumsEnabled bool `json:"checksums-enabled"` + + DynamicFeesConfig *commonfees.DynamicFeesConfig `json:"dynamic-fees-config"` } func ParseConfig(configBytes []byte) (Config, error) { diff --git a/vms/avm/config/dynamic_fees_config.go b/vms/avm/config/dynamic_fees_config.go index d6effc23c740..aed273ad9aec 100644 --- a/vms/avm/config/dynamic_fees_config.go +++ b/vms/avm/config/dynamic_fees_config.go @@ -4,6 +4,10 @@ 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" @@ -47,11 +51,27 @@ var ( InitialUnitFees: commonfees.Empty, BlockUnitsCap: commonfees.Max, } + + customDynamicFeesConfig *commonfees.DynamicFeesConfig ) func GetDynamicFeesConfig(isEActive bool) commonfees.DynamicFeesConfig { if !isEActive { return preEUpgradeDynamicFeesConfig } + if customDynamicFeesConfig != nil { + return *customDynamicFeesConfig + } return eUpgradeDynamicFeesConfig } + +func ResetDynamicFeesConfig(ctx *snow.Context, customFeesConfig *commonfees.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 +} diff --git a/vms/avm/environment_test.go b/vms/avm/environment_test.go index 14c657ef0947..071d66840c13 100644 --- a/vms/avm/environment_test.go +++ b/vms/avm/environment_test.go @@ -38,6 +38,7 @@ import ( "github.com/ava-labs/avalanchego/vms/secp256k1fx" avajson "github.com/ava-labs/avalanchego/utils/json" + commonfees "github.com/ava-labs/avalanchego/vms/components/fees" keystoreutils "github.com/ava-labs/avalanchego/vms/components/keystore" ) @@ -78,6 +79,29 @@ var ( keys = secp256k1.TestKeys()[:3] // TODO: Remove [:3] addrs []ids.ShortID // addrs[i] corresponds to keys[i] + + testFeesCfg = commonfees.DynamicFeesConfig{ + InitialUnitFees: commonfees.Dimensions{ + 5 * units.NanoAvax, + 5 * units.NanoAvax, + 5 * units.NanoAvax, + 5 * units.NanoAvax, + }, + MinUnitFees: commonfees.Dimensions{ + 1 * units.NanoAvax, + 1 * units.NanoAvax, + 1 * units.NanoAvax, + 1 * units.NanoAvax, + }, + UpdateCoefficient: commonfees.Dimensions{ + 1, + 1, + 1, + 1, + }, + BlockUnitsCap: commonfees.Max, + BlockUnitsTarget: commonfees.Dimensions{1000, 1000, 1000, 10000}, + } ) func init() { @@ -165,6 +189,7 @@ func setup(tb testing.TB, c *envConfig) *environment { } vmDynamicConfig := DefaultConfig + vmDynamicConfig.DynamicFeesConfig = &testFeesCfg vmDynamicConfig.IndexTransactions = true if c.vmDynamicConfig != nil { vmDynamicConfig = *c.vmDynamicConfig diff --git a/vms/avm/index_test.go b/vms/avm/index_test.go index 80d7329258e5..43749cce2c91 100644 --- a/vms/avm/index_test.go +++ b/vms/avm/index_test.go @@ -28,7 +28,7 @@ import ( func TestIndexTransaction_Ordered(t *testing.T) { require := require.New(t) - env := setup(t, &envConfig{fork: durango}) + env := setup(t, &envConfig{fork: eUpgrade}) defer func() { require.NoError(env.vm.Shutdown(context.Background())) env.vm.ctx.Lock.Unlock() @@ -70,7 +70,7 @@ func TestIndexTransaction_Ordered(t *testing.T) { func TestIndexTransaction_MultipleTransactions(t *testing.T) { require := require.New(t) - env := setup(t, &envConfig{fork: durango}) + env := setup(t, &envConfig{fork: eUpgrade}) defer func() { require.NoError(env.vm.Shutdown(context.Background())) env.vm.ctx.Lock.Unlock() diff --git a/vms/avm/service_test.go b/vms/avm/service_test.go index f691deb6b633..f7970a55c79e 100644 --- a/vms/avm/service_test.go +++ b/vms/avm/service_test.go @@ -580,7 +580,7 @@ func TestServiceGetTxJSON_BaseTx(t *testing.T) { "addresses": [ "X-testing1d6kkj0qh4wcmus3tk59npwt3rluc6en72ngurd" ], - "amount": 999993673, + "amount": 999990355, "locktime": 0, "threshold": 1 } @@ -662,7 +662,7 @@ func TestServiceGetTxJSON_ExportTx(t *testing.T) { "addresses": [ "X-testing1lnk637g0edwnqc2tn8tel39652fswa3xk4r65e" ], - "amount": 999993645, + "amount": 999990215, "locktime": 0, "threshold": 1 } @@ -811,7 +811,7 @@ func TestServiceGetTxJSON_CreateAssetTx(t *testing.T) { "addresses": [ "X-testing1lnk637g0edwnqc2tn8tel39652fswa3xk4r65e" ], - "amount": 999994709, + "amount": 999990715, "locktime": 0, "threshold": 1 } @@ -906,7 +906,7 @@ func TestServiceGetTxJSON_CreateAssetTx(t *testing.T) { "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", "credential": { "signatures": [ - "0xa8e66a5d264a8ffcde2cdb882bfa7a66346f86d252ba8c802e8c6a899c6c96fd3aa940fe09eb702dd7aa878adeb0e9c9783a64534a0d2082c5b50142cd45974801" + "0x11df1cb82f9a5e3b3ced9167654330e7782832c1189a04bb6b6207f7a69b979d55e5e3819744e4a13255ca724697c6a4ecab8cc9e8464cd2ec574e5b4bda1e2701" ] } } @@ -978,8 +978,34 @@ func TestServiceGetTxJSON_OperationTxWithNftxMintOp(t *testing.T) { "unsignedTx": { "networkID": 10, "blockchainID": "PLACEHOLDER_BLOCKCHAIN_ID", - "outputs": null, - "inputs": null, + "outputs": [ + { + "assetID": "tvLKci3hNoCX4NijS6TfiT6XJJY3gGKd2git6SSVTG5J8Nfby", + "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", + "output": { + "addresses": [ + "X-testing1lnk637g0edwnqc2tn8tel39652fswa3xk4r65e" + ], + "amount": 999989915, + "locktime": 0, + "threshold": 1 + } + } + ], + "inputs": [ + { + "txID": "KGWg2g81xZHm3Enyd16GKh79tRgRK1hcFDsJe5eY9RZQAv5QG", + "outputIndex": 0, + "assetID": "tvLKci3hNoCX4NijS6TfiT6XJJY3gGKd2git6SSVTG5J8Nfby", + "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", + "input": { + "amount": 999991615, + "signatureIndices": [ + 0 + ] + } + } + ], "memo": "0x", "operations": [ { @@ -1013,11 +1039,19 @@ func TestServiceGetTxJSON_OperationTxWithNftxMintOp(t *testing.T) { ] }, "credentials": [ + { + "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", + "credential": { + "signatures": [ + "0x9afa3e41f7b55bea294c30d9b1e79148ed32c5526e5c4449a24745664b4eb1382bc7be71a1ddc77acdcab06c3f020fd53ff9d963dfd2c70c036aa4c1de46571800" + ] + } + }, { "fxID": "qd2U4HDWUvMrVUeTcCHp6xH3Qpnn1XbU5MDdnBoiifFqvgXwT", "credential": { "signatures": [ - "0x4c862cf04a2df68cfd1451568d7c08e8015c72c968bbd31f9764397ddef2046e6d1fab7593cc001900807a15a9f481cfcfd116adbf612a9b194332fec361f23e01" + "0x9afa3e41f7b55bea294c30d9b1e79148ed32c5526e5c4449a24745664b4eb1382bc7be71a1ddc77acdcab06c3f020fd53ff9d963dfd2c70c036aa4c1de46571800" ] } } @@ -1029,7 +1063,7 @@ func TestServiceGetTxJSON_OperationTxWithNftxMintOp(t *testing.T) { expectedReplyTxString = strings.Replace(expectedReplyTxString, "PLACEHOLDER_TX_ID", mintNFTTx.ID().String(), 1) expectedReplyTxString = strings.Replace(expectedReplyTxString, "PLACEHOLDER_BLOCKCHAIN_ID", mintNFTTx.Unsigned.(*txs.OperationTx).BlockchainID.String(), 1) - sigStr, err := formatting.Encode(formatting.HexNC, mintNFTTx.Creds[0].Credential.(*nftfx.Credential).Sigs[0][:]) + sigStr, err := formatting.Encode(formatting.HexNC, mintNFTTx.Creds[1].Credential.(*nftfx.Credential).Sigs[0][:]) require.NoError(err) expectedReplyTxString = strings.Replace(expectedReplyTxString, "PLACEHOLDER_SIGNATURE", sigStr, 1) @@ -1098,8 +1132,34 @@ func TestServiceGetTxJSON_OperationTxWithMultipleNftxMintOp(t *testing.T) { "unsignedTx": { "networkID": 10, "blockchainID": "PLACEHOLDER_BLOCKCHAIN_ID", - "outputs": null, - "inputs": null, + "outputs": [ + { + "assetID": "tvLKci3hNoCX4NijS6TfiT6XJJY3gGKd2git6SSVTG5J8Nfby", + "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", + "output": { + "addresses": [ + "X-testing1lnk637g0edwnqc2tn8tel39652fswa3xk4r65e" + ], + "amount": 999989738, + "locktime": 0, + "threshold": 1 + } + } + ], + "inputs": [ + { + "txID": "Pbg8AVMJUZUzPiFnnBvNKvW6Ljjobr43udPirFbfEYuW7t49z", + "outputIndex": 0, + "assetID": "tvLKci3hNoCX4NijS6TfiT6XJJY3gGKd2git6SSVTG5J8Nfby", + "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", + "input": { + "amount": 999991575, + "signatureIndices": [ + 0 + ] + } + } + ], "memo": "0x", "operations": [ { @@ -1161,11 +1221,19 @@ func TestServiceGetTxJSON_OperationTxWithMultipleNftxMintOp(t *testing.T) { ] }, "credentials": [ + { + "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", + "credential": { + "signatures": [ + "0xdbc76c0ed5064da5c7f391a05800de4a917adb92c98be22d3d995d358e973f877eafd8b32ba9dd4381ab61e20a315b6152171e4bceaedee1b87c009806a584d800" + ] + } + }, { "fxID": "qd2U4HDWUvMrVUeTcCHp6xH3Qpnn1XbU5MDdnBoiifFqvgXwT", "credential": { "signatures": [ - "0xb8fe75ee309edda8d03cb6d890774b98a7171ec18da22894c7d760fc66a0d9392aac513bbc2fbddea9702001dbceaf1cd505a0b3b2b25770471ec0590f5fd24701" + "0xdbc76c0ed5064da5c7f391a05800de4a917adb92c98be22d3d995d358e973f877eafd8b32ba9dd4381ab61e20a315b6152171e4bceaedee1b87c009806a584d800" ] } }, @@ -1248,8 +1316,34 @@ func TestServiceGetTxJSON_OperationTxWithSecpMintOp(t *testing.T) { "unsignedTx": { "networkID": 10, "blockchainID": "PLACEHOLDER_BLOCKCHAIN_ID", - "outputs": null, - "inputs": null, + "outputs": [ + { + "assetID": "tvLKci3hNoCX4NijS6TfiT6XJJY3gGKd2git6SSVTG5J8Nfby", + "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", + "output": { + "addresses": [ + "X-testing1lnk637g0edwnqc2tn8tel39652fswa3xk4r65e" + ], + "amount": 999989908, + "locktime": 0, + "threshold": 1 + } + } + ], + "inputs": [ + { + "txID": "2MBRmBRnKGXkCe7Byc5g9xArAW24qjpKL9fDVNEWJht156xYKp", + "outputIndex": 0, + "assetID": "tvLKci3hNoCX4NijS6TfiT6XJJY3gGKd2git6SSVTG5J8Nfby", + "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", + "input": { + "amount": 999991635, + "signatureIndices": [ + 0 + ] + } + } + ], "memo": "0x", "operations": [ { @@ -1291,7 +1385,15 @@ func TestServiceGetTxJSON_OperationTxWithSecpMintOp(t *testing.T) { "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", "credential": { "signatures": [ - "0x0be6194c911b5836960ac3c79ed0e1243a1df47913dde4d473ee228daf224b8a310a9b12fb42ecac2406699d75ee86d7046525be79c9f747a4d8ac4b0591300700" + "0x3bebf1a4bee4e309a3a93c39886caacc0fe246c0fcad01715cc30152157db4ee3bad1bf8e6466a36255675f7b33defdcc11b2539571dd12cbef2c373e8963cef01" + ] + } + }, + { + "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", + "credential": { + "signatures": [ + "0x3bebf1a4bee4e309a3a93c39886caacc0fe246c0fcad01715cc30152157db4ee3bad1bf8e6466a36255675f7b33defdcc11b2539571dd12cbef2c373e8963cef01" ] } } @@ -1370,8 +1472,34 @@ func TestServiceGetTxJSON_OperationTxWithMultipleSecpMintOp(t *testing.T) { "unsignedTx": { "networkID": 10, "blockchainID": "PLACEHOLDER_BLOCKCHAIN_ID", - "outputs": null, - "inputs": null, + "outputs": [ + { + "assetID": "tvLKci3hNoCX4NijS6TfiT6XJJY3gGKd2git6SSVTG5J8Nfby", + "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", + "output": { + "addresses": [ + "X-testing1lnk637g0edwnqc2tn8tel39652fswa3xk4r65e" + ], + "amount": 999989724, + "locktime": 0, + "threshold": 1 + } + } + ], + "inputs": [ + { + "txID": "rS3zk6KTARY8H6njFhYbMs2tdCqgCnyRXBUUu1ta5jyqfXVq", + "outputIndex": 0, + "assetID": "tvLKci3hNoCX4NijS6TfiT6XJJY3gGKd2git6SSVTG5J8Nfby", + "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", + "input": { + "amount": 999991615, + "signatureIndices": [ + 0 + ] + } + } + ], "memo": "0x", "operations": [ { @@ -1453,7 +1581,15 @@ func TestServiceGetTxJSON_OperationTxWithMultipleSecpMintOp(t *testing.T) { "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", "credential": { "signatures": [ - "0x4e6eb93c7a744c1c550140b115edf7490a9d94a122c9b7cfaed1dfa75b5da3142637d113d85e6a1cbfd0b383f1b604e74b72422207c4631bb2b78f929632df0c00" + "0xc8b9f92346b7cfd553ff0ce07ad3404a2a6f5d3772fad505394ecc569854942c43a7acad47b8da7a0483404213695103732a508db9b7ff31c3cb594ef21416b300" + ] + } + }, + { + "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", + "credential": { + "signatures": [ + "0xc8b9f92346b7cfd553ff0ce07ad3404a2a6f5d3772fad505394ecc569854942c43a7acad47b8da7a0483404213695103732a508db9b7ff31c3cb594ef21416b300" ] } } @@ -1523,8 +1659,34 @@ func TestServiceGetTxJSON_OperationTxWithPropertyFxMintOp(t *testing.T) { "unsignedTx": { "networkID": 10, "blockchainID": "PLACEHOLDER_BLOCKCHAIN_ID", - "outputs": null, - "inputs": null, + "outputs": [ + { + "assetID": "tvLKci3hNoCX4NijS6TfiT6XJJY3gGKd2git6SSVTG5J8Nfby", + "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", + "output": { + "addresses": [ + "X-testing1lnk637g0edwnqc2tn8tel39652fswa3xk4r65e" + ], + "amount": 999990156, + "locktime": 0, + "threshold": 1 + } + } + ], + "inputs": [ + { + "txID": "2JE2HjEceadRG2nPvZP3iaPdcG9N9zLhXy3t7RpDqNKFYitJuE", + "outputIndex": 0, + "assetID": "tvLKci3hNoCX4NijS6TfiT6XJJY3gGKd2git6SSVTG5J8Nfby", + "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", + "input": { + "amount": 999991855, + "signatureIndices": [ + 0 + ] + } + } + ], "memo": "0x", "operations": [ { @@ -1559,6 +1721,14 @@ func TestServiceGetTxJSON_OperationTxWithPropertyFxMintOp(t *testing.T) { ] }, "credentials": [ + { + "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", + "credential": { + "signatures": [ + "0x5d5c832a43c268fbfaeac448d70abcdf421ddb43330569fb226e13fe6612e52c75f1cedf5a9273bdd27382e7823d6cb57491f655bfce86101d95874c291f601101" + ] + } + }, { "fxID": "rXJsCSEYXg2TehWxCEEGj6JU2PWKTkd6cBdNLjoe2SpsKD9cy", "credential": { @@ -1575,7 +1745,7 @@ func TestServiceGetTxJSON_OperationTxWithPropertyFxMintOp(t *testing.T) { expectedReplyTxString = strings.Replace(expectedReplyTxString, "PLACEHOLDER_TX_ID", mintPropertyFxOpTx.ID().String(), 1) expectedReplyTxString = strings.Replace(expectedReplyTxString, "PLACEHOLDER_BLOCKCHAIN_ID", mintPropertyFxOpTx.Unsigned.(*txs.OperationTx).BlockchainID.String(), 1) - sigStr, err := formatting.Encode(formatting.HexNC, mintPropertyFxOpTx.Creds[0].Credential.(*propertyfx.Credential).Sigs[0][:]) + sigStr, err := formatting.Encode(formatting.HexNC, mintPropertyFxOpTx.Creds[1].Credential.(*propertyfx.Credential).Sigs[0][:]) require.NoError(err) expectedReplyTxString = strings.Replace(expectedReplyTxString, "PLACEHOLDER_SIGNATURE", sigStr, 1) @@ -1640,8 +1810,34 @@ func TestServiceGetTxJSON_OperationTxWithPropertyFxMintOpMultiple(t *testing.T) "unsignedTx": { "networkID": 10, "blockchainID": "PLACEHOLDER_BLOCKCHAIN_ID", - "outputs": null, - "inputs": null, + "outputs": [ + { + "assetID": "tvLKci3hNoCX4NijS6TfiT6XJJY3gGKd2git6SSVTG5J8Nfby", + "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", + "output": { + "addresses": [ + "X-testing1lnk637g0edwnqc2tn8tel39652fswa3xk4r65e" + ], + "amount": 999989820, + "locktime": 0, + "threshold": 1 + } + } + ], + "inputs": [ + { + "txID": "2nDskbBWwToZFJ4F2PaTds76ET7UkNuhsmAsmtPpVyodWBZXS7", + "outputIndex": 0, + "assetID": "tvLKci3hNoCX4NijS6TfiT6XJJY3gGKd2git6SSVTG5J8Nfby", + "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", + "input": { + "amount": 999991655, + "signatureIndices": [ + 0 + ] + } + } + ], "memo": "0x", "operations": [ { @@ -1705,6 +1901,14 @@ func TestServiceGetTxJSON_OperationTxWithPropertyFxMintOpMultiple(t *testing.T) ] }, "credentials": [ + { + "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", + "credential": { + "signatures": [ + "0x21e481d413077b99d8baec68669ba96e98a41b99961c0dda5ae8d6e4289f7fa67ad63896989e51f80b3ceba21fd92f8b61e4e6d32f7d4817eaf6980f62fd863601" + ] + } + }, { "fxID": "rXJsCSEYXg2TehWxCEEGj6JU2PWKTkd6cBdNLjoe2SpsKD9cy", "credential": { diff --git a/vms/avm/vm.go b/vms/avm/vm.go index bdc003ee9f34..45e0c8b3568b 100644 --- a/vms/avm/vm.go +++ b/vms/avm/vm.go @@ -171,6 +171,9 @@ func (vm *VM) Initialize( ctx.Log.Info("VM config initialized", zap.Reflect("config", avmConfig), ) + if err := config.ResetDynamicFeesConfig(ctx, avmConfig.DynamicFeesConfig); err != nil { + return fmt.Errorf("failed resetting dynamic fees config: %w", err) + } registerer := prometheus.NewRegistry() if err := ctx.Metrics.Register(registerer); err != nil { diff --git a/vms/avm/vm_regression_test.go b/vms/avm/vm_regression_test.go index 473af93355e6..db58d0039ab3 100644 --- a/vms/avm/vm_regression_test.go +++ b/vms/avm/vm_regression_test.go @@ -19,7 +19,7 @@ import ( func TestVerifyFxUsage(t *testing.T) { require := require.New(t) - env := setup(t, &envConfig{fork: durango}) + env := setup(t, &envConfig{fork: eUpgrade}) env.vm.ctx.Lock.Unlock() defer func() { env.vm.ctx.Lock.Lock() diff --git a/vms/avm/vm_test.go b/vms/avm/vm_test.go index 53d5f41f3d8e..2b352ecf419c 100644 --- a/vms/avm/vm_test.go +++ b/vms/avm/vm_test.go @@ -213,7 +213,7 @@ func TestIssueProperty(t *testing.T) { require := require.New(t) env := setup(t, &envConfig{ - fork: durango, + fork: eUpgrade, additionalFxs: []*common.Fx{{ ID: propertyfx.ID, Fx: &propertyfx.Fx{}, @@ -622,7 +622,7 @@ func TestForceAcceptImportTx(t *testing.T) { UTXOID: utxoID, Asset: txAssetID, In: &secp256k1fx.TransferInput{ - Amt: 1455, + Amt: 10_000 * units.NanoAvax, Input: secp256k1fx.Input{ SigIndices: []uint32{0}, }, @@ -744,7 +744,7 @@ func TestClearForceAcceptedExportTx(t *testing.T) { env.service.txBuilderBackend.ResetAddresses(kc.Addresses()) - expectedFee := uint64(5355) + expectedFee := uint64(7975) tx, _, err := buildExportTx( env.service.txBuilderBackend, constants.PlatformChainID, From 330975295de1064a7b707452f55d0c3ffea65968 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 18 Mar 2024 14:29:34 +0100 Subject: [PATCH 119/132] removed floats from fees update algo --- vms/avm/service_test.go | 32 +++++++++---------- vms/components/fees/manager.go | 14 ++++----- vms/components/fees/manager_test.go | 48 ++++++++++++++--------------- 3 files changed, 47 insertions(+), 47 deletions(-) diff --git a/vms/avm/service_test.go b/vms/avm/service_test.go index f7970a55c79e..426d5ab1718f 100644 --- a/vms/avm/service_test.go +++ b/vms/avm/service_test.go @@ -986,7 +986,7 @@ func TestServiceGetTxJSON_OperationTxWithNftxMintOp(t *testing.T) { "addresses": [ "X-testing1lnk637g0edwnqc2tn8tel39652fswa3xk4r65e" ], - "amount": 999989915, + "amount": 999988215, "locktime": 0, "threshold": 1 } @@ -1043,7 +1043,7 @@ func TestServiceGetTxJSON_OperationTxWithNftxMintOp(t *testing.T) { "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", "credential": { "signatures": [ - "0x9afa3e41f7b55bea294c30d9b1e79148ed32c5526e5c4449a24745664b4eb1382bc7be71a1ddc77acdcab06c3f020fd53ff9d963dfd2c70c036aa4c1de46571800" + "0xf692f8fb45d54064f6453936f5bf636219e2ddf64b5b86ece204aa1527c6e60f10ecbfad2c4cf07b982ef611e791220ac9064035062ab5bf00ec983355437ef400" ] } }, @@ -1051,7 +1051,7 @@ func TestServiceGetTxJSON_OperationTxWithNftxMintOp(t *testing.T) { "fxID": "qd2U4HDWUvMrVUeTcCHp6xH3Qpnn1XbU5MDdnBoiifFqvgXwT", "credential": { "signatures": [ - "0x9afa3e41f7b55bea294c30d9b1e79148ed32c5526e5c4449a24745664b4eb1382bc7be71a1ddc77acdcab06c3f020fd53ff9d963dfd2c70c036aa4c1de46571800" + "0xf692f8fb45d54064f6453936f5bf636219e2ddf64b5b86ece204aa1527c6e60f10ecbfad2c4cf07b982ef611e791220ac9064035062ab5bf00ec983355437ef400" ] } } @@ -1140,7 +1140,7 @@ func TestServiceGetTxJSON_OperationTxWithMultipleNftxMintOp(t *testing.T) { "addresses": [ "X-testing1lnk637g0edwnqc2tn8tel39652fswa3xk4r65e" ], - "amount": 999989738, + "amount": 999987901, "locktime": 0, "threshold": 1 } @@ -1225,7 +1225,7 @@ func TestServiceGetTxJSON_OperationTxWithMultipleNftxMintOp(t *testing.T) { "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", "credential": { "signatures": [ - "0xdbc76c0ed5064da5c7f391a05800de4a917adb92c98be22d3d995d358e973f877eafd8b32ba9dd4381ab61e20a315b6152171e4bceaedee1b87c009806a584d800" + "0x71861edb51241d98280409243382697667ec850852360ab6b72c7864d926ca6d08a0ef2d7a3a3c17e4c38693973ee6b22aeebccd46ae9aab2a038f3777bee18200" ] } }, @@ -1233,7 +1233,7 @@ func TestServiceGetTxJSON_OperationTxWithMultipleNftxMintOp(t *testing.T) { "fxID": "qd2U4HDWUvMrVUeTcCHp6xH3Qpnn1XbU5MDdnBoiifFqvgXwT", "credential": { "signatures": [ - "0xdbc76c0ed5064da5c7f391a05800de4a917adb92c98be22d3d995d358e973f877eafd8b32ba9dd4381ab61e20a315b6152171e4bceaedee1b87c009806a584d800" + "0x71861edb51241d98280409243382697667ec850852360ab6b72c7864d926ca6d08a0ef2d7a3a3c17e4c38693973ee6b22aeebccd46ae9aab2a038f3777bee18200" ] } }, @@ -1324,7 +1324,7 @@ func TestServiceGetTxJSON_OperationTxWithSecpMintOp(t *testing.T) { "addresses": [ "X-testing1lnk637g0edwnqc2tn8tel39652fswa3xk4r65e" ], - "amount": 999989908, + "amount": 999988181, "locktime": 0, "threshold": 1 } @@ -1385,7 +1385,7 @@ func TestServiceGetTxJSON_OperationTxWithSecpMintOp(t *testing.T) { "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", "credential": { "signatures": [ - "0x3bebf1a4bee4e309a3a93c39886caacc0fe246c0fcad01715cc30152157db4ee3bad1bf8e6466a36255675f7b33defdcc11b2539571dd12cbef2c373e8963cef01" + "0xc7c6ee0541a7f9535aea63485698565004ba1904df15ae11a1f9320258b8a0910a7e67b3adecfb583b3c1aa169ce334b6599332a2edb0213438008ee6b8d6e9200" ] } }, @@ -1393,7 +1393,7 @@ func TestServiceGetTxJSON_OperationTxWithSecpMintOp(t *testing.T) { "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", "credential": { "signatures": [ - "0x3bebf1a4bee4e309a3a93c39886caacc0fe246c0fcad01715cc30152157db4ee3bad1bf8e6466a36255675f7b33defdcc11b2539571dd12cbef2c373e8963cef01" + "0xc7c6ee0541a7f9535aea63485698565004ba1904df15ae11a1f9320258b8a0910a7e67b3adecfb583b3c1aa169ce334b6599332a2edb0213438008ee6b8d6e9200" ] } } @@ -1480,7 +1480,7 @@ func TestServiceGetTxJSON_OperationTxWithMultipleSecpMintOp(t *testing.T) { "addresses": [ "X-testing1lnk637g0edwnqc2tn8tel39652fswa3xk4r65e" ], - "amount": 999989724, + "amount": 999987833, "locktime": 0, "threshold": 1 } @@ -1581,7 +1581,7 @@ func TestServiceGetTxJSON_OperationTxWithMultipleSecpMintOp(t *testing.T) { "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", "credential": { "signatures": [ - "0xc8b9f92346b7cfd553ff0ce07ad3404a2a6f5d3772fad505394ecc569854942c43a7acad47b8da7a0483404213695103732a508db9b7ff31c3cb594ef21416b300" + "0x475c5887edeade739aa756b41705b74cccd265044d62a5ddb927cb36b5325fca24b9e60c45b86c75983a2e0b088ca43423f61580526d27e079d4e0699696f16f00" ] } }, @@ -1589,7 +1589,7 @@ func TestServiceGetTxJSON_OperationTxWithMultipleSecpMintOp(t *testing.T) { "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", "credential": { "signatures": [ - "0xc8b9f92346b7cfd553ff0ce07ad3404a2a6f5d3772fad505394ecc569854942c43a7acad47b8da7a0483404213695103732a508db9b7ff31c3cb594ef21416b300" + "0x475c5887edeade739aa756b41705b74cccd265044d62a5ddb927cb36b5325fca24b9e60c45b86c75983a2e0b088ca43423f61580526d27e079d4e0699696f16f00" ] } } @@ -1667,7 +1667,7 @@ func TestServiceGetTxJSON_OperationTxWithPropertyFxMintOp(t *testing.T) { "addresses": [ "X-testing1lnk637g0edwnqc2tn8tel39652fswa3xk4r65e" ], - "amount": 999990156, + "amount": 999988457, "locktime": 0, "threshold": 1 } @@ -1725,7 +1725,7 @@ func TestServiceGetTxJSON_OperationTxWithPropertyFxMintOp(t *testing.T) { "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", "credential": { "signatures": [ - "0x5d5c832a43c268fbfaeac448d70abcdf421ddb43330569fb226e13fe6612e52c75f1cedf5a9273bdd27382e7823d6cb57491f655bfce86101d95874c291f601101" + "0xb57f28c21f47bdcba299086d6f45c94b97f24d45a9c1c68d6c8b42be41ff3e130521dd297c9c9b4af66defde7a3e15538aefaee70211a0191d00e8f280afa5bb00" ] } }, @@ -1818,7 +1818,7 @@ func TestServiceGetTxJSON_OperationTxWithPropertyFxMintOpMultiple(t *testing.T) "addresses": [ "X-testing1lnk637g0edwnqc2tn8tel39652fswa3xk4r65e" ], - "amount": 999989820, + "amount": 999987985, "locktime": 0, "threshold": 1 } @@ -1905,7 +1905,7 @@ func TestServiceGetTxJSON_OperationTxWithPropertyFxMintOpMultiple(t *testing.T) "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", "credential": { "signatures": [ - "0x21e481d413077b99d8baec68669ba96e98a41b99961c0dda5ae8d6e4289f7fa67ad63896989e51f80b3ceba21fd92f8b61e4e6d32f7d4817eaf6980f62fd863601" + "0xcd0efc04d93b862a2fd95c75ccb4b0a393632a2e57c7b68c8fa1821a93e16c83381940dcb52fb5349aa954d9323486ea1022b75d5d9feabd6bf8c9263488234d01" ] } }, 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: Fri, 22 Mar 2024 10:18:34 +0100 Subject: [PATCH 120/132] restructured following P-chain --- tests/e2e/p/workflow.go | 6 +- tests/e2e/x/transfer/virtuous.go | 6 +- vms/avm/block/builder/builder.go | 22 +- vms/avm/block/builder/builder_test.go | 24 +- vms/avm/block/executor/block.go | 21 +- vms/avm/block/executor/block_test.go | 64 ++--- vms/avm/block/executor/manager.go | 14 +- vms/avm/block/executor/manager_test.go | 16 +- vms/avm/client.go | 10 +- vms/avm/config/dynamic_fees_config.go | 12 +- vms/avm/environment_test.go | 8 +- vms/avm/service.go | 41 +-- vms/avm/service_test.go | 4 +- vms/avm/state/diff.go | 44 +-- vms/avm/state/mock_state.go | 240 ++++++++-------- vms/avm/state/state.go | 40 +-- vms/avm/tx.go | 4 +- vms/avm/tx_builders.go | 28 +- .../txs/executor/semantic_verifier_test.go | 16 +- vms/avm/txs/fees/calculator.go | 4 +- vms/avm/txs/fees/calculator_test.go | 10 +- vms/components/fees/config.go | 55 ++-- vms/components/fees/dimensions.go | 3 + vms/components/fees/manager.go | 115 ++++---- vms/components/fees/manager_test.go | 259 ++++++------------ vms/components/fees/window.go | 106 ------- vms/components/fees/window_test.go | 70 ----- wallet/chain/x/wallet.go | 24 +- 28 files changed, 501 insertions(+), 765 deletions(-) delete mode 100644 vms/components/fees/window.go delete mode 100644 vms/components/fees/window_test.go diff --git a/tests/e2e/p/workflow.go b/tests/e2e/p/workflow.go index 21ed0cd4e87b..a97fff3906b1 100644 --- a/tests/e2e/p/workflow.go +++ b/tests/e2e/p/workflow.go @@ -190,13 +190,13 @@ var _ = e2e.DescribePChain("[Workflow]", func() { // retrieve fees paid for the tx feeCfg := config.GetDynamicFeesConfig(true /*isEActive*/) - _, unitFees, err := xChainClient.GetUnitFees(e2e.DefaultContext()) + _, feeRates, err := xChainClient.GetFeeRates(e2e.DefaultContext()) require.NoError(err) feeCalc := fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(unitFees), - ConsumedUnitsCap: feeCfg.BlockUnitsCap, + FeeManager: commonfees.NewManager(feeRates), + ConsumedUnitsCap: feeCfg.BlockMaxComplexity, Codec: xbuilder.Parser.Codec(), Credentials: tx.Creds, } diff --git a/tests/e2e/x/transfer/virtuous.go b/tests/e2e/x/transfer/virtuous.go index ddd890aa668c..d4df5bdaaa49 100644 --- a/tests/e2e/x/transfer/virtuous.go +++ b/tests/e2e/x/transfer/virtuous.go @@ -193,12 +193,12 @@ var _ = e2e.DescribeXChainSerial("[Virtuous Transfer Tx AVAX]", func() { feeCfg := config.GetDynamicFeesConfig(true /*isEActive*/) nodeURI := e2e.Env.GetRandomNodeURI() xChainClient := avm.NewClient(nodeURI.URI, "X") - _, unitFees, err := xChainClient.GetUnitFees(e2e.DefaultContext()) + _, feeRates, err := xChainClient.GetFeeRates(e2e.DefaultContext()) require.NoError(err) feeCalc := fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(unitFees), - ConsumedUnitsCap: feeCfg.BlockUnitsCap, + FeeManager: commonfees.NewManager(feeRates), + ConsumedUnitsCap: feeCfg.BlockMaxComplexity, Codec: xbuilder.Parser.Codec(), Credentials: tx.Creds, } diff --git a/vms/avm/block/builder/builder.go b/vms/avm/block/builder/builder.go index cbc148d1db3f..1d4a06b552b1 100644 --- a/vms/avm/block/builder/builder.go +++ b/vms/avm/block/builder/builder.go @@ -96,23 +96,25 @@ func (b *builder) BuildBlock(context.Context) (snowman.Block, error) { feesCfg = config.GetDynamicFeesConfig(isEForkActive) ) - unitFees, err := stateDiff.GetUnitFees() + feeRates, err := stateDiff.GetFeeRates() if err != nil { return nil, fmt.Errorf("failed retrieving unit fees: %w", err) } - feeWindows, err := stateDiff.GetFeeWindows() + parentBlkComplexity, err := stateDiff.GetLastBlockComplexity() if err != nil { return nil, fmt.Errorf("failed retrieving fee windows: %w", err) } - feeManager := fees.NewManager(unitFees) + feeManager := fees.NewManager(feeRates) if isEForkActive { - feeManager.UpdateUnitFees( + if err := feeManager.UpdateFeeRates( feesCfg, - feeWindows, + parentBlkComplexity, parentBlkTime.Unix(), nextBlkTime.Unix(), - ) + ); err != nil { + return nil, fmt.Errorf("failed updating fee rates, %w", err) + } } for { @@ -125,7 +127,7 @@ func (b *builder) BuildBlock(context.Context) (snowman.Block, error) { // pre e upgrade is active, we fill blocks till a target size // post e upgrade is active, we fill blocks till a target complexity done := (!isEForkActive && txSize > remainingSize) || - (isEForkActive && !fees.Compare(feeManager.GetCumulatedUnits(), feesCfg.BlockUnitsTarget)) + (isEForkActive && !fees.Compare(feeManager.GetCumulatedComplexity(), feesCfg.BlockTargetComplexityRate)) if done { break } @@ -141,7 +143,7 @@ func (b *builder) BuildBlock(context.Context) (snowman.Block, error) { err = tx.Unsigned.Visit(&txexecutor.SemanticVerifier{ Backend: b.backend, BlkFeeManager: feeManager, - UnitCaps: feesCfg.BlockUnitsCap, + UnitCaps: feesCfg.BlockMaxComplexity, State: txDiff, Tx: tx, }) @@ -177,8 +179,8 @@ func (b *builder) BuildBlock(context.Context) (snowman.Block, error) { inputs.Union(executor.Inputs) txDiff.AddTx(tx) - txDiff.SetUnitFees(feeManager.GetUnitFees()) - txDiff.SetFeeWindows(feeWindows) + txDiff.SetFeeRates(feeManager.GetFeeRates()) + txDiff.SetLastBlockComplexity(feeManager.GetCumulatedComplexity()) txDiff.Apply(stateDiff) if isEForkActive { diff --git a/vms/avm/block/builder/builder_test.go b/vms/avm/block/builder/builder_test.go index 229e7d85e63f..ca5c1c115aa9 100644 --- a/vms/avm/block/builder/builder_test.go +++ b/vms/avm/block/builder/builder_test.go @@ -123,8 +123,8 @@ func TestBuilderBuildBlock(t *testing.T) { preferredState := state.NewMockChain(ctrl) preferredState.EXPECT().GetLastAccepted().Return(preferredID) preferredState.EXPECT().GetTimestamp().Return(preferredTimestamp) - preferredState.EXPECT().GetUnitFees().Return(commonfees.Empty, nil) - preferredState.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows, nil) + preferredState.EXPECT().GetFeeRates().Return(commonfees.Empty, nil) + preferredState.EXPECT().GetLastBlockComplexity().Return(commonfees.Empty, nil) manager := blkexecutor.NewMockManager(ctrl) manager.EXPECT().Preferred().Return(preferredID) @@ -174,8 +174,8 @@ func TestBuilderBuildBlock(t *testing.T) { preferredState := state.NewMockChain(ctrl) preferredState.EXPECT().GetLastAccepted().Return(preferredID) preferredState.EXPECT().GetTimestamp().Return(preferredTimestamp) - preferredState.EXPECT().GetUnitFees().Return(commonfees.Empty, nil) - preferredState.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows, nil) + preferredState.EXPECT().GetFeeRates().Return(commonfees.Empty, nil) + preferredState.EXPECT().GetLastBlockComplexity().Return(commonfees.Empty, nil) manager := blkexecutor.NewMockManager(ctrl) manager.EXPECT().Preferred().Return(preferredID) @@ -226,8 +226,8 @@ func TestBuilderBuildBlock(t *testing.T) { preferredState := state.NewMockChain(ctrl) preferredState.EXPECT().GetLastAccepted().Return(preferredID) preferredState.EXPECT().GetTimestamp().Return(preferredTimestamp) - preferredState.EXPECT().GetUnitFees().Return(commonfees.Empty, nil) - preferredState.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows, nil) + preferredState.EXPECT().GetFeeRates().Return(commonfees.Empty, nil) + preferredState.EXPECT().GetLastBlockComplexity().Return(commonfees.Empty, nil) manager := blkexecutor.NewMockManager(ctrl) manager.EXPECT().Preferred().Return(preferredID) @@ -279,8 +279,8 @@ func TestBuilderBuildBlock(t *testing.T) { preferredState := state.NewMockChain(ctrl) preferredState.EXPECT().GetLastAccepted().Return(preferredID) preferredState.EXPECT().GetTimestamp().Return(preferredTimestamp) - preferredState.EXPECT().GetUnitFees().Return(commonfees.Empty, nil) - preferredState.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows, nil) + preferredState.EXPECT().GetFeeRates().Return(commonfees.Empty, nil) + preferredState.EXPECT().GetLastBlockComplexity().Return(commonfees.Empty, nil) // tx1 and tx2 both consume [inputID]. // tx1 is added to the block first, so tx2 should be dropped. @@ -382,8 +382,8 @@ func TestBuilderBuildBlock(t *testing.T) { preferredState := state.NewMockChain(ctrl) preferredState.EXPECT().GetLastAccepted().Return(preferredID) preferredState.EXPECT().GetTimestamp().Return(preferredTimestamp) - preferredState.EXPECT().GetUnitFees().Return(commonfees.Empty, nil) - preferredState.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows, nil) + preferredState.EXPECT().GetFeeRates().Return(commonfees.Empty, nil) + preferredState.EXPECT().GetLastBlockComplexity().Return(commonfees.Empty, nil) manager := blkexecutor.NewMockManager(ctrl) manager.EXPECT().Preferred().Return(preferredID) @@ -463,8 +463,8 @@ func TestBuilderBuildBlock(t *testing.T) { preferredState := state.NewMockChain(ctrl) preferredState.EXPECT().GetLastAccepted().Return(preferredID) preferredState.EXPECT().GetTimestamp().Return(preferredTimestamp) - preferredState.EXPECT().GetUnitFees().Return(commonfees.Empty, nil) - preferredState.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows, nil) + preferredState.EXPECT().GetFeeRates().Return(commonfees.Empty, nil) + preferredState.EXPECT().GetLastBlockComplexity().Return(commonfees.Empty, nil) manager := blkexecutor.NewMockManager(ctrl) manager.EXPECT().Preferred().Return(preferredID) diff --git a/vms/avm/block/executor/block.go b/vms/avm/block/executor/block.go index bb0a8d993847..8a853b4a6a6c 100644 --- a/vms/avm/block/executor/block.go +++ b/vms/avm/block/executor/block.go @@ -132,11 +132,11 @@ func (b *Block) Verify(context.Context) error { atomicRequests: make(map[ids.ID]*atomic.Requests), } - unitFees, err := stateDiff.GetUnitFees() + feeRates, err := stateDiff.GetFeeRates() if err != nil { return fmt.Errorf("failed retrieving unit fees: %w", err) } - feeWindows, err := stateDiff.GetFeeWindows() + parentBlkComplexitty, err := stateDiff.GetLastBlockComplexity() if err != nil { return fmt.Errorf("failed retrieving fee windows: %w", err) } @@ -146,14 +146,16 @@ func (b *Block) Verify(context.Context) error { feesCfg = config.GetDynamicFeesConfig(isEForkActive) ) - feeManager := fees.NewManager(unitFees) + feeManager := fees.NewManager(feeRates) if isEForkActive { - feeManager.UpdateUnitFees( + if err := feeManager.UpdateFeeRates( feesCfg, - feeWindows, + parentBlkComplexitty, parentChainTime.Unix(), newChainTime.Unix(), - ) + ); err != nil { + return fmt.Errorf("failed updating fee rates, %w", err) + } } for _, tx := range txs { @@ -162,7 +164,7 @@ func (b *Block) Verify(context.Context) error { err := tx.Unsigned.Visit(&executor.SemanticVerifier{ Backend: b.manager.backend, BlkFeeManager: feeManager, - UnitCaps: feesCfg.BlockUnitsCap, + UnitCaps: feesCfg.BlockMaxComplexity, State: stateDiff, Tx: tx, }) @@ -225,9 +227,8 @@ func (b *Block) Verify(context.Context) error { // Now that the block has been executed, we can add the block data to the // state diff. if isEForkActive { - feeManager.UpdateWindows(&feeWindows, parentChainTime.Unix(), newChainTime.Unix()) - stateDiff.SetUnitFees(feeManager.GetUnitFees()) - stateDiff.SetFeeWindows(feeWindows) + stateDiff.SetFeeRates(feeManager.GetFeeRates()) + stateDiff.SetLastBlockComplexity(parentBlkComplexitty) } stateDiff.SetLastAccepted(blkID) diff --git a/vms/avm/block/executor/block_test.go b/vms/avm/block/executor/block_test.go index 3d694b23d1b4..38fb1614288b 100644 --- a/vms/avm/block/executor/block_test.go +++ b/vms/avm/block/executor/block_test.go @@ -132,8 +132,8 @@ func TestBlockVerify(t *testing.T) { mempool.EXPECT().MarkDropped(errTx.ID(), errTest).Times(1) mockState := state.NewMockState(ctrl) - mockState.EXPECT().GetUnitFees().Return(commonfees.Empty, nil).AnyTimes() - mockState.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows, nil).AnyTimes() + mockState.EXPECT().GetFeeRates().Return(commonfees.Empty, nil).AnyTimes() + mockState.EXPECT().GetLastBlockComplexity().Return(commonfees.Empty, nil).AnyTimes() return &Block{ Block: mockBlock, @@ -169,8 +169,8 @@ func TestBlockVerify(t *testing.T) { mockState := state.NewMockState(ctrl) mockState.EXPECT().GetBlock(parentID).Return(nil, errTest) - mockState.EXPECT().GetUnitFees().Return(commonfees.Empty, nil).AnyTimes() - mockState.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows, nil).AnyTimes() + mockState.EXPECT().GetFeeRates().Return(commonfees.Empty, nil).AnyTimes() + mockState.EXPECT().GetLastBlockComplexity().Return(commonfees.Empty, nil).AnyTimes() return &Block{ Block: mockBlock, @@ -209,8 +209,8 @@ func TestBlockVerify(t *testing.T) { mockState := state.NewMockState(ctrl) mockState.EXPECT().GetBlock(parentID).Return(mockParentBlock, nil) - mockState.EXPECT().GetUnitFees().Return(commonfees.Empty, nil).AnyTimes() - mockState.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows, nil).AnyTimes() + mockState.EXPECT().GetFeeRates().Return(commonfees.Empty, nil).AnyTimes() + mockState.EXPECT().GetLastBlockComplexity().Return(commonfees.Empty, nil).AnyTimes() return &Block{ Block: mockBlock, @@ -253,8 +253,8 @@ func TestBlockVerify(t *testing.T) { mockParentState.EXPECT().GetTimestamp().Return(blockTimestamp.Add(1)) mockState := state.NewMockState(ctrl) - mockState.EXPECT().GetUnitFees().Return(commonfees.Empty, nil).AnyTimes() - mockState.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows, nil).AnyTimes() + mockState.EXPECT().GetFeeRates().Return(commonfees.Empty, nil).AnyTimes() + mockState.EXPECT().GetLastBlockComplexity().Return(commonfees.Empty, nil).AnyTimes() return &Block{ Block: mockBlock, @@ -301,13 +301,13 @@ func TestBlockVerify(t *testing.T) { mockParentState := state.NewMockDiff(ctrl) mockParentState.EXPECT().GetLastAccepted().Return(parentID) - mockParentState.EXPECT().GetUnitFees().Return(commonfees.Empty, nil) - mockParentState.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows, nil) + mockParentState.EXPECT().GetFeeRates().Return(commonfees.Empty, nil) + mockParentState.EXPECT().GetLastBlockComplexity().Return(commonfees.Empty, nil) mockParentState.EXPECT().GetTimestamp().Return(blockTimestamp) mockState := state.NewMockState(ctrl) - mockState.EXPECT().GetUnitFees().Return(commonfees.Empty, nil).AnyTimes() - mockState.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows, nil).AnyTimes() + mockState.EXPECT().GetFeeRates().Return(commonfees.Empty, nil).AnyTimes() + mockState.EXPECT().GetLastBlockComplexity().Return(commonfees.Empty, nil).AnyTimes() mempool := mempool.NewMockMempool(ctrl) mempool.EXPECT().MarkDropped(tx.ID(), errTest).Times(1) @@ -360,12 +360,12 @@ func TestBlockVerify(t *testing.T) { mockParentState := state.NewMockDiff(ctrl) mockParentState.EXPECT().GetLastAccepted().Return(parentID) mockParentState.EXPECT().GetTimestamp().Return(blockTimestamp) - mockParentState.EXPECT().GetUnitFees().Return(commonfees.Empty, nil) - mockParentState.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows, nil) + mockParentState.EXPECT().GetFeeRates().Return(commonfees.Empty, nil) + mockParentState.EXPECT().GetLastBlockComplexity().Return(commonfees.Empty, nil) mockState := state.NewMockState(ctrl) - mockState.EXPECT().GetUnitFees().Return(commonfees.Empty, nil).AnyTimes() - mockState.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows, nil).AnyTimes() + mockState.EXPECT().GetFeeRates().Return(commonfees.Empty, nil).AnyTimes() + mockState.EXPECT().GetLastBlockComplexity().Return(commonfees.Empty, nil).AnyTimes() mempool := mempool.NewMockMempool(ctrl) mempool.EXPECT().MarkDropped(tx.ID(), errTest).Times(1) @@ -445,12 +445,12 @@ func TestBlockVerify(t *testing.T) { mockParentState := state.NewMockDiff(ctrl) mockParentState.EXPECT().GetLastAccepted().Return(parentID) mockParentState.EXPECT().GetTimestamp().Return(blockTimestamp) - mockParentState.EXPECT().GetUnitFees().Return(commonfees.Empty, nil) - mockParentState.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows, nil) + mockParentState.EXPECT().GetFeeRates().Return(commonfees.Empty, nil) + mockParentState.EXPECT().GetLastBlockComplexity().Return(commonfees.Empty, nil) mockState := state.NewMockState(ctrl) - mockState.EXPECT().GetUnitFees().Return(commonfees.Empty, nil).AnyTimes() - mockState.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows, nil).AnyTimes() + mockState.EXPECT().GetFeeRates().Return(commonfees.Empty, nil).AnyTimes() + mockState.EXPECT().GetLastBlockComplexity().Return(commonfees.Empty, nil).AnyTimes() mempool := mempool.NewMockMempool(ctrl) mempool.EXPECT().MarkDropped(tx2.ID(), ErrConflictingBlockTxs).Times(1) @@ -514,12 +514,12 @@ func TestBlockVerify(t *testing.T) { mockParentState := state.NewMockDiff(ctrl) mockParentState.EXPECT().GetLastAccepted().Return(parentID) mockParentState.EXPECT().GetTimestamp().Return(blockTimestamp) - mockParentState.EXPECT().GetUnitFees().Return(commonfees.Empty, nil) - mockParentState.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows, nil) + mockParentState.EXPECT().GetFeeRates().Return(commonfees.Empty, nil) + mockParentState.EXPECT().GetLastBlockComplexity().Return(commonfees.Empty, nil) mockState := state.NewMockState(ctrl) - mockState.EXPECT().GetUnitFees().Return(commonfees.Empty, nil).AnyTimes() - mockState.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows, nil).AnyTimes() + mockState.EXPECT().GetFeeRates().Return(commonfees.Empty, nil).AnyTimes() + mockState.EXPECT().GetLastBlockComplexity().Return(commonfees.Empty, nil).AnyTimes() return &Block{ Block: mockBlock, @@ -569,12 +569,12 @@ func TestBlockVerify(t *testing.T) { mockParentState := state.NewMockDiff(ctrl) mockParentState.EXPECT().GetLastAccepted().Return(parentID) mockParentState.EXPECT().GetTimestamp().Return(blockTimestamp) - mockParentState.EXPECT().GetUnitFees().Return(commonfees.Empty, nil) - mockParentState.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows, nil) + mockParentState.EXPECT().GetFeeRates().Return(commonfees.Empty, nil) + mockParentState.EXPECT().GetLastBlockComplexity().Return(commonfees.Empty, nil) mockState := state.NewMockState(ctrl) - mockState.EXPECT().GetUnitFees().Return(commonfees.Empty, nil).AnyTimes() - mockState.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows, nil).AnyTimes() + mockState.EXPECT().GetFeeRates().Return(commonfees.Empty, nil).AnyTimes() + mockState.EXPECT().GetLastBlockComplexity().Return(commonfees.Empty, nil).AnyTimes() mockMempool := mempool.NewMockMempool(ctrl) mockMempool.EXPECT().Remove([]*txs.Tx{tx}) @@ -909,8 +909,8 @@ func TestBlockReject(t *testing.T) { mockState.EXPECT().GetLastAccepted().Return(lastAcceptedID).AnyTimes() mockState.EXPECT().GetBlock(lastAcceptedID).Return(lastAcceptedMockBlock, nil).AnyTimes() mockState.EXPECT().GetTimestamp().Return(time.Now()).AnyTimes() - mockState.EXPECT().GetUnitFees().Return(commonfees.Empty, nil).AnyTimes() - mockState.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows, nil).AnyTimes() + mockState.EXPECT().GetFeeRates().Return(commonfees.Empty, nil).AnyTimes() + mockState.EXPECT().GetLastBlockComplexity().Return(commonfees.Empty, nil).AnyTimes() manager := &manager{ lastAccepted: lastAcceptedID, @@ -973,8 +973,8 @@ func TestBlockReject(t *testing.T) { mockState.EXPECT().GetLastAccepted().Return(lastAcceptedID).AnyTimes() mockState.EXPECT().GetBlock(lastAcceptedID).Return(lastAcceptedMockBlock, nil).AnyTimes() mockState.EXPECT().GetTimestamp().Return(time.Now()).AnyTimes() - mockState.EXPECT().GetUnitFees().Return(commonfees.Empty, nil).AnyTimes() - mockState.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows, nil).AnyTimes() + mockState.EXPECT().GetFeeRates().Return(commonfees.Empty, nil).AnyTimes() + mockState.EXPECT().GetLastBlockComplexity().Return(commonfees.Empty, nil).AnyTimes() manager := &manager{ lastAccepted: lastAcceptedID, diff --git a/vms/avm/block/executor/manager.go b/vms/avm/block/executor/manager.go index f3556b8ea05f..7029f52cd509 100644 --- a/vms/avm/block/executor/manager.go +++ b/vms/avm/block/executor/manager.go @@ -171,11 +171,11 @@ func (m *manager) VerifyTx(tx *txs.Tx) error { return err } - unitFees, err := stateDiff.GetUnitFees() + feeRates, err := stateDiff.GetFeeRates() if err != nil { return fmt.Errorf("failed retrieving unit fees: %w", err) } - feeWindows, err := stateDiff.GetFeeWindows() + feeWindows, err := stateDiff.GetLastBlockComplexity() if err != nil { return fmt.Errorf("failed retrieving fee windows: %w", err) } @@ -185,20 +185,22 @@ func (m *manager) VerifyTx(tx *txs.Tx) error { feesCfg = config.GetDynamicFeesConfig(isEForkActive) ) - feeManager := fees.NewManager(unitFees) + feeManager := fees.NewManager(feeRates) if isEForkActive { - feeManager.UpdateUnitFees( + if err := feeManager.UpdateFeeRates( feesCfg, feeWindows, parentBlkTime.Unix(), nextBlkTime.Unix(), - ) + ); err != nil { + return fmt.Errorf("failed updating fee rates, %w", err) + } } err = tx.Unsigned.Visit(&executor.SemanticVerifier{ Backend: m.backend, BlkFeeManager: feeManager, - UnitCaps: feesCfg.BlockUnitsCap, + UnitCaps: feesCfg.BlockMaxComplexity, State: stateDiff, Tx: tx, }) diff --git a/vms/avm/block/executor/manager_test.go b/vms/avm/block/executor/manager_test.go index 697f4fc4c6da..9a6c711812d7 100644 --- a/vms/avm/block/executor/manager_test.go +++ b/vms/avm/block/executor/manager_test.go @@ -142,8 +142,8 @@ 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(commonfees.Empty, nil).AnyTimes() - state.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows, nil).AnyTimes() + state.EXPECT().GetFeeRates().Return(commonfees.Empty, nil).AnyTimes() + state.EXPECT().GetLastBlockComplexity().Return(commonfees.Empty, nil).AnyTimes() return &manager{ backend: defaultTestBackend(true, nil), @@ -175,8 +175,8 @@ func TestManagerVerifyTx(t *testing.T) { state.EXPECT().GetLastAccepted().Return(lastAcceptedID).AnyTimes() state.EXPECT().GetBlock(lastAcceptedID).Return(lastAcceptedMockBlock, nil).AnyTimes() state.EXPECT().GetTimestamp().Return(time.Time{}).AnyTimes() - state.EXPECT().GetUnitFees().Return(commonfees.Empty, nil).AnyTimes() - state.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows, nil).AnyTimes() + state.EXPECT().GetFeeRates().Return(commonfees.Empty, nil).AnyTimes() + state.EXPECT().GetLastBlockComplexity().Return(commonfees.Empty, nil).AnyTimes() m := &manager{ backend: defaultTestBackend(true, nil), @@ -215,8 +215,8 @@ func TestManagerVerifyTx(t *testing.T) { state.EXPECT().GetLastAccepted().Return(lastAcceptedID).AnyTimes() state.EXPECT().GetBlock(lastAcceptedID).Return(lastAcceptedMockBlock, nil).AnyTimes() state.EXPECT().GetTimestamp().Return(time.Time{}).AnyTimes() - state.EXPECT().GetUnitFees().Return(commonfees.Empty, nil).AnyTimes() - state.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows, nil).AnyTimes() + state.EXPECT().GetFeeRates().Return(commonfees.Empty, nil).AnyTimes() + state.EXPECT().GetLastBlockComplexity().Return(commonfees.Empty, nil).AnyTimes() m := &manager{ backend: defaultTestBackend(true, nil), @@ -254,8 +254,8 @@ func TestManagerVerifyTx(t *testing.T) { state.EXPECT().GetLastAccepted().Return(lastAcceptedID).AnyTimes() state.EXPECT().GetBlock(lastAcceptedID).Return(lastAcceptedMockBlock, nil).AnyTimes() state.EXPECT().GetTimestamp().Return(time.Time{}).AnyTimes() - state.EXPECT().GetUnitFees().Return(commonfees.Empty, nil).AnyTimes() - state.EXPECT().GetFeeWindows().Return(commonfees.EmptyWindows, nil).AnyTimes() + state.EXPECT().GetFeeRates().Return(commonfees.Empty, nil).AnyTimes() + state.EXPECT().GetLastBlockComplexity().Return(commonfees.Empty, nil).AnyTimes() m := &manager{ backend: defaultTestBackend(true, nil), diff --git a/vms/avm/client.go b/vms/avm/client.go index 1d42112759ad..ececf2618baf 100644 --- a/vms/avm/client.go +++ b/vms/avm/client.go @@ -76,8 +76,8 @@ type Client interface { // // Deprecated: GetUTXOs should be used instead. GetAllBalances(ctx context.Context, addr ids.ShortID, includePartial bool, options ...rpc.Option) ([]Balance, 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) // CreateAsset creates a new asset and returns its assetID // // Deprecated: Transactions should be issued using the @@ -410,9 +410,9 @@ func (c *client) GetAllBalances( return res.Balances, err } -func (c *client) GetUnitFees(ctx context.Context, options ...rpc.Option) (commonfees.Dimensions, commonfees.Dimensions, error) { - res := &GetUnitFeesReply{} - err := c.requester.SendRequest(ctx, "avm.getUnitFees", struct{}{}, res, options...) +func (c *client) GetFeeRates(ctx context.Context, options ...rpc.Option) (commonfees.Dimensions, commonfees.Dimensions, error) { + res := &GetFeeRatesReply{} + err := c.requester.SendRequest(ctx, "avm.getFeeRates", struct{}{}, res, options...) return res.CurrentUnitFees, res.NextUnitFees, err } diff --git a/vms/avm/config/dynamic_fees_config.go b/vms/avm/config/dynamic_fees_config.go index 36273df263b3..5929a70f5818 100644 --- a/vms/avm/config/dynamic_fees_config.go +++ b/vms/avm/config/dynamic_fees_config.go @@ -22,27 +22,27 @@ 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.Dimensions{}, + MinFeeRate: commonfees.Dimensions{}, UpdateCoefficient: commonfees.Dimensions{ 1, 1, 1, 1, }, - BlockUnitsCap: commonfees.Max, - BlockUnitsTarget: commonfees.Dimensions{1, 1, 1, 1}, + BlockMaxComplexity: commonfees.Max, + BlockTargetComplexityRate: commonfees.Dimensions{1, 1, 1, 1}, } // 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/avm/environment_test.go b/vms/avm/environment_test.go index fe56c4cdb692..dd4747c1be5c 100644 --- a/vms/avm/environment_test.go +++ b/vms/avm/environment_test.go @@ -80,13 +80,13 @@ var ( addrs []ids.ShortID // addrs[i] corresponds to keys[i] testFeesCfg = commonfees.DynamicFeesConfig{ - InitialUnitFees: commonfees.Dimensions{ + InitialFeeRate: commonfees.Dimensions{ 5 * units.NanoAvax, 5 * units.NanoAvax, 5 * units.NanoAvax, 5 * units.NanoAvax, }, - MinUnitFees: commonfees.Dimensions{ + MinFeeRate: commonfees.Dimensions{ 1 * units.NanoAvax, 1 * units.NanoAvax, 1 * units.NanoAvax, @@ -98,8 +98,8 @@ var ( 1, 1, }, - BlockUnitsCap: commonfees.Max, - BlockUnitsTarget: commonfees.Dimensions{1000, 1000, 1000, 10000}, + BlockMaxComplexity: commonfees.Max, + BlockTargetComplexityRate: commonfees.Dimensions{1000, 1000, 1000, 10000}, } ) diff --git a/vms/avm/service.go b/vms/avm/service.go index 7936a38a6e3b..a30a1bb65531 100644 --- a/vms/avm/service.go +++ b/vms/avm/service.go @@ -676,17 +676,17 @@ func (s *Service) GetAllBalances(_ *http.Request, args *GetAllBalancesArgs, repl return nil } -// GetUnitFeesReply is the response from GetUnitFees -type GetUnitFeesReply struct { +// GetFeeRatesReply is the response from GetFeeRates +type GetFeeRatesReply 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 *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() @@ -698,7 +698,7 @@ func (s *Service) GetUnitFees(_ *http.Request, _ *struct{}, reply *GetUnitFeesRe return fmt.Errorf("could not retrieve state for block %s", preferredID) } - currentUnitFees, err := onAccept.GetUnitFees() + currentUnitFees, err := onAccept.GetFeeRates() if err != nil { return err } @@ -717,46 +717,27 @@ func (s *Service) GetUnitFees(_ *http.Request, _ *struct{}, reply *GetUnitFeesRe feesCfg = config.GetDynamicFeesConfig(isEActivated) ) - feeWindows, err := onAccept.GetFeeWindows() + feeWindows, err := onAccept.GetLastBlockComplexity() if err != nil { return err } feeManager := commonfees.NewManager(currentUnitFees) if isEActivated { - feeManager.UpdateUnitFees( + if err := feeManager.UpdateFeeRates( feesCfg, feeWindows, 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 } -// 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", "avm"), - 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 -} - // Holder describes how much an address owns of an asset type Holder struct { Amount avajson.Uint64 `json:"amount"` diff --git a/vms/avm/service_test.go b/vms/avm/service_test.go index 9bf9bed254ac..2ab8271cac8f 100644 --- a/vms/avm/service_test.go +++ b/vms/avm/service_test.go @@ -2700,8 +2700,8 @@ func TestNFTWorkflow(t *testing.T) { feeCalc := &fees.Calculator{ IsEUpgradeActive: true, Config: &env.vm.Config, - FeeManager: commonfees.NewManager(feesCfg.InitialUnitFees), - ConsumedUnitsCap: feesCfg.BlockUnitsCap, + FeeManager: commonfees.NewManager(feesCfg.InitialFeeRate), + ConsumedUnitsCap: feesCfg.BlockMaxComplexity, Codec: env.service.txBuilderBackend.codec, Credentials: createAssetTx.Creds, } diff --git a/vms/avm/state/diff.go b/vms/avm/state/diff.go index a7902b21a233..ffdae17b90c6 100644 --- a/vms/avm/state/diff.go +++ b/vms/avm/state/diff.go @@ -40,10 +40,10 @@ type diff struct { addedBlockIDs map[uint64]ids.ID // map of height -> blockID addedBlocks map[ids.ID]block.Block // map of blockID -> block - lastAccepted ids.ID - timestamp time.Time - unitFees *commonfees.Dimensions - feesWindows *commonfees.Windows + lastAccepted ids.ID + timestamp time.Time + unitFees *commonfees.Dimensions + lastBlkComplexity *commonfees.Dimensions } func NewDiff( @@ -165,13 +165,13 @@ func (d *diff) SetTimestamp(t time.Time) { d.timestamp = t } -func (d *diff) GetUnitFees() (commonfees.Dimensions, error) { +func (d *diff) GetFeeRates() (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() + parentUnitFees, err := parentState.GetFeeRates() if err != nil { return commonfees.Empty, err } @@ -183,36 +183,36 @@ func (d *diff) GetUnitFees() (commonfees.Dimensions, error) { return *d.unitFees, nil } -func (d *diff) SetUnitFees(uf commonfees.Dimensions) { +func (d *diff) SetFeeRates(uf commonfees.Dimensions) { if d.unitFees == nil { d.unitFees = new(commonfees.Dimensions) } *d.unitFees = 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() + parentFeeWindows, 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 = parentFeeWindows } - 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(windows commonfees.Dimensions) { + if d.lastBlkComplexity == nil { + d.lastBlkComplexity = new(commonfees.Dimensions) } - *d.feesWindows = windows + *d.lastBlkComplexity = windows } func (d *diff) Apply(state Chain) { @@ -235,9 +235,9 @@ func (d *diff) Apply(state Chain) { state.SetLastAccepted(d.lastAccepted) state.SetTimestamp(d.timestamp) if d.unitFees != nil { - state.SetUnitFees(*d.unitFees) + state.SetFeeRates(*d.unitFees) } - if d.feesWindows != nil { - state.SetFeeWindows(*d.feesWindows) + if d.lastBlkComplexity != nil { + state.SetLastBlockComplexity(*d.lastBlkComplexity) } } diff --git a/vms/avm/state/mock_state.go b/vms/avm/state/mock_state.go index 5510fded9d96..d1c911d4338a 100644 --- a/vms/avm/state/mock_state.go +++ b/vms/avm/state/mock_state.go @@ -123,19 +123,19 @@ func (mr *MockChainMockRecorder) GetBlockIDAtHeight(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBlockIDAtHeight", reflect.TypeOf((*MockChain)(nil).GetBlockIDAtHeight), arg0) } -// 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 } -// GetFeeWindows indicates an expected call of GetFeeWindows. -func (mr *MockChainMockRecorder) GetFeeWindows() *gomock.Call { +// 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, "GetFeeWindows", reflect.TypeOf((*MockChain)(nil).GetFeeWindows)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFeeRates", reflect.TypeOf((*MockChain)(nil).GetFeeRates)) } // GetLastAccepted mocks base method. @@ -152,6 +152,21 @@ func (mr *MockChainMockRecorder) GetLastAccepted() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLastAccepted", reflect.TypeOf((*MockChain)(nil).GetLastAccepted)) } +// 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 +} + +// 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, "GetLastBlockComplexity", reflect.TypeOf((*MockChain)(nil).GetLastBlockComplexity)) +} + // GetTimestamp mocks base method. func (m *MockChain) GetTimestamp() time.Time { m.ctrl.T.Helper() @@ -196,31 +211,16 @@ 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)) -} - -// SetFeeWindows mocks base method. -func (m *MockChain) SetFeeWindows(arg0 fees.Windows) { +// SetFeeRates mocks base method. +func (m *MockChain) SetFeeRates(arg0 fees.Dimensions) { m.ctrl.T.Helper() - m.ctrl.Call(m, "SetFeeWindows", arg0) + m.ctrl.Call(m, "SetFeeRates", arg0) } -// SetFeeWindows indicates an expected call of SetFeeWindows. -func (mr *MockChainMockRecorder) SetFeeWindows(arg0 any) *gomock.Call { +// 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, "SetFeeWindows", reflect.TypeOf((*MockChain)(nil).SetFeeWindows), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetFeeRates", reflect.TypeOf((*MockChain)(nil).SetFeeRates), arg0) } // SetLastAccepted mocks base method. @@ -235,28 +235,28 @@ func (mr *MockChainMockRecorder) SetLastAccepted(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetLastAccepted", reflect.TypeOf((*MockChain)(nil).SetLastAccepted), arg0) } -// SetTimestamp mocks base method. -func (m *MockChain) SetTimestamp(arg0 time.Time) { +// SetLastBlockComplexity mocks base method. +func (m *MockChain) SetLastBlockComplexity(arg0 fees.Dimensions) { m.ctrl.T.Helper() - m.ctrl.Call(m, "SetTimestamp", arg0) + m.ctrl.Call(m, "SetLastBlockComplexity", arg0) } -// SetTimestamp indicates an expected call of SetTimestamp. -func (mr *MockChainMockRecorder) SetTimestamp(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, "SetTimestamp", reflect.TypeOf((*MockChain)(nil).SetTimestamp), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetLastBlockComplexity", reflect.TypeOf((*MockChain)(nil).SetLastBlockComplexity), arg0) } -// SetUnitFees mocks base method. -func (m *MockChain) SetUnitFees(arg0 fees.Dimensions) { +// SetTimestamp mocks base method. +func (m *MockChain) SetTimestamp(arg0 time.Time) { m.ctrl.T.Helper() - m.ctrl.Call(m, "SetUnitFees", arg0) + m.ctrl.Call(m, "SetTimestamp", arg0) } -// SetUnitFees indicates an expected call of SetUnitFees. -func (mr *MockChainMockRecorder) SetUnitFees(arg0 any) *gomock.Call { +// SetTimestamp indicates an expected call of SetTimestamp. +func (mr *MockChainMockRecorder) SetTimestamp(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetUnitFees", reflect.TypeOf((*MockChain)(nil).SetUnitFees), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetTimestamp", reflect.TypeOf((*MockChain)(nil).SetTimestamp), arg0) } // MockState is a mock of State interface. @@ -430,19 +430,19 @@ func (mr *MockStateMockRecorder) GetBlockIDAtHeight(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBlockIDAtHeight", reflect.TypeOf((*MockState)(nil).GetBlockIDAtHeight), arg0) } -// 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. @@ -459,6 +459,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)) +} + // GetTimestamp mocks base method. func (m *MockState) GetTimestamp() time.Time { m.ctrl.T.Helper() @@ -503,21 +518,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)) -} - // InitFees mocks base method. func (m *MockState) InitFees() error { m.ctrl.T.Helper() @@ -561,16 +561,16 @@ func (mr *MockStateMockRecorder) IsInitialized() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsInitialized", reflect.TypeOf((*MockState)(nil).IsInitialized)) } -// SetFeeWindows mocks base method. -func (m *MockState) SetFeeWindows(arg0 fees.Windows) { +// SetFeeRates mocks base method. +func (m *MockState) SetFeeRates(arg0 fees.Dimensions) { m.ctrl.T.Helper() - m.ctrl.Call(m, "SetFeeWindows", arg0) + m.ctrl.Call(m, "SetFeeRates", arg0) } -// SetFeeWindows indicates an expected call of SetFeeWindows. -func (mr *MockStateMockRecorder) SetFeeWindows(arg0 any) *gomock.Call { +// 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, "SetFeeWindows", reflect.TypeOf((*MockState)(nil).SetFeeWindows), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetFeeRates", reflect.TypeOf((*MockState)(nil).SetFeeRates), arg0) } // SetInitialized mocks base method. @@ -599,28 +599,28 @@ func (mr *MockStateMockRecorder) SetLastAccepted(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetLastAccepted", reflect.TypeOf((*MockState)(nil).SetLastAccepted), arg0) } -// SetTimestamp mocks base method. -func (m *MockState) SetTimestamp(arg0 time.Time) { +// SetLastBlockComplexity mocks base method. +func (m *MockState) SetLastBlockComplexity(arg0 fees.Dimensions) { m.ctrl.T.Helper() - m.ctrl.Call(m, "SetTimestamp", arg0) + m.ctrl.Call(m, "SetLastBlockComplexity", arg0) } -// SetTimestamp indicates an expected call of SetTimestamp. -func (mr *MockStateMockRecorder) SetTimestamp(arg0 any) *gomock.Call { +// 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, "SetTimestamp", reflect.TypeOf((*MockState)(nil).SetTimestamp), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetLastBlockComplexity", reflect.TypeOf((*MockState)(nil).SetLastBlockComplexity), arg0) } -// SetUnitFees mocks base method. -func (m *MockState) SetUnitFees(arg0 fees.Dimensions) { +// SetTimestamp mocks base method. +func (m *MockState) SetTimestamp(arg0 time.Time) { m.ctrl.T.Helper() - m.ctrl.Call(m, "SetUnitFees", arg0) + m.ctrl.Call(m, "SetTimestamp", arg0) } -// SetUnitFees indicates an expected call of SetUnitFees. -func (mr *MockStateMockRecorder) SetUnitFees(arg0 any) *gomock.Call { +// SetTimestamp indicates an expected call of SetTimestamp. +func (mr *MockStateMockRecorder) SetTimestamp(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetUnitFees", reflect.TypeOf((*MockState)(nil).SetUnitFees), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetTimestamp", reflect.TypeOf((*MockState)(nil).SetTimestamp), arg0) } // UTXOIDs mocks base method. @@ -751,19 +751,19 @@ func (mr *MockDiffMockRecorder) GetBlockIDAtHeight(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBlockIDAtHeight", reflect.TypeOf((*MockDiff)(nil).GetBlockIDAtHeight), arg0) } -// 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)) } // GetLastAccepted mocks base method. @@ -780,6 +780,21 @@ func (mr *MockDiffMockRecorder) GetLastAccepted() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLastAccepted", reflect.TypeOf((*MockDiff)(nil).GetLastAccepted)) } +// 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)) +} + // GetTimestamp mocks base method. func (m *MockDiff) GetTimestamp() time.Time { m.ctrl.T.Helper() @@ -824,31 +839,16 @@ 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)) -} - -// SetFeeWindows mocks base method. -func (m *MockDiff) SetFeeWindows(arg0 fees.Windows) { +// SetFeeRates mocks base method. +func (m *MockDiff) SetFeeRates(arg0 fees.Dimensions) { m.ctrl.T.Helper() - m.ctrl.Call(m, "SetFeeWindows", arg0) + m.ctrl.Call(m, "SetFeeRates", arg0) } -// SetFeeWindows indicates an expected call of SetFeeWindows. -func (mr *MockDiffMockRecorder) SetFeeWindows(arg0 any) *gomock.Call { +// 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, "SetFeeWindows", reflect.TypeOf((*MockDiff)(nil).SetFeeWindows), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetFeeRates", reflect.TypeOf((*MockDiff)(nil).SetFeeRates), arg0) } // SetLastAccepted mocks base method. @@ -863,26 +863,26 @@ func (mr *MockDiffMockRecorder) SetLastAccepted(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetLastAccepted", reflect.TypeOf((*MockDiff)(nil).SetLastAccepted), arg0) } -// SetTimestamp mocks base method. -func (m *MockDiff) SetTimestamp(arg0 time.Time) { +// SetLastBlockComplexity mocks base method. +func (m *MockDiff) SetLastBlockComplexity(arg0 fees.Dimensions) { m.ctrl.T.Helper() - m.ctrl.Call(m, "SetTimestamp", arg0) + m.ctrl.Call(m, "SetLastBlockComplexity", arg0) } -// SetTimestamp indicates an expected call of SetTimestamp. -func (mr *MockDiffMockRecorder) SetTimestamp(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, "SetTimestamp", reflect.TypeOf((*MockDiff)(nil).SetTimestamp), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetLastBlockComplexity", reflect.TypeOf((*MockDiff)(nil).SetLastBlockComplexity), arg0) } -// SetUnitFees mocks base method. -func (m *MockDiff) SetUnitFees(arg0 fees.Dimensions) { +// SetTimestamp mocks base method. +func (m *MockDiff) SetTimestamp(arg0 time.Time) { m.ctrl.T.Helper() - m.ctrl.Call(m, "SetUnitFees", arg0) + m.ctrl.Call(m, "SetTimestamp", arg0) } -// SetUnitFees indicates an expected call of SetUnitFees. -func (mr *MockDiffMockRecorder) SetUnitFees(arg0 any) *gomock.Call { +// SetTimestamp indicates an expected call of SetTimestamp. +func (mr *MockDiffMockRecorder) SetTimestamp(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetUnitFees", reflect.TypeOf((*MockDiff)(nil).SetUnitFees), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetTimestamp", reflect.TypeOf((*MockDiff)(nil).SetTimestamp), arg0) } diff --git a/vms/avm/state/state.go b/vms/avm/state/state.go index e4128b83d358..1c7f7f2ceb82 100644 --- a/vms/avm/state/state.go +++ b/vms/avm/state/state.go @@ -55,8 +55,8 @@ type ReadOnlyChain interface { GetLastAccepted() ids.ID GetTimestamp() time.Time - GetUnitFees() (commonfees.Dimensions, error) - GetFeeWindows() (commonfees.Windows, error) + GetFeeRates() (commonfees.Dimensions, error) + GetLastBlockComplexity() (commonfees.Dimensions, error) } type Chain interface { @@ -69,8 +69,8 @@ type Chain interface { SetLastAccepted(blkID ids.ID) SetTimestamp(t time.Time) - SetUnitFees(uf commonfees.Dimensions) - SetFeeWindows(windows commonfees.Windows) + SetFeeRates(uf commonfees.Dimensions) + SetLastBlockComplexity(windows commonfees.Dimensions) } // State persistently maintains a set of UTXOs, transaction, statuses, and @@ -149,8 +149,8 @@ type state struct { timestamp, persistedTimestamp time.Time singletonDB database.Database - unitFees commonfees.Dimensions - feesWindows commonfees.Windows + feeRates commonfees.Dimensions + lastBlkComplexity commonfees.Dimensions trackChecksum bool txChecksum ids.ID @@ -366,7 +366,7 @@ func (s *state) InitializeChainState(stopVertexID ids.ID, genesisTimestamp time. func (s *state) InitFees() error { switch unitFeesBytes, err := s.singletonDB.Get(unitFeesKey); err { case nil: - if err := s.unitFees.FromBytes(unitFeesBytes); err != nil { + if err := s.feeRates.FromBytes(unitFeesBytes); err != nil { return err } @@ -376,7 +376,7 @@ func (s *state) InitFees() error { // TODO: remove once fork is active isEActivated := s.cfg.IsEActivated(s.GetTimestamp()) feeCfg := config.GetDynamicFeesConfig(isEActivated) - s.unitFees = feeCfg.InitialUnitFees + s.feeRates = feeCfg.InitialFeeRate default: return err @@ -384,7 +384,7 @@ func (s *state) InitFees() error { switch feesWindowsBytes, err := s.singletonDB.Get(feesWindowsKey); err { case nil: - if err := s.feesWindows.FromBytes(feesWindowsBytes); err != nil { + if err := s.lastBlkComplexity.FromBytes(feesWindowsBytes); err != nil { return err } @@ -392,7 +392,7 @@ func (s *state) InitFees() 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 @@ -443,20 +443,20 @@ func (s *state) SetTimestamp(t time.Time) { s.timestamp = t } -func (s *state) GetUnitFees() (commonfees.Dimensions, error) { - return s.unitFees, nil +func (s *state) GetFeeRates() (commonfees.Dimensions, error) { + return s.feeRates, nil } -func (s *state) SetUnitFees(uf commonfees.Dimensions) { - s.unitFees = uf +func (s *state) SetFeeRates(feeRates commonfees.Dimensions) { + s.feeRates = feeRates } -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) Commit() error { @@ -565,10 +565,10 @@ func (s *state) writeMetadata() error { } s.persistedTimestamp = s.timestamp } - if err := s.singletonDB.Put(unitFeesKey, s.unitFees.Bytes()); err != nil { + if err := s.singletonDB.Put(unitFeesKey, s.feeRates.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(feesWindowsKey, s.lastBlkComplexity.Bytes()); err != nil { return fmt.Errorf("failed to write unit fees: %w", err) } if s.persistedLastAccepted != s.lastAccepted { diff --git a/vms/avm/tx.go b/vms/avm/tx.go index 9f7f55f4745c..50670536313a 100644 --- a/vms/avm/tx.go +++ b/vms/avm/tx.go @@ -128,7 +128,7 @@ func (tx *Tx) Verify(context.Context) error { return fmt.Errorf("%w: %s", errTxNotProcessing, s) } - unitFees, err := tx.vm.state.GetUnitFees() + unitFees, err := tx.vm.state.GetFeeRates() if err != nil { return fmt.Errorf("failed retrieving unit fees: %w", err) } @@ -141,7 +141,7 @@ func (tx *Tx) Verify(context.Context) error { return tx.tx.Unsigned.Visit(&executor.SemanticVerifier{ Backend: tx.vm.txExecutorBackend, BlkFeeManager: feeManager, - UnitCaps: feeCfg.BlockUnitsCap, + UnitCaps: feeCfg.BlockMaxComplexity, State: tx.vm.state, Tx: tx.tx, }) diff --git a/vms/avm/tx_builders.go b/vms/avm/tx_builders.go index 198729048af9..1571e740ca07 100644 --- a/vms/avm/tx_builders.go +++ b/vms/avm/tx_builders.go @@ -44,7 +44,7 @@ func buildCreateAssetTx( kc *secp256k1fx.Keychain, changeAddr ids.ShortID, ) (*txs.Tx, ids.ShortID, error) { - unitFees, err := backend.State().GetUnitFees() + unitFees, err := backend.State().GetFeeRates() if err != nil { return nil, ids.ShortEmpty, fmt.Errorf("failed retrieving unit fees: %w", err) } @@ -60,7 +60,7 @@ func buildCreateAssetTx( IsEUpgradeActive: isEUpgradeActive, Config: cfg, FeeManager: feeMan, - ConsumedUnitsCap: feeCfg.BlockUnitsCap, + ConsumedUnitsCap: feeCfg.BlockMaxComplexity, Codec: backend.Codec(), } ) @@ -92,7 +92,7 @@ func buildBaseTx( kc *secp256k1fx.Keychain, changeAddr ids.ShortID, ) (*txs.Tx, ids.ShortID, error) { - unitFees, err := backend.State().GetUnitFees() + unitFees, err := backend.State().GetFeeRates() if err != nil { return nil, ids.ShortEmpty, fmt.Errorf("failed retrieving unit fees: %w", err) } @@ -108,7 +108,7 @@ func buildBaseTx( IsEUpgradeActive: isEUpgradeActive, Config: cfg, FeeManager: feeMan, - ConsumedUnitsCap: feeCfg.BlockUnitsCap, + ConsumedUnitsCap: feeCfg.BlockMaxComplexity, Codec: backend.Codec(), } ) @@ -138,7 +138,7 @@ func mintNFT( kc *secp256k1fx.Keychain, changeAddr ids.ShortID, ) (*txs.Tx, error) { - unitFees, err := backend.State().GetUnitFees() + unitFees, err := backend.State().GetFeeRates() if err != nil { return nil, fmt.Errorf("failed retrieving unit fees: %w", err) } @@ -154,7 +154,7 @@ func mintNFT( IsEUpgradeActive: isEUpgradeActive, Config: cfg, FeeManager: feeMan, - ConsumedUnitsCap: feeCfg.BlockUnitsCap, + ConsumedUnitsCap: feeCfg.BlockMaxComplexity, Codec: backend.Codec(), } ) @@ -179,7 +179,7 @@ func mintFTs( kc *secp256k1fx.Keychain, changeAddr ids.ShortID, ) (*txs.Tx, error) { - unitFees, err := backend.State().GetUnitFees() + unitFees, err := backend.State().GetFeeRates() if err != nil { return nil, fmt.Errorf("failed retrieving unit fees: %w", err) } @@ -195,7 +195,7 @@ func mintFTs( IsEUpgradeActive: isEUpgradeActive, Config: cfg, FeeManager: feeMan, - ConsumedUnitsCap: feeCfg.BlockUnitsCap, + ConsumedUnitsCap: feeCfg.BlockMaxComplexity, Codec: backend.Codec(), } ) @@ -217,7 +217,7 @@ func buildOperation( kc *secp256k1fx.Keychain, changeAddr ids.ShortID, ) (*txs.Tx, error) { - unitFees, err := backend.State().GetUnitFees() + unitFees, err := backend.State().GetFeeRates() if err != nil { return nil, fmt.Errorf("failed retrieving unit fees: %w", err) } @@ -233,7 +233,7 @@ func buildOperation( IsEUpgradeActive: isEUpgradeActive, Config: cfg, FeeManager: feeMan, - ConsumedUnitsCap: feeCfg.BlockUnitsCap, + ConsumedUnitsCap: feeCfg.BlockMaxComplexity, Codec: backend.Codec(), } ) @@ -256,7 +256,7 @@ func buildImportTx( to ids.ShortID, kc *secp256k1fx.Keychain, ) (*txs.Tx, error) { - unitFees, err := backend.State().GetUnitFees() + unitFees, err := backend.State().GetFeeRates() if err != nil { return nil, fmt.Errorf("failed retrieving unit fees: %w", err) } @@ -272,7 +272,7 @@ func buildImportTx( IsEUpgradeActive: isEUpgradeActive, Config: cfg, FeeManager: feeMan, - ConsumedUnitsCap: feeCfg.BlockUnitsCap, + ConsumedUnitsCap: feeCfg.BlockMaxComplexity, Codec: backend.Codec(), } ) @@ -304,7 +304,7 @@ func buildExportTx( kc *secp256k1fx.Keychain, changeAddr ids.ShortID, ) (*txs.Tx, ids.ShortID, error) { - unitFees, err := backend.State().GetUnitFees() + unitFees, err := backend.State().GetFeeRates() if err != nil { return nil, ids.ShortEmpty, fmt.Errorf("failed retrieving unit fees: %w", err) } @@ -320,7 +320,7 @@ func buildExportTx( IsEUpgradeActive: isEUpgradeActive, Config: cfg, FeeManager: feeMan, - ConsumedUnitsCap: feeCfg.BlockUnitsCap, + ConsumedUnitsCap: feeCfg.BlockMaxComplexity, Codec: backend.Codec(), } ) diff --git a/vms/avm/txs/executor/semantic_verifier_test.go b/vms/avm/txs/executor/semantic_verifier_test.go index e860f291aa57..7d346c16f482 100644 --- a/vms/avm/txs/executor/semantic_verifier_test.go +++ b/vms/avm/txs/executor/semantic_verifier_test.go @@ -743,8 +743,8 @@ func TestSemanticVerifierBaseTx(t *testing.T) { err = tx.Unsigned.Visit(&SemanticVerifier{ Backend: backend, - BlkFeeManager: fees.NewManager(feeCfg.InitialUnitFees), - UnitCaps: feeCfg.BlockUnitsCap, + BlkFeeManager: fees.NewManager(feeCfg.InitialFeeRate), + UnitCaps: feeCfg.BlockMaxComplexity, State: state, Tx: tx, }) @@ -1497,8 +1497,8 @@ func TestSemanticVerifierExportTx(t *testing.T) { err = tx.Unsigned.Visit(&SemanticVerifier{ Backend: backend, - BlkFeeManager: fees.NewManager(feeCfg.InitialUnitFees), - UnitCaps: feeCfg.BlockUnitsCap, + BlkFeeManager: fees.NewManager(feeCfg.InitialFeeRate), + UnitCaps: feeCfg.BlockMaxComplexity, State: state, Tx: tx, }) @@ -1642,8 +1642,8 @@ func TestSemanticVerifierExportTxDifferentSubnet(t *testing.T) { err = tx.Unsigned.Visit(&SemanticVerifier{ Backend: backend, - BlkFeeManager: fees.NewManager(feeCfg.InitialUnitFees), - UnitCaps: feeCfg.BlockUnitsCap, + BlkFeeManager: fees.NewManager(feeCfg.InitialFeeRate), + UnitCaps: feeCfg.BlockMaxComplexity, State: state, Tx: tx, }) @@ -2180,8 +2180,8 @@ func TestSemanticVerifierImportTx(t *testing.T) { err = tx.Unsigned.Visit(&SemanticVerifier{ Backend: backend, - BlkFeeManager: fees.NewManager(feeCfg.InitialUnitFees), - UnitCaps: feeCfg.BlockUnitsCap, + BlkFeeManager: fees.NewManager(feeCfg.InitialFeeRate), + UnitCaps: feeCfg.BlockMaxComplexity, State: state, Tx: tx, }) diff --git a/vms/avm/txs/fees/calculator.go b/vms/avm/txs/fees/calculator.go index 2f672cf114bf..0ce55d3dc2ac 100644 --- a/vms/avm/txs/fees/calculator.go +++ b/vms/avm/txs/fees/calculator.go @@ -195,7 +195,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) } @@ -210,7 +210,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/avm/txs/fees/calculator_test.go b/vms/avm/txs/fees/calculator_test.go index 3faf1331d551..46b1487ca948 100644 --- a/vms/avm/txs/fees/calculator_test.go +++ b/vms/avm/txs/fees/calculator_test.go @@ -111,7 +111,7 @@ func TestBaseTxFees(t *testing.T) { 172, 1000, }, - fc.FeeManager.GetCumulatedUnits(), + fc.FeeManager.GetCumulatedComplexity(), ) }, }, @@ -229,7 +229,7 @@ func TestCreateAssetTxFees(t *testing.T) { 172, 1000, }, - fc.FeeManager.GetCumulatedUnits(), + fc.FeeManager.GetCumulatedComplexity(), ) }, }, @@ -347,7 +347,7 @@ func TestOperationTxFees(t *testing.T) { 172, 1000, }, - fc.FeeManager.GetCumulatedUnits(), + fc.FeeManager.GetCumulatedComplexity(), ) }, }, @@ -461,7 +461,7 @@ func TestImportTxFees(t *testing.T) { 262, 2000, }, - fc.FeeManager.GetCumulatedUnits(), + fc.FeeManager.GetCumulatedComplexity(), ) }, }, @@ -565,7 +565,7 @@ func TestExportTxFees(t *testing.T) { 254, 1000, }, - fc.FeeManager.GetCumulatedUnits(), + fc.FeeManager.GetCumulatedComplexity(), ) }, }, 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/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] { diff --git a/vms/components/fees/manager.go b/vms/components/fees/manager.go index 8fc2344e4547..269503ddabac 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]) + nextFeeRates := nextFeeRate( + m.feeRates[i], + feesConfig.UpdateCoefficient[i], + parentBlkComplexity[i], + feesConfig.BlockTargetComplexityRate[i], + elapsedTime, + ) + nextFeeRates = max(nextFeeRates, feesConfig.MinFeeRate[i]) + m.feeRates[i] = nextFeeRates } + 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<= 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)) -} diff --git a/wallet/chain/x/wallet.go b/wallet/chain/x/wallet.go index 0a3d9b644c8d..61c28b7aff49 100644 --- a/wallet/chain/x/wallet.go +++ b/wallet/chain/x/wallet.go @@ -171,7 +171,7 @@ type wallet struct { client avm.Client isEForkActive bool - unitFees, unitCaps commonfees.Dimensions + feeRates, unitCaps commonfees.Dimensions } func (w *wallet) Builder() builder.Builder { @@ -191,7 +191,7 @@ func (w *wallet) IssueBaseTx( } var ( - feesMan = commonfees.NewManager(w.unitFees) + feesMan = commonfees.NewManager(w.feeRates) feeCalc = &fees.Calculator{ IsEUpgradeActive: w.isEForkActive, Config: &config.Config{ @@ -222,7 +222,7 @@ func (w *wallet) IssueCreateAssetTx( } var ( - feesMan = commonfees.NewManager(w.unitFees) + feesMan = commonfees.NewManager(w.feeRates) feeCalc = &fees.Calculator{ IsEUpgradeActive: w.isEForkActive, Config: &config.Config{ @@ -250,7 +250,7 @@ func (w *wallet) IssueOperationTx( } var ( - feesMan = commonfees.NewManager(w.unitFees) + feesMan = commonfees.NewManager(w.feeRates) feeCalc = &fees.Calculator{ IsEUpgradeActive: w.isEForkActive, Config: &config.Config{ @@ -278,7 +278,7 @@ func (w *wallet) IssueOperationTxMintFT( } var ( - feesMan = commonfees.NewManager(w.unitFees) + feesMan = commonfees.NewManager(w.feeRates) feeCalc = &fees.Calculator{ IsEUpgradeActive: w.isEForkActive, Config: &config.Config{ @@ -308,7 +308,7 @@ func (w *wallet) IssueOperationTxMintNFT( } var ( - feesMan = commonfees.NewManager(w.unitFees) + feesMan = commonfees.NewManager(w.feeRates) feeCalc = &fees.Calculator{ IsEUpgradeActive: w.isEForkActive, Config: &config.Config{ @@ -337,7 +337,7 @@ func (w *wallet) IssueOperationTxMintProperty( } var ( - feesMan = commonfees.NewManager(w.unitFees) + feesMan = commonfees.NewManager(w.feeRates) feeCalc = &fees.Calculator{ IsEUpgradeActive: w.isEForkActive, Config: &config.Config{ @@ -365,7 +365,7 @@ func (w *wallet) IssueOperationTxBurnProperty( } var ( - feesMan = commonfees.NewManager(w.unitFees) + feesMan = commonfees.NewManager(w.feeRates) feeCalc = &fees.Calculator{ IsEUpgradeActive: w.isEForkActive, Config: &config.Config{ @@ -394,7 +394,7 @@ func (w *wallet) IssueImportTx( } var ( - feesMan = commonfees.NewManager(w.unitFees) + feesMan = commonfees.NewManager(w.feeRates) feeCalc = &fees.Calculator{ IsEUpgradeActive: w.isEForkActive, Config: &config.Config{ @@ -423,7 +423,7 @@ func (w *wallet) IssueExportTx( } var ( - feesMan = commonfees.NewManager(w.unitFees) + feesMan = commonfees.NewManager(w.feeRates) feeCalc = &fees.Calculator{ IsEUpgradeActive: w.isEForkActive, Config: &config.Config{ @@ -503,7 +503,7 @@ func (w *wallet) refreshFork(options ...common.Option) error { err error ) - _, w.unitFees, err = w.client.GetUnitFees(ctx) + _, w.feeRates, err = w.client.GetFeeRates(ctx) if err != nil { return err } @@ -517,6 +517,6 @@ func (w *wallet) refreshFork(options ...common.Option) error { // } chainTime := mockable.MaxTime // assume fork is already active w.isEForkActive = !chainTime.Before(eUpgradeTime) - w.unitCaps = config.GetDynamicFeesConfig(w.isEForkActive).BlockUnitsCap + w.unitCaps = config.GetDynamicFeesConfig(w.isEForkActive).BlockMaxComplexity return nil } From e3018a8115d77e79e7a98be7cec6fe444d416243 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Fri, 22 Mar 2024 10:29:23 +0100 Subject: [PATCH 121/132] renaming for clarify --- vms/avm/block/builder/builder.go | 2 +- vms/avm/block/executor/block.go | 2 +- vms/avm/block/executor/manager.go | 6 ++--- vms/avm/client.go | 2 +- vms/avm/service.go | 18 +++++++-------- vms/avm/state/diff.go | 30 ++++++++++++------------- vms/avm/state/state.go | 28 ++++++++++++------------ vms/avm/tx.go | 6 ++--- vms/avm/tx_builders.go | 28 ++++++++++++------------ vms/avm/txs/fees/calculator_test.go | 12 +++++----- wallet/chain/x/builder_test.go | 34 ++++++++++++++--------------- 11 files changed, 84 insertions(+), 84 deletions(-) diff --git a/vms/avm/block/builder/builder.go b/vms/avm/block/builder/builder.go index 1d4a06b552b1..1043022a8efa 100644 --- a/vms/avm/block/builder/builder.go +++ b/vms/avm/block/builder/builder.go @@ -102,7 +102,7 @@ func (b *builder) BuildBlock(context.Context) (snowman.Block, error) { } parentBlkComplexity, err := stateDiff.GetLastBlockComplexity() if err != nil { - return nil, fmt.Errorf("failed retrieving fee windows: %w", err) + return nil, fmt.Errorf("failed retrieving last block complexity: %w", err) } feeManager := fees.NewManager(feeRates) diff --git a/vms/avm/block/executor/block.go b/vms/avm/block/executor/block.go index 8a853b4a6a6c..893169fc2555 100644 --- a/vms/avm/block/executor/block.go +++ b/vms/avm/block/executor/block.go @@ -138,7 +138,7 @@ func (b *Block) Verify(context.Context) error { } parentBlkComplexitty, err := stateDiff.GetLastBlockComplexity() if err != nil { - return fmt.Errorf("failed retrieving fee windows: %w", err) + return fmt.Errorf("failed retrieving last block complexity: %w", err) } var ( diff --git a/vms/avm/block/executor/manager.go b/vms/avm/block/executor/manager.go index 7029f52cd509..b14cdc299663 100644 --- a/vms/avm/block/executor/manager.go +++ b/vms/avm/block/executor/manager.go @@ -175,9 +175,9 @@ func (m *manager) VerifyTx(tx *txs.Tx) error { if err != nil { return fmt.Errorf("failed retrieving unit fees: %w", err) } - feeWindows, err := stateDiff.GetLastBlockComplexity() + parentBlkComplexity, err := stateDiff.GetLastBlockComplexity() if err != nil { - return fmt.Errorf("failed retrieving fee windows: %w", err) + return fmt.Errorf("failed retrieving last block complexity: %w", err) } var ( @@ -189,7 +189,7 @@ func (m *manager) VerifyTx(tx *txs.Tx) error { if isEForkActive { if err := feeManager.UpdateFeeRates( feesCfg, - feeWindows, + parentBlkComplexity, parentBlkTime.Unix(), nextBlkTime.Unix(), ); err != nil { diff --git a/vms/avm/client.go b/vms/avm/client.go index ececf2618baf..2858143eef9d 100644 --- a/vms/avm/client.go +++ b/vms/avm/client.go @@ -413,7 +413,7 @@ func (c *client) GetAllBalances( func (c *client) GetFeeRates(ctx context.Context, options ...rpc.Option) (commonfees.Dimensions, commonfees.Dimensions, error) { res := &GetFeeRatesReply{} err := c.requester.SendRequest(ctx, "avm.getFeeRates", struct{}{}, res, options...) - return res.CurrentUnitFees, res.NextUnitFees, err + return res.CurrentFeeRates, res.NextFeeRates, err } // ClientHolder describes how much an address owns of an asset diff --git a/vms/avm/service.go b/vms/avm/service.go index a30a1bb65531..b406739b4d1f 100644 --- a/vms/avm/service.go +++ b/vms/avm/service.go @@ -678,8 +678,8 @@ func (s *Service) GetAllBalances(_ *http.Request, args *GetAllBalancesArgs, repl // GetFeeRatesReply is the response from GetFeeRates type GetFeeRatesReply struct { - CurrentUnitFees commonfees.Dimensions `json:"currentUnitFees"` - NextUnitFees commonfees.Dimensions `json:"nextUnitFees"` + CurrentFeeRates commonfees.Dimensions `json:"currentFeeRates"` + NextFeeRates commonfees.Dimensions `json:"nextFeesRates"` } // GetTimestamp returns the current timestamp on chain. @@ -698,17 +698,17 @@ func (s *Service) GetFeeRates(_ *http.Request, _ *struct{}, reply *GetFeeRatesRe return fmt.Errorf("could not retrieve state for block %s", preferredID) } - currentUnitFees, err := onAccept.GetFeeRates() + currentFeeRates, err := onAccept.GetFeeRates() if err != nil { return err } - reply.CurrentUnitFees = currentUnitFees + reply.CurrentFeeRates = currentFeeRates nextTimestamp := executor.NextBlockTime(onAccept.GetTimestamp(), &s.vm.clock) isEActivated := s.vm.Config.IsEActivated(nextTimestamp) if !isEActivated { - reply.NextUnitFees = reply.CurrentUnitFees + reply.NextFeeRates = reply.CurrentFeeRates return nil } @@ -717,23 +717,23 @@ func (s *Service) GetFeeRates(_ *http.Request, _ *struct{}, reply *GetFeeRatesRe feesCfg = config.GetDynamicFeesConfig(isEActivated) ) - feeWindows, err := onAccept.GetLastBlockComplexity() + parentBlkComplexity, err := onAccept.GetLastBlockComplexity() if err != nil { return err } - feeManager := commonfees.NewManager(currentUnitFees) + feeManager := commonfees.NewManager(currentFeeRates) if isEActivated { 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.GetFeeRates() + reply.NextFeeRates = feeManager.GetFeeRates() return nil } diff --git a/vms/avm/state/diff.go b/vms/avm/state/diff.go index ffdae17b90c6..bdcca0e9c8bd 100644 --- a/vms/avm/state/diff.go +++ b/vms/avm/state/diff.go @@ -42,7 +42,7 @@ type diff struct { lastAccepted ids.ID timestamp time.Time - unitFees *commonfees.Dimensions + feeRates *commonfees.Dimensions lastBlkComplexity *commonfees.Dimensions } @@ -166,28 +166,28 @@ func (d *diff) SetTimestamp(t time.Time) { } func (d *diff) GetFeeRates() (commonfees.Dimensions, error) { - if d.unitFees == nil { + 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.GetFeeRates() + parentFeeRates, 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 = parentFeeRates } - return *d.unitFees, nil + return *d.feeRates, nil } func (d *diff) SetFeeRates(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) GetLastBlockComplexity() (commonfees.Dimensions, error) { @@ -196,23 +196,23 @@ func (d *diff) GetLastBlockComplexity() (commonfees.Dimensions, error) { if !ok { return commonfees.Empty, fmt.Errorf("%w: %s", ErrMissingParentState, d.parentID) } - parentFeeWindows, err := parentState.GetLastBlockComplexity() + parentBlkComplexity, err := parentState.GetLastBlockComplexity() if err != nil { return commonfees.Empty, err } d.lastBlkComplexity = new(commonfees.Dimensions) - *d.lastBlkComplexity = parentFeeWindows + *d.lastBlkComplexity = parentBlkComplexity } return *d.lastBlkComplexity, nil } -func (d *diff) SetLastBlockComplexity(windows commonfees.Dimensions) { +func (d *diff) SetLastBlockComplexity(complexity commonfees.Dimensions) { if d.lastBlkComplexity == nil { d.lastBlkComplexity = new(commonfees.Dimensions) } - *d.lastBlkComplexity = windows + *d.lastBlkComplexity = complexity } func (d *diff) Apply(state Chain) { @@ -234,8 +234,8 @@ func (d *diff) Apply(state Chain) { state.SetLastAccepted(d.lastAccepted) state.SetTimestamp(d.timestamp) - if d.unitFees != nil { - state.SetFeeRates(*d.unitFees) + if d.feeRates != nil { + state.SetFeeRates(*d.feeRates) } if d.lastBlkComplexity != nil { state.SetLastBlockComplexity(*d.lastBlkComplexity) diff --git a/vms/avm/state/state.go b/vms/avm/state/state.go index 1c7f7f2ceb82..97dbb6905f18 100644 --- a/vms/avm/state/state.go +++ b/vms/avm/state/state.go @@ -37,11 +37,11 @@ var ( blockPrefix = []byte("block") singletonPrefix = []byte("singleton") - isInitializedKey = []byte{0x00} - timestampKey = []byte{0x01} - lastAcceptedKey = []byte{0x02} - unitFeesKey = []byte{0x03} - feesWindowsKey = []byte{0x04} + isInitializedKey = []byte{0x00} + timestampKey = []byte{0x01} + lastAcceptedKey = []byte{0x02} + feeRatesKey = []byte{0x03} + lastBlkComplexityKey = []byte{0x04} _ State = (*state)(nil) ) @@ -69,8 +69,8 @@ type Chain interface { SetLastAccepted(blkID ids.ID) SetTimestamp(t time.Time) - SetFeeRates(uf commonfees.Dimensions) - SetLastBlockComplexity(windows commonfees.Dimensions) + SetFeeRates(commonfees.Dimensions) + SetLastBlockComplexity(commonfees.Dimensions) } // State persistently maintains a set of UTXOs, transaction, statuses, and @@ -364,9 +364,9 @@ func (s *state) InitializeChainState(stopVertexID ids.ID, genesisTimestamp time. } func (s *state) InitFees() error { - switch unitFeesBytes, err := s.singletonDB.Get(unitFeesKey); err { + switch feeRatesBytes, err := s.singletonDB.Get(feeRatesKey); err { case nil: - if err := s.feeRates.FromBytes(unitFeesBytes); err != nil { + if err := s.feeRates.FromBytes(feeRatesBytes); err != nil { return err } @@ -382,15 +382,15 @@ func (s *state) InitFees() error { return err } - switch feesWindowsBytes, err := s.singletonDB.Get(feesWindowsKey); err { + switch lastBlkComplexityBytes, err := s.singletonDB.Get(lastBlkComplexityKey); err { case nil: - if err := s.lastBlkComplexity.FromBytes(feesWindowsBytes); err != nil { + if err := s.lastBlkComplexity.FromBytes(lastBlkComplexityBytes); 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 + // hence we may have never stored block complexities. Set to nil // TODO: remove once fork is active s.lastBlkComplexity = commonfees.Empty @@ -565,10 +565,10 @@ func (s *state) writeMetadata() error { } s.persistedTimestamp = s.timestamp } - if err := s.singletonDB.Put(unitFeesKey, s.feeRates.Bytes()); err != nil { + if err := s.singletonDB.Put(feeRatesKey, s.feeRates.Bytes()); err != nil { return fmt.Errorf("failed to write unit fees: %w", err) } - if err := s.singletonDB.Put(feesWindowsKey, s.lastBlkComplexity.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.persistedLastAccepted != s.lastAccepted { diff --git a/vms/avm/tx.go b/vms/avm/tx.go index 50670536313a..15b1fad9e9c0 100644 --- a/vms/avm/tx.go +++ b/vms/avm/tx.go @@ -128,15 +128,15 @@ func (tx *Tx) Verify(context.Context) error { return fmt.Errorf("%w: %s", errTxNotProcessing, s) } - unitFees, err := tx.vm.state.GetFeeRates() + feeRates, err := tx.vm.state.GetFeeRates() if err != nil { - return fmt.Errorf("failed retrieving unit fees: %w", err) + return fmt.Errorf("failed retrieving fee rates: %w", err) } var ( isEActivated = tx.vm.txExecutorBackend.Config.IsEActivated(tx.vm.state.GetTimestamp()) feeCfg = config.GetDynamicFeesConfig(isEActivated) - feeManager = fees.NewManager(unitFees) + feeManager = fees.NewManager(feeRates) ) return tx.tx.Unsigned.Visit(&executor.SemanticVerifier{ Backend: tx.vm.txExecutorBackend, diff --git a/vms/avm/tx_builders.go b/vms/avm/tx_builders.go index 1571e740ca07..abe432206601 100644 --- a/vms/avm/tx_builders.go +++ b/vms/avm/tx_builders.go @@ -44,7 +44,7 @@ func buildCreateAssetTx( kc *secp256k1fx.Keychain, changeAddr ids.ShortID, ) (*txs.Tx, ids.ShortID, error) { - unitFees, err := backend.State().GetFeeRates() + feeRates, err := backend.State().GetFeeRates() if err != nil { return nil, ids.ShortEmpty, fmt.Errorf("failed retrieving unit fees: %w", err) } @@ -55,7 +55,7 @@ func buildCreateAssetTx( cfg = backend.Config() isEUpgradeActive = cfg.IsEActivated(chainTime) feeCfg = config.GetDynamicFeesConfig(isEUpgradeActive) - feeMan = commonfees.NewManager(unitFees) + feeMan = commonfees.NewManager(feeRates) feeCalc = &fees.Calculator{ IsEUpgradeActive: isEUpgradeActive, Config: cfg, @@ -92,7 +92,7 @@ func buildBaseTx( kc *secp256k1fx.Keychain, changeAddr ids.ShortID, ) (*txs.Tx, ids.ShortID, error) { - unitFees, err := backend.State().GetFeeRates() + feeRates, err := backend.State().GetFeeRates() if err != nil { return nil, ids.ShortEmpty, fmt.Errorf("failed retrieving unit fees: %w", err) } @@ -103,7 +103,7 @@ func buildBaseTx( cfg = backend.Config() isEUpgradeActive = cfg.IsEActivated(chainTime) feeCfg = config.GetDynamicFeesConfig(isEUpgradeActive) - feeMan = commonfees.NewManager(unitFees) + feeMan = commonfees.NewManager(feeRates) feeCalc = &fees.Calculator{ IsEUpgradeActive: isEUpgradeActive, Config: cfg, @@ -138,7 +138,7 @@ func mintNFT( kc *secp256k1fx.Keychain, changeAddr ids.ShortID, ) (*txs.Tx, error) { - unitFees, err := backend.State().GetFeeRates() + feeRates, err := backend.State().GetFeeRates() if err != nil { return nil, fmt.Errorf("failed retrieving unit fees: %w", err) } @@ -149,7 +149,7 @@ func mintNFT( cfg = backend.Config() isEUpgradeActive = cfg.IsEActivated(chainTime) feeCfg = config.GetDynamicFeesConfig(isEUpgradeActive) - feeMan = commonfees.NewManager(unitFees) + feeMan = commonfees.NewManager(feeRates) feeCalc = &fees.Calculator{ IsEUpgradeActive: isEUpgradeActive, Config: cfg, @@ -179,7 +179,7 @@ func mintFTs( kc *secp256k1fx.Keychain, changeAddr ids.ShortID, ) (*txs.Tx, error) { - unitFees, err := backend.State().GetFeeRates() + feeRates, err := backend.State().GetFeeRates() if err != nil { return nil, fmt.Errorf("failed retrieving unit fees: %w", err) } @@ -190,7 +190,7 @@ func mintFTs( cfg = backend.Config() isEUpgradeActive = cfg.IsEActivated(chainTime) feeCfg = config.GetDynamicFeesConfig(isEUpgradeActive) - feeMan = commonfees.NewManager(unitFees) + feeMan = commonfees.NewManager(feeRates) feeCalc = &fees.Calculator{ IsEUpgradeActive: isEUpgradeActive, Config: cfg, @@ -217,7 +217,7 @@ func buildOperation( kc *secp256k1fx.Keychain, changeAddr ids.ShortID, ) (*txs.Tx, error) { - unitFees, err := backend.State().GetFeeRates() + feeRates, err := backend.State().GetFeeRates() if err != nil { return nil, fmt.Errorf("failed retrieving unit fees: %w", err) } @@ -228,7 +228,7 @@ func buildOperation( cfg = backend.Config() isEUpgradeActive = cfg.IsEActivated(chainTime) feeCfg = config.GetDynamicFeesConfig(isEUpgradeActive) - feeMan = commonfees.NewManager(unitFees) + feeMan = commonfees.NewManager(feeRates) feeCalc = &fees.Calculator{ IsEUpgradeActive: isEUpgradeActive, Config: cfg, @@ -256,7 +256,7 @@ func buildImportTx( to ids.ShortID, kc *secp256k1fx.Keychain, ) (*txs.Tx, error) { - unitFees, err := backend.State().GetFeeRates() + feeRates, err := backend.State().GetFeeRates() if err != nil { return nil, fmt.Errorf("failed retrieving unit fees: %w", err) } @@ -267,7 +267,7 @@ func buildImportTx( cfg = backend.Config() isEUpgradeActive = cfg.IsEActivated(chainTime) feeCfg = config.GetDynamicFeesConfig(isEUpgradeActive) - feeMan = commonfees.NewManager(unitFees) + feeMan = commonfees.NewManager(feeRates) feeCalc = &fees.Calculator{ IsEUpgradeActive: isEUpgradeActive, Config: cfg, @@ -304,7 +304,7 @@ func buildExportTx( kc *secp256k1fx.Keychain, changeAddr ids.ShortID, ) (*txs.Tx, ids.ShortID, error) { - unitFees, err := backend.State().GetFeeRates() + feeRates, err := backend.State().GetFeeRates() if err != nil { return nil, ids.ShortEmpty, fmt.Errorf("failed retrieving unit fees: %w", err) } @@ -315,7 +315,7 @@ func buildExportTx( cfg = backend.Config() isEUpgradeActive = cfg.IsEActivated(chainTime) feeCfg = config.GetDynamicFeesConfig(isEUpgradeActive) - feeMan = commonfees.NewManager(unitFees) + feeMan = commonfees.NewManager(feeRates) feeCalc = &fees.Calculator{ IsEUpgradeActive: isEUpgradeActive, Config: cfg, diff --git a/vms/avm/txs/fees/calculator_test.go b/vms/avm/txs/fees/calculator_test.go index 46b1487ca948..f425070ac543 100644 --- a/vms/avm/txs/fees/calculator_test.go +++ b/vms/avm/txs/fees/calculator_test.go @@ -29,7 +29,7 @@ import ( ) var ( - testUnitFees = fees.Dimensions{ + testFeeRates = fees.Dimensions{ 1 * units.MicroAvax, 2 * units.MicroAvax, 3 * units.MicroAvax, @@ -148,7 +148,7 @@ func TestBaseTxFees(t *testing.T) { IsEUpgradeActive: cfg.IsEActivated(chainTime), Config: cfg, Codec: codec, - FeeManager: fees.NewManager(testUnitFees), + FeeManager: fees.NewManager(testFeeRates), ConsumedUnitsCap: consumedUnitCaps, Credentials: sTx.Creds, } @@ -266,7 +266,7 @@ func TestCreateAssetTxFees(t *testing.T) { IsEUpgradeActive: cfg.IsEActivated(chainTime), Config: cfg, Codec: codec, - FeeManager: fees.NewManager(testUnitFees), + FeeManager: fees.NewManager(testFeeRates), ConsumedUnitsCap: consumedUnitCaps, Credentials: sTx.Creds, } @@ -384,7 +384,7 @@ func TestOperationTxFees(t *testing.T) { IsEUpgradeActive: cfg.IsEActivated(chainTime), Config: cfg, Codec: codec, - FeeManager: fees.NewManager(testUnitFees), + FeeManager: fees.NewManager(testFeeRates), ConsumedUnitsCap: consumedUnitCaps, Credentials: sTx.Creds, } @@ -498,7 +498,7 @@ func TestImportTxFees(t *testing.T) { IsEUpgradeActive: cfg.IsEActivated(chainTime), Config: cfg, Codec: codec, - FeeManager: fees.NewManager(testUnitFees), + FeeManager: fees.NewManager(testFeeRates), ConsumedUnitsCap: consumedUnitCaps, Credentials: sTx.Creds, } @@ -602,7 +602,7 @@ func TestExportTxFees(t *testing.T) { IsEUpgradeActive: cfg.IsEActivated(chainTime), Config: cfg, Codec: codec, - FeeManager: fees.NewManager(testUnitFees), + FeeManager: fees.NewManager(testFeeRates), ConsumedUnitsCap: consumedUnitCaps, Credentials: sTx.Creds, } diff --git a/wallet/chain/x/builder_test.go b/wallet/chain/x/builder_test.go index 3bf5e1f202b6..541d1776d84b 100644 --- a/wallet/chain/x/builder_test.go +++ b/wallet/chain/x/builder_test.go @@ -46,7 +46,7 @@ var ( CreateAssetTxFee: 99 * units.MilliAvax, } - testUnitFees = commonfees.Dimensions{ + testFeeRates = commonfees.Dimensions{ 1 * units.MicroAvax, 2 * units.MicroAvax, 3 * units.MicroAvax, @@ -95,7 +95,7 @@ func TestBaseTx(t *testing.T) { { // Post E-Upgrade feeCalc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees), + FeeManager: commonfees.NewManager(testFeeRates), ConsumedUnitsCap: testBlockMaxConsumedUnits, Codec: builder.Parser.Codec(), } @@ -110,7 +110,7 @@ func TestBaseTx(t *testing.T) { fc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees), + FeeManager: commonfees.NewManager(testFeeRates), ConsumedUnitsCap: testBlockMaxConsumedUnits, Credentials: tx.Creds, Codec: builder.Parser.Codec(), @@ -251,7 +251,7 @@ func TestCreateAssetTx(t *testing.T) { // Post E-Upgrade feeCalc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees), + FeeManager: commonfees.NewManager(testFeeRates), ConsumedUnitsCap: testBlockMaxConsumedUnits, Codec: builder.Parser.Codec(), } @@ -270,7 +270,7 @@ func TestCreateAssetTx(t *testing.T) { fc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees), + FeeManager: commonfees.NewManager(testFeeRates), ConsumedUnitsCap: testBlockMaxConsumedUnits, Codec: builder.Parser.Codec(), Credentials: tx.Creds, @@ -369,7 +369,7 @@ func TestMintNFTOperation(t *testing.T) { // Post E-Upgrade feeCalc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees), + FeeManager: commonfees.NewManager(testFeeRates), ConsumedUnitsCap: testBlockMaxConsumedUnits, Codec: builder.Parser.Codec(), } @@ -387,7 +387,7 @@ func TestMintNFTOperation(t *testing.T) { fc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees), + FeeManager: commonfees.NewManager(testFeeRates), ConsumedUnitsCap: testBlockMaxConsumedUnits, Codec: builder.Parser.Codec(), Credentials: tx.Creds, @@ -491,7 +491,7 @@ func TestMintFTOperation(t *testing.T) { // Post E-Upgrade feeCalc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees), + FeeManager: commonfees.NewManager(testFeeRates), ConsumedUnitsCap: testBlockMaxConsumedUnits, Codec: builder.Parser.Codec(), } @@ -507,7 +507,7 @@ func TestMintFTOperation(t *testing.T) { fc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees), + FeeManager: commonfees.NewManager(testFeeRates), ConsumedUnitsCap: testBlockMaxConsumedUnits, Codec: builder.Parser.Codec(), Credentials: tx.Creds, @@ -604,7 +604,7 @@ func TestMintPropertyOperation(t *testing.T) { // Post E-Upgrade feeCalc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees), + FeeManager: commonfees.NewManager(testFeeRates), ConsumedUnitsCap: testBlockMaxConsumedUnits, Codec: builder.Parser.Codec(), } @@ -621,7 +621,7 @@ func TestMintPropertyOperation(t *testing.T) { fc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees), + FeeManager: commonfees.NewManager(testFeeRates), ConsumedUnitsCap: testBlockMaxConsumedUnits, Codec: builder.Parser.Codec(), Credentials: tx.Creds, @@ -713,7 +713,7 @@ func TestBurnPropertyOperation(t *testing.T) { // Post E-Upgrade feeCalc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees), + FeeManager: commonfees.NewManager(testFeeRates), ConsumedUnitsCap: testBlockMaxConsumedUnits, Codec: builder.Parser.Codec(), } @@ -729,7 +729,7 @@ func TestBurnPropertyOperation(t *testing.T) { fc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees), + FeeManager: commonfees.NewManager(testFeeRates), ConsumedUnitsCap: testBlockMaxConsumedUnits, Codec: builder.Parser.Codec(), Credentials: tx.Creds, @@ -832,7 +832,7 @@ func TestImportTx(t *testing.T) { { // Post E-Upgrade feeCalc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees), + FeeManager: commonfees.NewManager(testFeeRates), ConsumedUnitsCap: testBlockMaxConsumedUnits, Codec: builder.Parser.Codec(), } @@ -848,7 +848,7 @@ func TestImportTx(t *testing.T) { fc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees), + FeeManager: commonfees.NewManager(testFeeRates), ConsumedUnitsCap: testBlockMaxConsumedUnits, Credentials: tx.Creds, Codec: builder.Parser.Codec(), @@ -954,7 +954,7 @@ func TestExportTx(t *testing.T) { { // Post E-Upgrade feeCalc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees), + FeeManager: commonfees.NewManager(testFeeRates), ConsumedUnitsCap: testBlockMaxConsumedUnits, Codec: builder.Parser.Codec(), } @@ -970,7 +970,7 @@ func TestExportTx(t *testing.T) { fc := &fees.Calculator{ IsEUpgradeActive: true, - FeeManager: commonfees.NewManager(testUnitFees), + FeeManager: commonfees.NewManager(testFeeRates), ConsumedUnitsCap: testBlockMaxConsumedUnits, Credentials: tx.Creds, Codec: builder.Parser.Codec(), From cccf6cd2790ddb8ff9dce3a5e7d6b48ce7e4b50d Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Fri, 22 Mar 2024 13:54:10 +0100 Subject: [PATCH 122/132] some more naming cleanup --- vms/avm/block/builder/builder.go | 12 +++--- vms/avm/block/executor/block.go | 12 +++--- vms/avm/block/executor/manager.go | 12 +++--- vms/avm/client.go | 2 +- vms/avm/state/state.go | 6 +-- vms/avm/tx.go | 10 ++--- vms/avm/tx_builders.go | 14 +++---- vms/avm/txs/executor/semantic_verifier.go | 10 ++--- .../txs/executor/semantic_verifier_test.go | 40 +++++++++---------- 9 files changed, 59 insertions(+), 59 deletions(-) diff --git a/vms/avm/block/builder/builder.go b/vms/avm/block/builder/builder.go index 1043022a8efa..0e5ca1d07484 100644 --- a/vms/avm/block/builder/builder.go +++ b/vms/avm/block/builder/builder.go @@ -98,7 +98,7 @@ func (b *builder) BuildBlock(context.Context) (snowman.Block, error) { feeRates, err := stateDiff.GetFeeRates() if err != nil { - return nil, fmt.Errorf("failed retrieving unit fees: %w", err) + return nil, fmt.Errorf("failed retrieving fee rates: %w", err) } parentBlkComplexity, err := stateDiff.GetLastBlockComplexity() if err != nil { @@ -141,11 +141,11 @@ func (b *builder) BuildBlock(context.Context) (snowman.Block, error) { } err = tx.Unsigned.Visit(&txexecutor.SemanticVerifier{ - Backend: b.backend, - BlkFeeManager: feeManager, - UnitCaps: feesCfg.BlockMaxComplexity, - State: txDiff, - Tx: tx, + Backend: b.backend, + BlkFeeManager: feeManager, + BlockMaxComplexity: feesCfg.BlockMaxComplexity, + State: txDiff, + Tx: tx, }) if err != nil { txID := tx.ID() diff --git a/vms/avm/block/executor/block.go b/vms/avm/block/executor/block.go index 893169fc2555..9cb2d33ac52f 100644 --- a/vms/avm/block/executor/block.go +++ b/vms/avm/block/executor/block.go @@ -134,7 +134,7 @@ func (b *Block) Verify(context.Context) error { feeRates, err := stateDiff.GetFeeRates() if err != nil { - return fmt.Errorf("failed retrieving unit fees: %w", err) + return fmt.Errorf("failed retrieving fee rates: %w", err) } parentBlkComplexitty, err := stateDiff.GetLastBlockComplexity() if err != nil { @@ -162,11 +162,11 @@ func (b *Block) Verify(context.Context) error { // Verify that the tx is valid according to the current state of the // chain. err := tx.Unsigned.Visit(&executor.SemanticVerifier{ - Backend: b.manager.backend, - BlkFeeManager: feeManager, - UnitCaps: feesCfg.BlockMaxComplexity, - State: stateDiff, - Tx: tx, + Backend: b.manager.backend, + BlkFeeManager: feeManager, + BlockMaxComplexity: feesCfg.BlockMaxComplexity, + State: stateDiff, + 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 b14cdc299663..b920400e525f 100644 --- a/vms/avm/block/executor/manager.go +++ b/vms/avm/block/executor/manager.go @@ -173,7 +173,7 @@ func (m *manager) VerifyTx(tx *txs.Tx) error { feeRates, err := stateDiff.GetFeeRates() if err != nil { - return fmt.Errorf("failed retrieving unit fees: %w", err) + return fmt.Errorf("failed retrieving fee rates: %w", err) } parentBlkComplexity, err := stateDiff.GetLastBlockComplexity() if err != nil { @@ -198,11 +198,11 @@ func (m *manager) VerifyTx(tx *txs.Tx) error { } err = tx.Unsigned.Visit(&executor.SemanticVerifier{ - Backend: m.backend, - BlkFeeManager: feeManager, - UnitCaps: feesCfg.BlockMaxComplexity, - State: stateDiff, - Tx: tx, + Backend: m.backend, + BlkFeeManager: feeManager, + BlockMaxComplexity: feesCfg.BlockMaxComplexity, + State: stateDiff, + Tx: tx, }) if err != nil { return err diff --git a/vms/avm/client.go b/vms/avm/client.go index 2858143eef9d..49bfe05209a1 100644 --- a/vms/avm/client.go +++ b/vms/avm/client.go @@ -76,7 +76,7 @@ type Client interface { // // Deprecated: GetUTXOs should be used instead. GetAllBalances(ctx context.Context, addr ids.ShortID, includePartial bool, options ...rpc.Option) ([]Balance, error) - // GetFeeRates returns the current unit fees and the next unit fees that a transaction must pay to be accepted + // GetFeeRates returns the current fee rates and the next fee rates that a transaction must pay to be accepted GetFeeRates(ctx context.Context, options ...rpc.Option) (commonfees.Dimensions, commonfees.Dimensions, error) // CreateAsset creates a new asset and returns its assetID // diff --git a/vms/avm/state/state.go b/vms/avm/state/state.go index 97dbb6905f18..588fcff21a6a 100644 --- a/vms/avm/state/state.go +++ b/vms/avm/state/state.go @@ -372,7 +372,7 @@ func (s *state) InitFees() error { 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 isEActivated := s.cfg.IsEActivated(s.GetTimestamp()) feeCfg := config.GetDynamicFeesConfig(isEActivated) @@ -566,10 +566,10 @@ func (s *state) writeMetadata() error { s.persistedTimestamp = s.timestamp } if err := s.singletonDB.Put(feeRatesKey, s.feeRates.Bytes()); err != nil { - return fmt.Errorf("failed to write unit fees: %w", err) + 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.persistedLastAccepted != s.lastAccepted { if err := database.PutID(s.singletonDB, lastAcceptedKey, s.lastAccepted); err != nil { diff --git a/vms/avm/tx.go b/vms/avm/tx.go index 15b1fad9e9c0..a6d9e0e5881a 100644 --- a/vms/avm/tx.go +++ b/vms/avm/tx.go @@ -139,10 +139,10 @@ func (tx *Tx) Verify(context.Context) error { feeManager = fees.NewManager(feeRates) ) return tx.tx.Unsigned.Visit(&executor.SemanticVerifier{ - Backend: tx.vm.txExecutorBackend, - BlkFeeManager: feeManager, - UnitCaps: feeCfg.BlockMaxComplexity, - State: tx.vm.state, - Tx: tx.tx, + Backend: tx.vm.txExecutorBackend, + BlkFeeManager: feeManager, + BlockMaxComplexity: feeCfg.BlockMaxComplexity, + State: tx.vm.state, + Tx: tx.tx, }) } diff --git a/vms/avm/tx_builders.go b/vms/avm/tx_builders.go index 5ae65b9e0b65..0df9a2658a8c 100644 --- a/vms/avm/tx_builders.go +++ b/vms/avm/tx_builders.go @@ -46,7 +46,7 @@ func buildCreateAssetTx( ) (*txs.Tx, ids.ShortID, error) { feeRates, err := backend.State().GetFeeRates() if err != nil { - return nil, ids.ShortEmpty, fmt.Errorf("failed retrieving unit fees: %w", err) + return nil, ids.ShortEmpty, fmt.Errorf("failed retrieving fee rates: %w", err) } var ( @@ -94,7 +94,7 @@ func buildBaseTx( ) (*txs.Tx, ids.ShortID, error) { feeRates, err := backend.State().GetFeeRates() if err != nil { - return nil, ids.ShortEmpty, fmt.Errorf("failed retrieving unit fees: %w", err) + return nil, ids.ShortEmpty, fmt.Errorf("failed retrieving fee rates: %w", err) } var ( @@ -140,7 +140,7 @@ func mintNFT( ) (*txs.Tx, error) { feeRates, err := backend.State().GetFeeRates() if err != nil { - return nil, fmt.Errorf("failed retrieving unit fees: %w", err) + return nil, fmt.Errorf("failed retrieving fee rates: %w", err) } var ( @@ -181,7 +181,7 @@ func mintFTs( ) (*txs.Tx, error) { feeRates, err := backend.State().GetFeeRates() if err != nil { - return nil, fmt.Errorf("failed retrieving unit fees: %w", err) + return nil, fmt.Errorf("failed retrieving fee rates: %w", err) } var ( @@ -219,7 +219,7 @@ func buildOperation( ) (*txs.Tx, error) { feeRates, err := backend.State().GetFeeRates() if err != nil { - return nil, fmt.Errorf("failed retrieving unit fees: %w", err) + return nil, fmt.Errorf("failed retrieving fee rates: %w", err) } var ( @@ -258,7 +258,7 @@ func buildImportTx( ) (*txs.Tx, error) { feeRates, err := backend.State().GetFeeRates() if err != nil { - return nil, fmt.Errorf("failed retrieving unit fees: %w", err) + return nil, fmt.Errorf("failed retrieving fee rates: %w", err) } var ( @@ -306,7 +306,7 @@ func buildExportTx( ) (*txs.Tx, ids.ShortID, error) { feeRates, err := backend.State().GetFeeRates() if err != nil { - return nil, ids.ShortEmpty, fmt.Errorf("failed retrieving unit fees: %w", err) + return nil, ids.ShortEmpty, fmt.Errorf("failed retrieving fee rates: %w", err) } var ( diff --git a/vms/avm/txs/executor/semantic_verifier.go b/vms/avm/txs/executor/semantic_verifier.go index 16231d3a7236..cbf1e6c44e4d 100644 --- a/vms/avm/txs/executor/semantic_verifier.go +++ b/vms/avm/txs/executor/semantic_verifier.go @@ -30,10 +30,10 @@ var ( type SemanticVerifier struct { *Backend - BlkFeeManager *commonfees.Manager - UnitCaps commonfees.Dimensions - State state.ReadOnlyChain - Tx *txs.Tx + BlkFeeManager *commonfees.Manager + BlockMaxComplexity commonfees.Dimensions + State state.ReadOnlyChain + Tx *txs.Tx } func (v *SemanticVerifier) BaseTx(tx *txs.BaseTx) error { @@ -141,7 +141,7 @@ func (v *SemanticVerifier) verifyBaseTx( IsEUpgradeActive: v.Config.IsEActivated(v.State.GetTimestamp()), Config: v.Config, FeeManager: v.BlkFeeManager, - BlockMaxComplexity: v.UnitCaps, + BlockMaxComplexity: v.BlockMaxComplexity, Codec: v.Codec, Credentials: creds, } diff --git a/vms/avm/txs/executor/semantic_verifier_test.go b/vms/avm/txs/executor/semantic_verifier_test.go index 7d346c16f482..ad4e870635f9 100644 --- a/vms/avm/txs/executor/semantic_verifier_test.go +++ b/vms/avm/txs/executor/semantic_verifier_test.go @@ -742,11 +742,11 @@ func TestSemanticVerifierBaseTx(t *testing.T) { feeCfg := config.GetDynamicFeesConfig(true /*isEActive*/) err = tx.Unsigned.Visit(&SemanticVerifier{ - Backend: backend, - BlkFeeManager: fees.NewManager(feeCfg.InitialFeeRate), - UnitCaps: feeCfg.BlockMaxComplexity, - State: state, - Tx: tx, + Backend: backend, + BlkFeeManager: fees.NewManager(feeCfg.InitialFeeRate), + BlockMaxComplexity: feeCfg.BlockMaxComplexity, + State: state, + Tx: tx, }) require.ErrorIs(err, test.err) }) @@ -1496,11 +1496,11 @@ func TestSemanticVerifierExportTx(t *testing.T) { feeCfg := config.GetDynamicFeesConfig(true /*isEActive*/) err = tx.Unsigned.Visit(&SemanticVerifier{ - Backend: backend, - BlkFeeManager: fees.NewManager(feeCfg.InitialFeeRate), - UnitCaps: feeCfg.BlockMaxComplexity, - State: state, - Tx: tx, + Backend: backend, + BlkFeeManager: fees.NewManager(feeCfg.InitialFeeRate), + BlockMaxComplexity: feeCfg.BlockMaxComplexity, + State: state, + Tx: tx, }) require.ErrorIs(err, test.err) }) @@ -1641,11 +1641,11 @@ func TestSemanticVerifierExportTxDifferentSubnet(t *testing.T) { feeCfg := config.GetDynamicFeesConfig(true /*isEActive*/) err = tx.Unsigned.Visit(&SemanticVerifier{ - Backend: backend, - BlkFeeManager: fees.NewManager(feeCfg.InitialFeeRate), - UnitCaps: feeCfg.BlockMaxComplexity, - State: state, - Tx: tx, + Backend: backend, + BlkFeeManager: fees.NewManager(feeCfg.InitialFeeRate), + BlockMaxComplexity: feeCfg.BlockMaxComplexity, + State: state, + Tx: tx, }) require.ErrorIs(err, verify.ErrMismatchedSubnetIDs) } @@ -2179,11 +2179,11 @@ func TestSemanticVerifierImportTx(t *testing.T) { feeCfg := config.GetDynamicFeesConfig(true /*isEActive*/) err = tx.Unsigned.Visit(&SemanticVerifier{ - Backend: backend, - BlkFeeManager: fees.NewManager(feeCfg.InitialFeeRate), - UnitCaps: feeCfg.BlockMaxComplexity, - State: state, - Tx: tx, + Backend: backend, + BlkFeeManager: fees.NewManager(feeCfg.InitialFeeRate), + BlockMaxComplexity: feeCfg.BlockMaxComplexity, + State: state, + Tx: tx, }) require.ErrorIs(err, test.expectedErr) }) From eca84c4ebb7faaa2c32e0cb8e676113d5afa47d7 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Fri, 22 Mar 2024 14:09:34 +0100 Subject: [PATCH 123/132] added x-chain e2e test --- tests/e2e/x/dynamic_fees.go | 128 ++++++++++++++++++++++++++++++++++++ vms/avm/state/state.go | 22 +++++-- vms/avm/vm.go | 8 +-- vms/avm/vm_test.go | 2 +- 4 files changed, 148 insertions(+), 12 deletions(-) create mode 100644 tests/e2e/x/dynamic_fees.go diff --git a/tests/e2e/x/dynamic_fees.go b/tests/e2e/x/dynamic_fees.go new file mode 100644 index 000000000000..00e13ccbb652 --- /dev/null +++ b/tests/e2e/x/dynamic_fees.go @@ -0,0 +1,128 @@ +// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package x + +import ( + "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/utils/units" + "github.com/ava-labs/avalanchego/vms/avm" + "github.com/ava-labs/avalanchego/vms/components/verify" + "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{ + InitialFeeRate: commonfees.Dimensions{1, 2, 3, 4}, + MinFeeRate: commonfees.Dimensions{1, 1, 1, 1}, + UpdateCoefficient: commonfees.Dimensions{2, 2, 2, 2}, + 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{300, 50, 150, 800}, + } + + 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{ + "X": { + "dynamic-fees-config": customDynamicFeesConfig, + }, + }, + } + e2e.Env.StartPrivateNetwork(privateNetwork) + + ginkgo.By("setup a wallet and a X-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) + xWallet := baseWallet.X() + xChainClient := avm.NewClient(nodeURI.URI, "X") + + // retrieve initial balances + xBuilder := xWallet.Builder() + xContext := xBuilder.Context() + avaxAssetID := xContext.AVAXAssetID + xBalances, err := xWallet.Builder().GetFTBalance() + require.NoError(err) + xStartBalance := xBalances[avaxAssetID] + tests.Outf("{{blue}} X-chain initial balance: %d {{/}}\n", xStartBalance) + + ginkgo.By("checking that initial fee values match with configured ones", func() { + currFeeRates, _, err := xChainClient.GetFeeRates(e2e.DefaultContext()) + require.NoError(err) + require.Equal(customDynamicFeesConfig.InitialFeeRate, currFeeRates) + }) + + ginkgo.By("issue expensive transactions so to increase the fee rates to be paid for accepting the transactons", + func() { + currFeeRates := commonfees.Empty + + ginkgo.By("repeatedly change the permissioned subnet owner to increase fee rates", func() { + txsCount := 10 + for i := 0; i < txsCount; i++ { + owner := secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{ + keychain.Keys[1].Address(), + }, + } + + _, err := xWallet.IssueCreateAssetTx( + "HI", + "HI", + byte(txsCount), + map[uint32][]verify.State{ + 0: { + &secp256k1fx.TransferOutput{ + Amt: units.Schmeckle, + OutputOwners: owner, + }, + }, + }, + ) + require.NoError(err) + + updatedFeeRates, _, err := xChainClient.GetFeeRates(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)) + currFeeRates = updatedFeeRates + } + }) + + ginkgo.By("wait for the fee rates to decrease", func() { + initialFeeRates := currFeeRates + e2e.Eventually(func() bool { + var err error + _, currFeeRates, err = xChainClient.GetFeeRates(e2e.DefaultContext()) + require.NoError(err) + tests.Outf("{{blue}} next fee rates: %v {{/}}\n", 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/avm/state/state.go b/vms/avm/state/state.go index 588fcff21a6a..948b2be69cf6 100644 --- a/vms/avm/state/state.go +++ b/vms/avm/state/state.go @@ -149,7 +149,7 @@ type state struct { timestamp, persistedTimestamp time.Time singletonDB database.Database - feeRates commonfees.Dimensions + feeRates *commonfees.Dimensions // pointer, to allow customization for test networks lastBlkComplexity commonfees.Dimensions trackChecksum bool @@ -364,6 +364,7 @@ func (s *state) InitializeChainState(stopVertexID ids.ID, genesisTimestamp time. } func (s *state) InitFees() error { + s.feeRates = new(commonfees.Dimensions) switch feeRatesBytes, err := s.singletonDB.Get(feeRatesKey); err { case nil: if err := s.feeRates.FromBytes(feeRatesBytes); err != nil { @@ -376,7 +377,7 @@ func (s *state) InitFees() error { // TODO: remove once fork is active isEActivated := s.cfg.IsEActivated(s.GetTimestamp()) feeCfg := config.GetDynamicFeesConfig(isEActivated) - s.feeRates = feeCfg.InitialFeeRate + *s.feeRates = feeCfg.InitialFeeRate default: return err @@ -444,11 +445,15 @@ func (s *state) SetTimestamp(t time.Time) { } func (s *state) GetFeeRates() (commonfees.Dimensions, error) { - return s.feeRates, nil + if s.feeRates == nil { + return commonfees.Empty, nil + } + return *s.feeRates, nil } -func (s *state) SetFeeRates(feeRates commonfees.Dimensions) { - s.feeRates = feeRates +func (s *state) SetFeeRates(fr commonfees.Dimensions) { + feeRates := fr + s.feeRates = &feeRates } func (s *state) GetLastBlockComplexity() (commonfees.Dimensions, error) { @@ -565,8 +570,11 @@ func (s *state) writeMetadata() error { } s.persistedTimestamp = s.timestamp } - if err := s.singletonDB.Put(feeRatesKey, s.feeRates.Bytes()); err != nil { - return fmt.Errorf("failed to write fee rates: %w", err) + + if s.feeRates != nil { + if err := s.singletonDB.Put(feeRatesKey, s.feeRates.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/avm/vm.go b/vms/avm/vm.go index 3c9fe647b260..c9d6067e6023 100644 --- a/vms/avm/vm.go +++ b/vms/avm/vm.go @@ -415,6 +415,10 @@ func (vm *VM) Linearize(ctx context.Context, stopVertexID ids.ID, toEngine chan< return err } + if err := vm.state.InitFees(); err != nil { + return err + } + mempool, err := mempool.New("mempool", vm.registerer, toEngine) if err != nil { return fmt.Errorf("failed to create mempool: %w", err) @@ -579,10 +583,6 @@ func (vm *VM) initGenesis(genesisBytes []byte) error { } } - if err := vm.state.InitFees(); err != nil { - return err - } - if !stateInitialized { return vm.state.SetInitialized() } diff --git a/vms/avm/vm_test.go b/vms/avm/vm_test.go index 358a858b0351..d59d2e9e347d 100644 --- a/vms/avm/vm_test.go +++ b/vms/avm/vm_test.go @@ -466,7 +466,7 @@ func TestTxAcceptAfterParseTx(t *testing.T) { }, Asset: avax.Asset{ID: env.genesisTx.ID()}, In: &secp256k1fx.TransferInput{ - Amt: 499991395, + Amt: 500000000, Input: secp256k1fx.Input{ SigIndices: []uint32{ 0, From 8a43b658b78eed4e0b281bda0a607ff48da3fc49 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Wed, 27 Mar 2024 14:46:08 +0100 Subject: [PATCH 124/132] update avm tx builder to use next fee manager --- vms/avm/environment_test.go | 3 +- vms/avm/service_backend.go | 8 ++ vms/avm/service_test.go | 117 +++++++++--------------------- vms/avm/tx_builders.go | 96 ++++++++++-------------- vms/avm/txs/fees/helpers.go | 33 +++++++++ vms/avm/vm.go | 1 + vms/avm/vm_test.go | 2 +- vms/avm/wallet_service_backend.go | 5 ++ 8 files changed, 121 insertions(+), 144 deletions(-) diff --git a/vms/avm/environment_test.go b/vms/avm/environment_test.go index dd4747c1be5c..4374c8ea315c 100644 --- a/vms/avm/environment_test.go +++ b/vms/avm/environment_test.go @@ -236,6 +236,7 @@ func setup(tb testing.TB, c *envConfig) *environment { vm.parser.Codec(), vm.ctx, &vm.Config, + &vm.clock, vm.state, vm.AtomicUTXOManager, ), @@ -365,7 +366,7 @@ func newTx(tb testing.TB, genesisBytes []byte, chainID ids.ID, parser txs.Parser // Sample from a set of addresses and return them raw and formatted as strings. // The size of the sample is between 1 and len(addrs) // If len(addrs) == 0, returns nil -func sampleAddrs(tb testing.TB, addressFormatter avax.AddressManager, addrs []ids.ShortID) ([]ids.ShortID, []string) { +func sampleAddrs(tb testing.TB, addressFormatter avax.AddressManager, addrs []ids.ShortID) ([]ids.ShortID, []string) { //nolint:unparam require := require.New(tb) sampledAddrs := []ids.ShortID{} diff --git a/vms/avm/service_backend.go b/vms/avm/service_backend.go index 3096c0cb0901..386ecf49bb82 100644 --- a/vms/avm/service_backend.go +++ b/vms/avm/service_backend.go @@ -12,6 +12,7 @@ import ( "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/snow" "github.com/ava-labs/avalanchego/utils/set" + "github.com/ava-labs/avalanchego/utils/timer/mockable" "github.com/ava-labs/avalanchego/vms/avm/config" "github.com/ava-labs/avalanchego/vms/avm/state" "github.com/ava-labs/avalanchego/vms/components/avax" @@ -25,6 +26,7 @@ func newServiceBackend( codec codec.Manager, ctx *snow.Context, cfg *config.Config, + clk *mockable.Clock, state state.State, atomicUTXOsMan avax.AtomicUTXOManager, ) *serviceBackend { @@ -41,6 +43,7 @@ func newServiceBackend( ctx: backendCtx, xchainID: ctx.XChainID, cfg: cfg, + clk: clk, state: state, atomicUTXOsMan: atomicUTXOsMan, } @@ -51,6 +54,7 @@ type serviceBackend struct { ctx *builder.Context xchainID ids.ID cfg *config.Config + clk *mockable.Clock addrs set.Set[ids.ShortID] state state.State atomicUTXOsMan avax.AtomicUTXOManager @@ -68,6 +72,10 @@ func (b *serviceBackend) Codec() codec.Manager { return b.codec } +func (b *serviceBackend) Clock() *mockable.Clock { + return b.clk +} + func (b *serviceBackend) Context() *builder.Context { return b.ctx } diff --git a/vms/avm/service_test.go b/vms/avm/service_test.go index 44e22c422b0b..638c0cff17b3 100644 --- a/vms/avm/service_test.go +++ b/vms/avm/service_test.go @@ -34,7 +34,6 @@ import ( "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/fees" "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/components/index" "github.com/ava-labs/avalanchego/vms/components/verify" @@ -43,7 +42,6 @@ import ( "github.com/ava-labs/avalanchego/vms/secp256k1fx" avajson "github.com/ava-labs/avalanchego/utils/json" - commonfees "github.com/ava-labs/avalanchego/vms/components/fees" ) func TestServiceIssueTx(t *testing.T) { @@ -594,7 +592,7 @@ func TestServiceGetTxJSON_BaseTx(t *testing.T) { "addresses": [ "X-testing1d6kkj0qh4wcmus3tk59npwt3rluc6en72ngurd" ], - "amount": 999990355, + "amount": 999995542, "locktime": 0, "threshold": 1 } @@ -678,7 +676,7 @@ func TestServiceGetTxJSON_ExportTx(t *testing.T) { "addresses": [ "X-testing1lnk637g0edwnqc2tn8tel39652fswa3xk4r65e" ], - "amount": 999990215, + "amount": 999995486, "locktime": 0, "threshold": 1 } @@ -827,7 +825,7 @@ func TestServiceGetTxJSON_CreateAssetTx(t *testing.T) { "addresses": [ "X-testing1lnk637g0edwnqc2tn8tel39652fswa3xk4r65e" ], - "amount": 999990715, + "amount": 999996286, "locktime": 0, "threshold": 1 } @@ -922,7 +920,7 @@ func TestServiceGetTxJSON_CreateAssetTx(t *testing.T) { "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", "credential": { "signatures": [ - "0x11df1cb82f9a5e3b3ced9167654330e7782832c1189a04bb6b6207f7a69b979d55e5e3819744e4a13255ca724697c6a4ecab8cc9e8464cd2ec574e5b4bda1e2701" + "0xf1d2a476b36e07debd906c4aae0238e9d1275c1cfd806ceeb8968818d3df0ad524cdae56b687fde9dbd0a18739da7656d140a675766c164e38af726fa822ad2100" ] } } @@ -1002,7 +1000,7 @@ func TestServiceGetTxJSON_OperationTxWithNftxMintOp(t *testing.T) { "addresses": [ "X-testing1lnk637g0edwnqc2tn8tel39652fswa3xk4r65e" ], - "amount": 999988215, + "amount": 999994946, "locktime": 0, "threshold": 1 } @@ -1010,12 +1008,12 @@ func TestServiceGetTxJSON_OperationTxWithNftxMintOp(t *testing.T) { ], "inputs": [ { - "txID": "KGWg2g81xZHm3Enyd16GKh79tRgRK1hcFDsJe5eY9RZQAv5QG", + "txID": "5qm7raFsDQzXgWJ77ygRZ1Ey4qd1ru5sMhcB8iirkKyQQ736D", "outputIndex": 0, "assetID": "tvLKci3hNoCX4NijS6TfiT6XJJY3gGKd2git6SSVTG5J8Nfby", "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", "input": { - "amount": 999991615, + "amount": 999996646, "signatureIndices": [ 0 ] @@ -1059,7 +1057,7 @@ func TestServiceGetTxJSON_OperationTxWithNftxMintOp(t *testing.T) { "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", "credential": { "signatures": [ - "0xf692f8fb45d54064f6453936f5bf636219e2ddf64b5b86ece204aa1527c6e60f10ecbfad2c4cf07b982ef611e791220ac9064035062ab5bf00ec983355437ef400" + "0x63ce475c0f2abf1d98c68034bdf1409c2ab6e0120753013886f184e5b13b85356ff793fdd38a5b6877022e0e584c610d6b3e077133ed8a7efab36fa631dcf34e01" ] } }, @@ -1067,7 +1065,7 @@ func TestServiceGetTxJSON_OperationTxWithNftxMintOp(t *testing.T) { "fxID": "qd2U4HDWUvMrVUeTcCHp6xH3Qpnn1XbU5MDdnBoiifFqvgXwT", "credential": { "signatures": [ - "0xf692f8fb45d54064f6453936f5bf636219e2ddf64b5b86ece204aa1527c6e60f10ecbfad2c4cf07b982ef611e791220ac9064035062ab5bf00ec983355437ef400" + "0x63ce475c0f2abf1d98c68034bdf1409c2ab6e0120753013886f184e5b13b85356ff793fdd38a5b6877022e0e584c610d6b3e077133ed8a7efab36fa631dcf34e01" ] } } @@ -1156,7 +1154,7 @@ func TestServiceGetTxJSON_OperationTxWithMultipleNftxMintOp(t *testing.T) { "addresses": [ "X-testing1lnk637g0edwnqc2tn8tel39652fswa3xk4r65e" ], - "amount": 999987901, + "amount": 999994793, "locktime": 0, "threshold": 1 } @@ -1164,12 +1162,12 @@ func TestServiceGetTxJSON_OperationTxWithMultipleNftxMintOp(t *testing.T) { ], "inputs": [ { - "txID": "Pbg8AVMJUZUzPiFnnBvNKvW6Ljjobr43udPirFbfEYuW7t49z", + "txID": "yKvG3o8msJ7QAv2T6pvqPbTc1hJpaFUhvsHepRZ9MayMLw2w6", "outputIndex": 0, "assetID": "tvLKci3hNoCX4NijS6TfiT6XJJY3gGKd2git6SSVTG5J8Nfby", "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", "input": { - "amount": 999991575, + "amount": 999996630, "signatureIndices": [ 0 ] @@ -1241,7 +1239,7 @@ func TestServiceGetTxJSON_OperationTxWithMultipleNftxMintOp(t *testing.T) { "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", "credential": { "signatures": [ - "0x71861edb51241d98280409243382697667ec850852360ab6b72c7864d926ca6d08a0ef2d7a3a3c17e4c38693973ee6b22aeebccd46ae9aab2a038f3777bee18200" + "0xc222a8cd263bab6f3895b4623df8ca4346b02c32c9adc63c56d0c7dad5db5d7a0dd7e17ce07cec024de546015868239d04cff92f1c9fc46a9b54426f15d9ab1801" ] } }, @@ -1249,7 +1247,7 @@ func TestServiceGetTxJSON_OperationTxWithMultipleNftxMintOp(t *testing.T) { "fxID": "qd2U4HDWUvMrVUeTcCHp6xH3Qpnn1XbU5MDdnBoiifFqvgXwT", "credential": { "signatures": [ - "0x71861edb51241d98280409243382697667ec850852360ab6b72c7864d926ca6d08a0ef2d7a3a3c17e4c38693973ee6b22aeebccd46ae9aab2a038f3777bee18200" + "0xc222a8cd263bab6f3895b4623df8ca4346b02c32c9adc63c56d0c7dad5db5d7a0dd7e17ce07cec024de546015868239d04cff92f1c9fc46a9b54426f15d9ab1801" ] } }, @@ -1340,7 +1338,7 @@ func TestServiceGetTxJSON_OperationTxWithSecpMintOp(t *testing.T) { "addresses": [ "X-testing1lnk637g0edwnqc2tn8tel39652fswa3xk4r65e" ], - "amount": 999988181, + "amount": 999994927, "locktime": 0, "threshold": 1 } @@ -1348,12 +1346,12 @@ func TestServiceGetTxJSON_OperationTxWithSecpMintOp(t *testing.T) { ], "inputs": [ { - "txID": "2MBRmBRnKGXkCe7Byc5g9xArAW24qjpKL9fDVNEWJht156xYKp", + "txID": "2Pb53uW6P9BpQ9pN4PNffTi8AcLgeALjtTSFTeTL65baHicAR5", "outputIndex": 0, "assetID": "tvLKci3hNoCX4NijS6TfiT6XJJY3gGKd2git6SSVTG5J8Nfby", "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", "input": { - "amount": 999991635, + "amount": 999996654, "signatureIndices": [ 0 ] @@ -1401,7 +1399,7 @@ func TestServiceGetTxJSON_OperationTxWithSecpMintOp(t *testing.T) { "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", "credential": { "signatures": [ - "0xc7c6ee0541a7f9535aea63485698565004ba1904df15ae11a1f9320258b8a0910a7e67b3adecfb583b3c1aa169ce334b6599332a2edb0213438008ee6b8d6e9200" + "0x67c966f5571b51b25d7890366ecc5548251618966ae1d20bddb89442999e8fda3691619295fdb821e1e8d16fc05e29e4d661535712143b84f1a43070a5e669db01" ] } }, @@ -1409,7 +1407,7 @@ func TestServiceGetTxJSON_OperationTxWithSecpMintOp(t *testing.T) { "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", "credential": { "signatures": [ - "0xc7c6ee0541a7f9535aea63485698565004ba1904df15ae11a1f9320258b8a0910a7e67b3adecfb583b3c1aa169ce334b6599332a2edb0213438008ee6b8d6e9200" + "0x67c966f5571b51b25d7890366ecc5548251618966ae1d20bddb89442999e8fda3691619295fdb821e1e8d16fc05e29e4d661535712143b84f1a43070a5e669db01" ] } } @@ -1496,7 +1494,7 @@ func TestServiceGetTxJSON_OperationTxWithMultipleSecpMintOp(t *testing.T) { "addresses": [ "X-testing1lnk637g0edwnqc2tn8tel39652fswa3xk4r65e" ], - "amount": 999987833, + "amount": 999994755, "locktime": 0, "threshold": 1 } @@ -1504,12 +1502,12 @@ func TestServiceGetTxJSON_OperationTxWithMultipleSecpMintOp(t *testing.T) { ], "inputs": [ { - "txID": "rS3zk6KTARY8H6njFhYbMs2tdCqgCnyRXBUUu1ta5jyqfXVq", + "txID": "2SbcXEUatKafkjWi7ZAnTqjzumyHLM6LNSy2PC5PTqThdibZLZ", "outputIndex": 0, "assetID": "tvLKci3hNoCX4NijS6TfiT6XJJY3gGKd2git6SSVTG5J8Nfby", "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", "input": { - "amount": 999991615, + "amount": 999996646, "signatureIndices": [ 0 ] @@ -1597,7 +1595,7 @@ func TestServiceGetTxJSON_OperationTxWithMultipleSecpMintOp(t *testing.T) { "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", "credential": { "signatures": [ - "0x475c5887edeade739aa756b41705b74cccd265044d62a5ddb927cb36b5325fca24b9e60c45b86c75983a2e0b088ca43423f61580526d27e079d4e0699696f16f00" + "0xf592dc536526516c8df78d787845bb6ae367b0ae62a6db93e4ebc010347c15c704665dc2c6cca3acba2af45190c92fd038e3831aa72f9dad63cce6d56b53fe1e01" ] } }, @@ -1605,7 +1603,7 @@ func TestServiceGetTxJSON_OperationTxWithMultipleSecpMintOp(t *testing.T) { "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", "credential": { "signatures": [ - "0x475c5887edeade739aa756b41705b74cccd265044d62a5ddb927cb36b5325fca24b9e60c45b86c75983a2e0b088ca43423f61580526d27e079d4e0699696f16f00" + "0xf592dc536526516c8df78d787845bb6ae367b0ae62a6db93e4ebc010347c15c704665dc2c6cca3acba2af45190c92fd038e3831aa72f9dad63cce6d56b53fe1e01" ] } } @@ -1683,7 +1681,7 @@ func TestServiceGetTxJSON_OperationTxWithPropertyFxMintOp(t *testing.T) { "addresses": [ "X-testing1lnk637g0edwnqc2tn8tel39652fswa3xk4r65e" ], - "amount": 999988457, + "amount": 999995043, "locktime": 0, "threshold": 1 } @@ -1691,12 +1689,12 @@ func TestServiceGetTxJSON_OperationTxWithPropertyFxMintOp(t *testing.T) { ], "inputs": [ { - "txID": "2JE2HjEceadRG2nPvZP3iaPdcG9N9zLhXy3t7RpDqNKFYitJuE", + "txID": "2QaaDARUZ3uEiGwFfdzhNQUNdFtJVqw7fDevM9evcqsCEyjXo7", "outputIndex": 0, "assetID": "tvLKci3hNoCX4NijS6TfiT6XJJY3gGKd2git6SSVTG5J8Nfby", "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", "input": { - "amount": 999991855, + "amount": 999996742, "signatureIndices": [ 0 ] @@ -1741,7 +1739,7 @@ func TestServiceGetTxJSON_OperationTxWithPropertyFxMintOp(t *testing.T) { "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", "credential": { "signatures": [ - "0xb57f28c21f47bdcba299086d6f45c94b97f24d45a9c1c68d6c8b42be41ff3e130521dd297c9c9b4af66defde7a3e15538aefaee70211a0191d00e8f280afa5bb00" + "0x8c3c994f62e60944c73bab594c8ece929c99b0cc6cb5e67adf760e0ebaa210316599f1e9c51f4e8a703c7e6731a34ff710f06c511875be8d9f834dfd8e05596e01" ] } }, @@ -1834,7 +1832,7 @@ func TestServiceGetTxJSON_OperationTxWithPropertyFxMintOpMultiple(t *testing.T) "addresses": [ "X-testing1lnk637g0edwnqc2tn8tel39652fswa3xk4r65e" ], - "amount": 999987985, + "amount": 999994827, "locktime": 0, "threshold": 1 } @@ -1842,12 +1840,12 @@ func TestServiceGetTxJSON_OperationTxWithPropertyFxMintOpMultiple(t *testing.T) ], "inputs": [ { - "txID": "2nDskbBWwToZFJ4F2PaTds76ET7UkNuhsmAsmtPpVyodWBZXS7", + "txID": "27GtULJnoV8AsmqF12nrPE6sMfLpmWxPWdCtnAHFbN1M9p39pG", "outputIndex": 0, "assetID": "tvLKci3hNoCX4NijS6TfiT6XJJY3gGKd2git6SSVTG5J8Nfby", "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", "input": { - "amount": 999991655, + "amount": 999996662, "signatureIndices": [ 0 ] @@ -1921,7 +1919,7 @@ func TestServiceGetTxJSON_OperationTxWithPropertyFxMintOpMultiple(t *testing.T) "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", "credential": { "signatures": [ - "0xcd0efc04d93b862a2fd95c75ccb4b0a393632a2e57c7b68c8fa1821a93e16c83381940dcb52fb5349aa954d9323486ea1022b75d5d9feabd6bf8c9263488234d01" + "0xd3a729b8eea5a36ba20f376e190bac4eeaa634351bdf769baf74ce3c8bd4cb860ad85276ca1c9efd059a83690dee1f6d21bc2cf955c3a481cd67722be06d4d7601" ] } }, @@ -2631,7 +2629,7 @@ func TestNFTWorkflow(t *testing.T) { env.vm.ctx.Lock.Unlock() }() - fromAddrs, fromAddrsStr := sampleAddrs(t, env.vm.AddressManager, addrs) + _, fromAddrsStr := sampleAddrs(t, env.vm.AddressManager, addrs) // Test minting of the created variable cap asset addrStr, err := env.vm.FormatLocalAddress(keys[0].PublicKey().Address()) @@ -2663,55 +2661,6 @@ func TestNFTWorkflow(t *testing.T) { buildAndAccept(require, env.vm, env.issuer, createReply.AssetID) - // Key: Address - // Value: AVAX balance - balances := map[ids.ShortID]uint64{} - for _, addr := range addrs { // get balances for all addresses - addrStr, err := env.vm.FormatLocalAddress(addr) - require.NoError(err) - - reply := &GetBalanceReply{} - require.NoError(env.service.GetBalance(nil, - &GetBalanceArgs{ - Address: addrStr, - AssetID: env.vm.feeAssetID.String(), - }, - reply, - )) - - balances[addr] = uint64(reply.Balance) - } - - fromAddrsTotalBalance := uint64(0) - for _, addr := range fromAddrs { - fromAddrsTotalBalance += balances[addr] - } - - // retrieve tx fee - lastAcceptedBlkID := env.vm.chainManager.LastAccepted() - lastAcceptedBlk, err := env.vm.chainManager.GetStatelessBlock(lastAcceptedBlkID) - require.NoError(err) - txs := lastAcceptedBlk.Txs() - require.Len(txs, 1) - createAssetTx := txs[0] - - isEActivated := env.vm.Config.IsEActivated(env.vm.state.GetTimestamp()) - feesCfg := config.GetDynamicFeesConfig(isEActivated) - feeCalc := &fees.Calculator{ - IsEActive: true, - Config: &env.vm.Config, - FeeManager: commonfees.NewManager(feesCfg.InitialFeeRate), - BlockMaxComplexity: feesCfg.BlockMaxComplexity, - Codec: env.service.txBuilderBackend.codec, - Credentials: createAssetTx.Creds, - } - - require.NoError(createAssetTx.Unsigned.Visit(feeCalc)) - expectedFee := feeCalc.Fee - - fromAddrsStartBalance := startBalance * uint64(len(fromAddrs)) - require.Equal(fromAddrsStartBalance-expectedFee, fromAddrsTotalBalance) - assetID := createReply.AssetID payload, err := formatting.Encode(formatting.Hex, []byte{1, 2, 3, 4, 5}) require.NoError(err) diff --git a/vms/avm/tx_builders.go b/vms/avm/tx_builders.go index a823e52bff42..00cd6b87bb20 100644 --- a/vms/avm/tx_builders.go +++ b/vms/avm/tx_builders.go @@ -10,6 +10,8 @@ import ( "github.com/ava-labs/avalanchego/codec" "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/executor" "github.com/ava-labs/avalanchego/vms/avm/config" "github.com/ava-labs/avalanchego/vms/avm/state" "github.com/ava-labs/avalanchego/vms/avm/txs" @@ -20,7 +22,6 @@ import ( "github.com/ava-labs/avalanchego/wallet/chain/x/signer" "github.com/ava-labs/avalanchego/wallet/subnet/primary/common" - commonfees "github.com/ava-labs/avalanchego/vms/components/fees" walletbuilder "github.com/ava-labs/avalanchego/wallet/chain/x/builder" ) @@ -31,6 +32,7 @@ type txBuilderBackend interface { State() state.State Config() *config.Config Codec() codec.Manager + Clock() *mockable.Clock Context() *walletbuilder.Context ResetAddresses(addrs set.Set[ids.ShortID]) @@ -44,16 +46,12 @@ func buildCreateAssetTx( kc *secp256k1fx.Keychain, changeAddr ids.ShortID, ) (*txs.Tx, ids.ShortID, error) { - feeRates, err := backend.State().GetFeeRates() + pBuilder, pSigner := builders(backend, kc) + feeCalc, err := feeCalculator(backend) if err != nil { - return nil, ids.ShortEmpty, fmt.Errorf("failed retrieving fee rates: %w", err) + return nil, ids.ShortEmpty, fmt.Errorf("failed creating fee calculator: %w", err) } - var ( - pBuilder, pSigner = builders(backend, kc) - feeCalc = feeCalculator(backend, feeRates) - ) - utx, err := pBuilder.NewCreateAssetTx( name, symbol, @@ -81,16 +79,12 @@ func buildBaseTx( kc *secp256k1fx.Keychain, changeAddr ids.ShortID, ) (*txs.Tx, ids.ShortID, error) { - feeRates, err := backend.State().GetFeeRates() + pBuilder, pSigner := builders(backend, kc) + feeCalc, err := feeCalculator(backend) if err != nil { - return nil, ids.ShortEmpty, fmt.Errorf("failed retrieving fee rates: %w", err) + return nil, ids.ShortEmpty, fmt.Errorf("failed creating fee calculator: %w", err) } - var ( - pBuilder, pSigner = builders(backend, kc) - feeCalc = feeCalculator(backend, feeRates) - ) - utx, err := pBuilder.NewBaseTx( outs, feeCalc, @@ -116,16 +110,12 @@ func mintNFT( kc *secp256k1fx.Keychain, changeAddr ids.ShortID, ) (*txs.Tx, error) { - feeRates, err := backend.State().GetFeeRates() + pBuilder, pSigner := builders(backend, kc) + feeCalc, err := feeCalculator(backend) if err != nil { - return nil, fmt.Errorf("failed retrieving fee rates: %w", err) + return nil, fmt.Errorf("failed creating fee calculator: %w", err) } - var ( - pBuilder, pSigner = builders(backend, kc) - feeCalc = feeCalculator(backend, feeRates) - ) - utx, err := pBuilder.NewOperationTxMintNFT( assetID, payload, @@ -146,15 +136,12 @@ func mintFTs( kc *secp256k1fx.Keychain, changeAddr ids.ShortID, ) (*txs.Tx, error) { - feeRates, err := backend.State().GetFeeRates() + pBuilder, pSigner := builders(backend, kc) + feeCalc, err := feeCalculator(backend) if err != nil { - return nil, fmt.Errorf("failed retrieving fee rates: %w", err) + return nil, fmt.Errorf("failed creating fee calculator: %w", err) } - var ( - pBuilder, pSigner = builders(backend, kc) - feeCalc = feeCalculator(backend, feeRates) - ) utx, err := pBuilder.NewOperationTxMintFT( outputs, feeCalc, @@ -173,16 +160,12 @@ func buildOperation( kc *secp256k1fx.Keychain, changeAddr ids.ShortID, ) (*txs.Tx, error) { - feeRates, err := backend.State().GetFeeRates() + pBuilder, pSigner := builders(backend, kc) + feeCalc, err := feeCalculator(backend) if err != nil { - return nil, fmt.Errorf("failed retrieving fee rates: %w", err) + return nil, fmt.Errorf("failed creating fee calculator: %w", err) } - var ( - pBuilder, pSigner = builders(backend, kc) - feeCalc = feeCalculator(backend, feeRates) - ) - utx, err := pBuilder.NewOperationTx( ops, feeCalc, @@ -201,16 +184,12 @@ func buildImportTx( to ids.ShortID, kc *secp256k1fx.Keychain, ) (*txs.Tx, error) { - feeRates, err := backend.State().GetFeeRates() + pBuilder, pSigner := builders(backend, kc) + feeCalc, err := feeCalculator(backend) if err != nil { - return nil, fmt.Errorf("failed retrieving fee rates: %w", err) + return nil, fmt.Errorf("failed creating fee calculator: %w", err) } - var ( - pBuilder, pSigner = builders(backend, kc) - feeCalc = feeCalculator(backend, feeRates) - ) - outOwner := &secp256k1fx.OutputOwners{ Locktime: 0, Threshold: 1, @@ -238,16 +217,12 @@ func buildExportTx( kc *secp256k1fx.Keychain, changeAddr ids.ShortID, ) (*txs.Tx, ids.ShortID, error) { - feeRates, err := backend.State().GetFeeRates() + pBuilder, pSigner := builders(backend, kc) + feeCalc, err := feeCalculator(backend) if err != nil { - return nil, ids.ShortEmpty, fmt.Errorf("failed retrieving fee rates: %w", err) + return nil, ids.ShortEmpty, fmt.Errorf("failed creating fee calculator: %w", err) } - var ( - pBuilder, pSigner = builders(backend, kc) - feeCalc = feeCalculator(backend, feeRates) - ) - outputs := []*avax.TransferableOutput{{ Asset: avax.Asset{ID: exportedAssetID}, Out: &secp256k1fx.TransferOutput{ @@ -289,22 +264,27 @@ func builders(backend txBuilderBackend, kc *secp256k1fx.Keychain) (walletbuilder return builder, signer } -func feeCalculator(backend txBuilderBackend, feeRates commonfees.Dimensions) *fees.Calculator { +func feeCalculator(backend txBuilderBackend) (*fees.Calculator, error) { var ( - chainTime = backend.State().GetTimestamp() - cfg = backend.Config() - isEActive = cfg.IsEActivated(chainTime) - feeCfg = config.GetDynamicFeesConfig(isEActive) - feeMan = commonfees.NewManager(feeRates) + currentChainTime = backend.State().GetTimestamp() + nextChainTime = executor.NextBlockTime(currentChainTime, backend.Clock()) + cfg = backend.Config() + isEActive = cfg.IsEActivated(currentChainTime) + feeCfg = config.GetDynamicFeesConfig(isEActive) ) + feeManager, err := fees.UpdatedFeeManager(backend.State(), backend.Config(), currentChainTime, nextChainTime) + if err != nil { + return nil, err + } + return &fees.Calculator{ - IsEActive: cfg.IsEActivated(chainTime), + IsEActive: isEActive, Config: cfg, - FeeManager: feeMan, + FeeManager: feeManager, BlockMaxComplexity: feeCfg.BlockMaxComplexity, Codec: backend.Codec(), - } + }, nil } func options(changeAddr ids.ShortID, memo []byte) []common.Option { diff --git a/vms/avm/txs/fees/helpers.go b/vms/avm/txs/fees/helpers.go index 805d1371664e..143b44dc3146 100644 --- a/vms/avm/txs/fees/helpers.go +++ b/vms/avm/txs/fees/helpers.go @@ -5,8 +5,11 @@ package fees import ( "fmt" + "time" "github.com/ava-labs/avalanchego/codec" + "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/components/avax" "github.com/ava-labs/avalanchego/vms/components/fees" @@ -47,3 +50,33 @@ func FinanceCredential(feeCalc *Calculator, codec codec.Manager, keysCount int) } 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/avm/vm.go b/vms/avm/vm.go index c9d6067e6023..e58cce298f87 100644 --- a/vms/avm/vm.go +++ b/vms/avm/vm.go @@ -349,6 +349,7 @@ func (vm *VM) CreateHandlers(context.Context) (map[string]http.Handler, error) { vm.parser.Codec(), vm.ctx, &vm.Config, + &vm.clock, vm.state, vm.AtomicUTXOManager, ), diff --git a/vms/avm/vm_test.go b/vms/avm/vm_test.go index d59d2e9e347d..dde741e5d9d1 100644 --- a/vms/avm/vm_test.go +++ b/vms/avm/vm_test.go @@ -466,7 +466,7 @@ func TestTxAcceptAfterParseTx(t *testing.T) { }, Asset: avax.Asset{ID: env.genesisTx.ID()}, In: &secp256k1fx.TransferInput{ - Amt: 500000000, + Amt: 499998279, Input: secp256k1fx.Input{ SigIndices: []uint32{ 0, diff --git a/vms/avm/wallet_service_backend.go b/vms/avm/wallet_service_backend.go index c6543fc1d340..c5f5f1b7d60e 100644 --- a/vms/avm/wallet_service_backend.go +++ b/vms/avm/wallet_service_backend.go @@ -13,6 +13,7 @@ import ( "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils/linkedhashmap" "github.com/ava-labs/avalanchego/utils/set" + "github.com/ava-labs/avalanchego/utils/timer/mockable" "github.com/ava-labs/avalanchego/vms/avm/config" "github.com/ava-labs/avalanchego/vms/avm/state" "github.com/ava-labs/avalanchego/vms/avm/txs" @@ -60,6 +61,10 @@ func (b *walletServiceBackend) Codec() codec.Manager { return b.vm.parser.Codec() } +func (b *walletServiceBackend) Clock() *mockable.Clock { + return &b.vm.clock +} + func (b *walletServiceBackend) Context() *builder.Context { return b.ctx } From 4c93dd5a64c8613eca7fe6d25dc61249833558f7 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Wed, 27 Mar 2024 16:22:24 +0100 Subject: [PATCH 125/132] removed some code duplication --- vms/avm/block/builder/builder.go | 26 +++++--------------------- vms/avm/block/executor/block.go | 26 +++++--------------------- vms/avm/block/executor/manager.go | 28 +++++----------------------- vms/avm/service.go | 21 ++------------------- 4 files changed, 17 insertions(+), 84 deletions(-) diff --git a/vms/avm/block/builder/builder.go b/vms/avm/block/builder/builder.go index 9bab5c57451c..8679558b0ef6 100644 --- a/vms/avm/block/builder/builder.go +++ b/vms/avm/block/builder/builder.go @@ -6,7 +6,6 @@ package builder import ( "context" "errors" - "fmt" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/snow/consensus/snowman" @@ -17,11 +16,12 @@ import ( "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/fees" "github.com/ava-labs/avalanchego/vms/avm/txs/mempool" - "github.com/ava-labs/avalanchego/vms/components/fees" blockexecutor "github.com/ava-labs/avalanchego/vms/avm/block/executor" txexecutor "github.com/ava-labs/avalanchego/vms/avm/txs/executor" + commonfees "github.com/ava-labs/avalanchego/vms/components/fees" ) // targetBlockSize is the max block size we aim to produce @@ -97,25 +97,9 @@ func (b *builder) BuildBlock(context.Context) (snowman.Block, error) { feesCfg = config.GetDynamicFeesConfig(isEActive) ) - feeRates, err := stateDiff.GetFeeRates() + feeManager, err := fees.UpdatedFeeManager(stateDiff, b.backend.Config, parentBlkTime, nextBlkTime) 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) - } - - feeManager := fees.NewManager(feeRates) - if isEActive { - if err := feeManager.UpdateFeeRates( - feesCfg, - parentBlkComplexity, - parentBlkTime.Unix(), - nextBlkTime.Unix(), - ); err != nil { - return nil, fmt.Errorf("failed updating fee rates, %w", err) - } + return nil, err } for { @@ -128,7 +112,7 @@ func (b *builder) BuildBlock(context.Context) (snowman.Block, error) { // pre e upgrade is active, we fill blocks till a target size // post e upgrade is active, we fill blocks till a target complexity done := (!isEActive && txSize > remainingSize) || - (isEActive && !fees.Compare(feeManager.GetCumulatedComplexity(), feesCfg.BlockTargetComplexityRate)) + (isEActive && !commonfees.Compare(feeManager.GetCumulatedComplexity(), feesCfg.BlockTargetComplexityRate)) if done { break } diff --git a/vms/avm/block/executor/block.go b/vms/avm/block/executor/block.go index d19e0fe19cc1..811633781c6a 100644 --- a/vms/avm/block/executor/block.go +++ b/vms/avm/block/executor/block.go @@ -20,7 +20,7 @@ import ( "github.com/ava-labs/avalanchego/vms/avm/config" "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" + "github.com/ava-labs/avalanchego/vms/avm/txs/fees" ) const SyncBound = 10 * time.Second @@ -132,30 +132,14 @@ func (b *Block) Verify(context.Context) error { atomicRequests: make(map[ids.ID]*atomic.Requests), } - feeRates, err := stateDiff.GetFeeRates() - if err != nil { - return fmt.Errorf("failed retrieving fee rates: %w", err) - } - parentBlkComplexitty, err := stateDiff.GetLastBlockComplexity() - if err != nil { - return fmt.Errorf("failed retrieving last block complexity: %w", err) - } - var ( isEActive = b.manager.backend.Config.IsEActivated(parentChainTime) feesCfg = config.GetDynamicFeesConfig(isEActive) ) - feeManager := fees.NewManager(feeRates) - if isEActive { - if err := feeManager.UpdateFeeRates( - feesCfg, - parentBlkComplexitty, - parentChainTime.Unix(), - newChainTime.Unix(), - ); err != nil { - return fmt.Errorf("failed updating fee rates, %w", err) - } + feeManager, err := fees.UpdatedFeeManager(stateDiff, b.manager.backend.Config, parentChainTime, newChainTime) + if err != nil { + return err } for _, tx := range txs { @@ -228,7 +212,7 @@ func (b *Block) Verify(context.Context) error { // state diff. if isEActive { stateDiff.SetFeeRates(feeManager.GetFeeRates()) - stateDiff.SetLastBlockComplexity(parentBlkComplexitty) + stateDiff.SetLastBlockComplexity(feeManager.GetCumulatedComplexity()) } stateDiff.SetLastAccepted(blkID) diff --git a/vms/avm/block/executor/manager.go b/vms/avm/block/executor/manager.go index ff18f0e3bee6..0f7e74cad579 100644 --- a/vms/avm/block/executor/manager.go +++ b/vms/avm/block/executor/manager.go @@ -5,7 +5,6 @@ package executor import ( "errors" - "fmt" "github.com/ava-labs/avalanchego/chains/atomic" "github.com/ava-labs/avalanchego/ids" @@ -18,8 +17,8 @@ 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" - "github.com/ava-labs/avalanchego/vms/components/fees" ) var ( @@ -171,31 +170,14 @@ func (m *manager) VerifyTx(tx *txs.Tx) error { return err } - 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) - } - var ( - chainTime = m.state.GetTimestamp() - isEActive = m.backend.Config.IsEActivated(chainTime) + isEActive = m.backend.Config.IsEActivated(parentBlkTime) feesCfg = config.GetDynamicFeesConfig(isEActive) ) - feeManager := fees.NewManager(feeRates) - if isEActive { - if err := feeManager.UpdateFeeRates( - feesCfg, - parentBlkComplexity, - parentBlkTime.Unix(), - nextBlkTime.Unix(), - ); err != nil { - return fmt.Errorf("failed updating fee rates, %w", err) - } + feeManager, err := fees.UpdatedFeeManager(m.state, m.backend.Config, parentBlkTime, nextBlkTime) + if err != nil { + return err } err = tx.Unsigned.Visit(&executor.SemanticVerifier{ diff --git a/vms/avm/service.go b/vms/avm/service.go index b406739b4d1f..0f317bbe4a8b 100644 --- a/vms/avm/service.go +++ b/vms/avm/service.go @@ -22,8 +22,8 @@ import ( "github.com/ava-labs/avalanchego/utils/logging" "github.com/ava-labs/avalanchego/utils/set" "github.com/ava-labs/avalanchego/vms/avm/block/executor" - "github.com/ava-labs/avalanchego/vms/avm/config" "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/keystore" "github.com/ava-labs/avalanchego/vms/components/verify" @@ -712,29 +712,12 @@ func (s *Service) GetFeeRates(_ *http.Request, _ *struct{}, reply *GetFeeRatesRe return nil } - var ( - currentTimestamp = onAccept.GetTimestamp() - feesCfg = config.GetDynamicFeesConfig(isEActivated) - ) - - parentBlkComplexity, err := onAccept.GetLastBlockComplexity() + feeManager, err := fees.UpdatedFeeManager(onAccept, &s.vm.Config, onAccept.GetTimestamp(), nextTimestamp) if err != nil { return err } - feeManager := commonfees.NewManager(currentFeeRates) - if isEActivated { - if err := feeManager.UpdateFeeRates( - feesCfg, - parentBlkComplexity, - currentTimestamp.Unix(), - nextTimestamp.Unix(), - ); err != nil { - return fmt.Errorf("failed updating fee rates, %w", err) - } - } reply.NextFeeRates = feeManager.GetFeeRates() - return nil } From 3aecfc3c963adac0d7c7570aa16c7826be4c6bc7 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Wed, 27 Mar 2024 17:27:32 +0100 Subject: [PATCH 126/132] removed some more code duplication --- wallet/chain/x/wallet.go | 162 +++++++++------------------------------ 1 file changed, 36 insertions(+), 126 deletions(-) diff --git a/wallet/chain/x/wallet.go b/wallet/chain/x/wallet.go index 3a1809df2b5b..597a37a33037 100644 --- a/wallet/chain/x/wallet.go +++ b/wallet/chain/x/wallet.go @@ -5,6 +5,7 @@ package x import ( "errors" + "fmt" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/snow/choices" @@ -186,23 +187,11 @@ func (w *wallet) IssueBaseTx( outputs []*avax.TransferableOutput, options ...common.Option, ) (*txs.Tx, error) { - if err := w.refreshFork(options...); err != nil { + feeCalc, err := w.feeCalculator(options...) + if err != nil { return nil, err } - var ( - feesMan = commonfees.NewManager(w.feeRates) - feeCalc = &fees.Calculator{ - IsEActive: w.isEForkActive, - Config: &config.Config{ - TxFee: w.builder.Context().BaseTxFee, - }, - FeeManager: feesMan, - BlockMaxComplexity: w.blockMaxComplexity, - Codec: builder.Parser.Codec(), - } - ) - utx, err := w.builder.NewBaseTx(outputs, feeCalc, options...) if err != nil { return nil, err @@ -217,23 +206,11 @@ func (w *wallet) IssueCreateAssetTx( initialState map[uint32][]verify.State, options ...common.Option, ) (*txs.Tx, error) { - if err := w.refreshFork(options...); err != nil { + feeCalc, err := w.feeCalculator(options...) + if err != nil { return nil, err } - var ( - feesMan = commonfees.NewManager(w.feeRates) - feeCalc = &fees.Calculator{ - IsEActive: w.isEForkActive, - Config: &config.Config{ - TxFee: w.builder.Context().BaseTxFee, - }, - FeeManager: feesMan, - BlockMaxComplexity: w.blockMaxComplexity, - Codec: builder.Parser.Codec(), - } - ) - utx, err := w.builder.NewCreateAssetTx(name, symbol, denomination, initialState, feeCalc, options...) if err != nil { return nil, err @@ -245,23 +222,11 @@ func (w *wallet) IssueOperationTx( operations []*txs.Operation, options ...common.Option, ) (*txs.Tx, error) { - if err := w.refreshFork(options...); err != nil { + feeCalc, err := w.feeCalculator(options...) + if err != nil { return nil, err } - var ( - feesMan = commonfees.NewManager(w.feeRates) - feeCalc = &fees.Calculator{ - IsEActive: w.isEForkActive, - Config: &config.Config{ - TxFee: w.builder.Context().BaseTxFee, - }, - FeeManager: feesMan, - BlockMaxComplexity: w.blockMaxComplexity, - Codec: builder.Parser.Codec(), - } - ) - utx, err := w.builder.NewOperationTx(operations, feeCalc, options...) if err != nil { return nil, err @@ -273,23 +238,11 @@ func (w *wallet) IssueOperationTxMintFT( outputs map[ids.ID]*secp256k1fx.TransferOutput, options ...common.Option, ) (*txs.Tx, error) { - if err := w.refreshFork(options...); err != nil { + feeCalc, err := w.feeCalculator(options...) + if err != nil { return nil, err } - var ( - feesMan = commonfees.NewManager(w.feeRates) - feeCalc = &fees.Calculator{ - IsEActive: w.isEForkActive, - Config: &config.Config{ - TxFee: w.builder.Context().BaseTxFee, - }, - FeeManager: feesMan, - BlockMaxComplexity: w.blockMaxComplexity, - Codec: builder.Parser.Codec(), - } - ) - utx, err := w.builder.NewOperationTxMintFT(outputs, feeCalc, options...) if err != nil { return nil, err @@ -303,23 +256,11 @@ func (w *wallet) IssueOperationTxMintNFT( owners []*secp256k1fx.OutputOwners, options ...common.Option, ) (*txs.Tx, error) { - if err := w.refreshFork(options...); err != nil { + feeCalc, err := w.feeCalculator(options...) + if err != nil { return nil, err } - var ( - feesMan = commonfees.NewManager(w.feeRates) - feeCalc = &fees.Calculator{ - IsEActive: w.isEForkActive, - Config: &config.Config{ - TxFee: w.builder.Context().BaseTxFee, - }, - FeeManager: feesMan, - BlockMaxComplexity: w.blockMaxComplexity, - Codec: builder.Parser.Codec(), - } - ) - utx, err := w.builder.NewOperationTxMintNFT(assetID, payload, owners, feeCalc, options...) if err != nil { return nil, err @@ -332,23 +273,11 @@ func (w *wallet) IssueOperationTxMintProperty( owner *secp256k1fx.OutputOwners, options ...common.Option, ) (*txs.Tx, error) { - if err := w.refreshFork(options...); err != nil { + feeCalc, err := w.feeCalculator(options...) + if err != nil { return nil, err } - var ( - feesMan = commonfees.NewManager(w.feeRates) - feeCalc = &fees.Calculator{ - IsEActive: w.isEForkActive, - Config: &config.Config{ - TxFee: w.builder.Context().BaseTxFee, - }, - FeeManager: feesMan, - BlockMaxComplexity: w.blockMaxComplexity, - Codec: builder.Parser.Codec(), - } - ) - utx, err := w.builder.NewOperationTxMintProperty(assetID, owner, feeCalc, options...) if err != nil { return nil, err @@ -360,23 +289,11 @@ func (w *wallet) IssueOperationTxBurnProperty( assetID ids.ID, options ...common.Option, ) (*txs.Tx, error) { - if err := w.refreshFork(options...); err != nil { + feeCalc, err := w.feeCalculator(options...) + if err != nil { return nil, err } - var ( - feesMan = commonfees.NewManager(w.feeRates) - feeCalc = &fees.Calculator{ - IsEActive: w.isEForkActive, - Config: &config.Config{ - TxFee: w.builder.Context().BaseTxFee, - }, - FeeManager: feesMan, - BlockMaxComplexity: w.blockMaxComplexity, - Codec: builder.Parser.Codec(), - } - ) - utx, err := w.builder.NewOperationTxBurnProperty(assetID, feeCalc, options...) if err != nil { return nil, err @@ -389,23 +306,11 @@ func (w *wallet) IssueImportTx( to *secp256k1fx.OutputOwners, options ...common.Option, ) (*txs.Tx, error) { - if err := w.refreshFork(options...); err != nil { + feeCalc, err := w.feeCalculator(options...) + if err != nil { return nil, err } - var ( - feesMan = commonfees.NewManager(w.feeRates) - feeCalc = &fees.Calculator{ - IsEActive: w.isEForkActive, - Config: &config.Config{ - TxFee: w.builder.Context().BaseTxFee, - }, - FeeManager: feesMan, - BlockMaxComplexity: w.blockMaxComplexity, - Codec: builder.Parser.Codec(), - } - ) - utx, err := w.builder.NewImportTx(chainID, to, feeCalc, options...) if err != nil { return nil, err @@ -418,23 +323,11 @@ func (w *wallet) IssueExportTx( outputs []*avax.TransferableOutput, options ...common.Option, ) (*txs.Tx, error) { - if err := w.refreshFork(options...); err != nil { + feeCalc, err := w.feeCalculator(options...) + if err != nil { return nil, err } - var ( - feesMan = commonfees.NewManager(w.feeRates) - feeCalc = &fees.Calculator{ - IsEActive: w.isEForkActive, - Config: &config.Config{ - TxFee: w.builder.Context().BaseTxFee, - }, - FeeManager: feesMan, - BlockMaxComplexity: w.blockMaxComplexity, - Codec: builder.Parser.Codec(), - } - ) - utx, err := w.builder.NewExportTx(chainID, outputs, feeCalc, options...) if err != nil { return nil, err @@ -520,3 +413,20 @@ func (w *wallet) refreshFork(options ...common.Option) error { w.blockMaxComplexity = config.GetDynamicFeesConfig(w.isEForkActive).BlockMaxComplexity return nil } + +func (w *wallet) feeCalculator(options ...common.Option) (*fees.Calculator, error) { + if err := w.refreshFork(options...); err != nil { + return nil, fmt.Errorf("failed refreshing dynamic fees data: %w", err) + } + + feesMan := commonfees.NewManager(w.feeRates) + return &fees.Calculator{ + IsEActive: w.isEForkActive, + Config: &config.Config{ + TxFee: w.builder.Context().BaseTxFee, + }, + FeeManager: feesMan, + BlockMaxComplexity: w.blockMaxComplexity, + Codec: builder.Parser.Codec(), + }, nil +} From 10524b5064a7c3aed5345ea8feb66df7394215f1 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 28 Mar 2024 11:54:24 +0100 Subject: [PATCH 127/132] wip: fixing e2e tests --- tests/e2e/p/workflow.go | 2 +- tests/e2e/x/dynamic_fees.go | 8 +++----- vms/avm/config/dynamic_fees_config.go | 2 +- wallet/chain/x/wallet.go | 8 ++++---- 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/tests/e2e/p/workflow.go b/tests/e2e/p/workflow.go index f16ee9b300dc..da56a8120321 100644 --- a/tests/e2e/p/workflow.go +++ b/tests/e2e/p/workflow.go @@ -190,7 +190,7 @@ var _ = e2e.DescribePChain("[Workflow]", func() { // retrieve fees paid for the tx feeCfg := config.GetDynamicFeesConfig(true /*isEActive*/) - _, feeRates, err := xChainClient.GetFeeRates(e2e.DefaultContext()) + feeRates, _, err := xChainClient.GetFeeRates(e2e.DefaultContext()) require.NoError(err) feeCalc := fees.Calculator{ diff --git a/tests/e2e/x/dynamic_fees.go b/tests/e2e/x/dynamic_fees.go index 00e13ccbb652..6f78cd463d45 100644 --- a/tests/e2e/x/dynamic_fees.go +++ b/tests/e2e/x/dynamic_fees.go @@ -4,8 +4,6 @@ package x import ( - "math" - "github.com/stretchr/testify/require" "github.com/ava-labs/avalanchego/ids" @@ -28,11 +26,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{2, 2, 2, 2}, - BlockMaxComplexity: commonfees.Dimensions{math.MaxUint64, math.MaxUint64, math.MaxUint64, math.MaxUint64}, + UpdateCoefficient: commonfees.Dimensions{1, 1, 1, 1}, + BlockMaxComplexity: commonfees.Max, // BlockUnitsTarget are set to cause an increase of fees while simple transactions are issued - BlockTargetComplexityRate: commonfees.Dimensions{300, 50, 150, 800}, + BlockTargetComplexityRate: commonfees.Dimensions{300, 80, 150, 800}, } ginkgo.By("creating a new private network to ensure isolation from other tests") diff --git a/vms/avm/config/dynamic_fees_config.go b/vms/avm/config/dynamic_fees_config.go index 67fda0aef057..3d7c469c204b 100644 --- a/vms/avm/config/dynamic_fees_config.go +++ b/vms/avm/config/dynamic_fees_config.go @@ -36,7 +36,7 @@ var ( 1, }, BlockMaxComplexity: commonfees.Max, - BlockTargetComplexityRate: commonfees.Dimensions{1, 1, 1, 1}, + BlockTargetComplexityRate: commonfees.Dimensions{1000, 1000, 1000, 2000}, } // TODO ABENEGIA: decide if and how to validate preEUpgradeDynamicFeesConfig diff --git a/wallet/chain/x/wallet.go b/wallet/chain/x/wallet.go index 597a37a33037..3c5642b5ef18 100644 --- a/wallet/chain/x/wallet.go +++ b/wallet/chain/x/wallet.go @@ -171,8 +171,8 @@ type wallet struct { signer signer.Signer client avm.Client - isEForkActive bool - feeRates, blockMaxComplexity commonfees.Dimensions + isEForkActive bool + nextFeeRates, blockMaxComplexity commonfees.Dimensions } func (w *wallet) Builder() builder.Builder { @@ -396,7 +396,7 @@ func (w *wallet) refreshFork(options ...common.Option) error { err error ) - _, w.feeRates, err = w.client.GetFeeRates(ctx) + _, w.nextFeeRates, err = w.client.GetFeeRates(ctx) if err != nil { return err } @@ -419,7 +419,7 @@ func (w *wallet) feeCalculator(options ...common.Option) (*fees.Calculator, erro return nil, fmt.Errorf("failed refreshing dynamic fees data: %w", err) } - feesMan := commonfees.NewManager(w.feeRates) + feesMan := commonfees.NewManager(w.nextFeeRates) return &fees.Calculator{ IsEActive: w.isEForkActive, Config: &config.Config{ From 6e561d61ddbb70ca4eed8773c18624cacad2958f Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 28 Mar 2024 14:30:21 +0100 Subject: [PATCH 128/132] fixed e2e test --- tests/e2e/x/transfer/virtuous.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/tests/e2e/x/transfer/virtuous.go b/tests/e2e/x/transfer/virtuous.go index 3a3fb7ef9768..b48429dd01e6 100644 --- a/tests/e2e/x/transfer/virtuous.go +++ b/tests/e2e/x/transfer/virtuous.go @@ -172,6 +172,13 @@ var _ = e2e.DescribeXChainSerial("[Virtuous Transfer Tx AVAX]", func() { require.Contains(err.Error(), "insufficient funds") }) + // retrieve the unit fees that will be used for the BaseTx + feeCfg := config.GetDynamicFeesConfig(true /*isEActive*/) + nodeURI := e2e.Env.GetRandomNodeURI() + xChainClient := avm.NewClient(nodeURI.URI, "X") + _, feeRates, err := xChainClient.GetFeeRates(e2e.DefaultContext()) + require.NoError(err) + tx, err := wallets[fromIdx].X().IssueBaseTx( []*avax.TransferableOutput{{ Asset: avax.Asset{ @@ -190,11 +197,6 @@ var _ = e2e.DescribeXChainSerial("[Virtuous Transfer Tx AVAX]", func() { require.NoError(err) // retrieve fees paid for the BaseTx - feeCfg := config.GetDynamicFeesConfig(true /*isEActive*/) - nodeURI := e2e.Env.GetRandomNodeURI() - xChainClient := avm.NewClient(nodeURI.URI, "X") - _, feeRates, err := xChainClient.GetFeeRates(e2e.DefaultContext()) - require.NoError(err) feeCalc := fees.Calculator{ IsEActive: true, FeeManager: commonfees.NewManager(feeRates), From fd4b4f086c53c2d76096805f5fca8038e58e647c Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 29 Apr 2024 10:57:06 +0200 Subject: [PATCH 129/132] update fee update algo --- vms/components/fees/manager.go | 74 +++++++--- vms/components/fees/manager_test.go | 213 +++++++++++++++++++++------- 2 files changed, 212 insertions(+), 75 deletions(-) diff --git a/vms/components/fees/manager.go b/vms/components/fees/manager.go index 269503ddabac..85ee1f539064 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(1_000) + type Manager struct { // Avax denominated fee rates, i.e. fees per unit of complexity. feeRates Dimensions @@ -116,14 +119,30 @@ func (m *Manager) UpdateFeeRates( return nil } -func nextFeeRate(currentFeeRate, coeff, parentBlkComplexity, targetComplexityRate, elapsedTime uint64) uint64 { +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 approximate the exponential as follows: + // + // 1 + k * delta^2 if delta >= 0 + // feeRate_{t+1} = feeRate_t * + // 1 / (1 + k * delta^2) if delta < 0 // - // 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 + // 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) @@ -132,22 +151,37 @@ func nextFeeRate(currentFeeRate, coeff, parentBlkComplexity, targetComplexityRat targetComplexity = math.MaxUint64 } - switch { - 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(currentFeeRate, 1< Date: Mon, 29 Apr 2024 11:39:32 +0200 Subject: [PATCH 130/132] removed fee tests flakiness --- vms/avm/service_test.go | 100 +++++++++++++++++++++++++++------------- vms/avm/vm_test.go | 5 ++ 2 files changed, 73 insertions(+), 32 deletions(-) diff --git a/vms/avm/service_test.go b/vms/avm/service_test.go index 638c0cff17b3..5d325b9ad35b 100644 --- a/vms/avm/service_test.go +++ b/vms/avm/service_test.go @@ -554,6 +554,10 @@ func TestServiceGetTxJSON_BaseTx(t *testing.T) { env.vm.ctx.Lock.Unlock() }() + // to avoid tests flackiness we fix clock time wrt chain time + // so to have stable updated fee rates. + env.vm.clock.Set(env.vm.state.GetTimestamp().Add(time.Second)) + newTx := newAvaxBaseTxWithOutputs(t, env) issueAndAccept(require, env.vm, env.issuer, newTx) @@ -592,7 +596,7 @@ func TestServiceGetTxJSON_BaseTx(t *testing.T) { "addresses": [ "X-testing1d6kkj0qh4wcmus3tk59npwt3rluc6en72ngurd" ], - "amount": 999995542, + "amount": 999992084, "locktime": 0, "threshold": 1 } @@ -651,6 +655,10 @@ func TestServiceGetTxJSON_ExportTx(t *testing.T) { env.vm.ctx.Lock.Unlock() }() + // to avoid tests flackiness we fix clock time wrt chain time + // so to have stable updated fee rates. + env.vm.clock.Set(env.vm.state.GetTimestamp().Add(time.Second)) + newTx := buildTestExportTx(t, env, env.vm.ctx.CChainID) issueAndAccept(require, env.vm, env.issuer, newTx) @@ -676,7 +684,7 @@ func TestServiceGetTxJSON_ExportTx(t *testing.T) { "addresses": [ "X-testing1lnk637g0edwnqc2tn8tel39652fswa3xk4r65e" ], - "amount": 999995486, + "amount": 999991972, "locktime": 0, "threshold": 1 } @@ -754,6 +762,10 @@ func TestServiceGetTxJSON_CreateAssetTx(t *testing.T) { env.vm.ctx.Lock.Unlock() }() + // to avoid tests flackiness we fix clock time wrt chain time + // so to have stable updated fee rates. + env.vm.clock.Set(env.vm.state.GetTimestamp().Add(time.Second)) + initialStates := map[uint32][]verify.State{ uint32(0): { &nftfx.MintOutput{ @@ -825,7 +837,7 @@ func TestServiceGetTxJSON_CreateAssetTx(t *testing.T) { "addresses": [ "X-testing1lnk637g0edwnqc2tn8tel39652fswa3xk4r65e" ], - "amount": 999996286, + "amount": 999992572, "locktime": 0, "threshold": 1 } @@ -920,7 +932,7 @@ func TestServiceGetTxJSON_CreateAssetTx(t *testing.T) { "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", "credential": { "signatures": [ - "0xf1d2a476b36e07debd906c4aae0238e9d1275c1cfd806ceeb8968818d3df0ad524cdae56b687fde9dbd0a18739da7656d140a675766c164e38af726fa822ad2100" + "0xe943dfd81049dc87f0acecd7a94f2b42717891f230ce04d73fe501c9d4e29f8b5fcd3c6b763f1074da01799fb782d221bc6f5fdebce41180b18bd6aa1cff91c700" ] } } @@ -951,6 +963,10 @@ func TestServiceGetTxJSON_OperationTxWithNftxMintOp(t *testing.T) { env.vm.ctx.Lock.Unlock() }() + // to avoid tests flackiness we fix clock time wrt chain time + // so to have stable updated fee rates. + env.vm.clock.Set(env.vm.state.GetTimestamp().Add(time.Second)) + key := keys[0] initialStates := map[uint32][]verify.State{ uint32(1): { @@ -1000,7 +1016,7 @@ func TestServiceGetTxJSON_OperationTxWithNftxMintOp(t *testing.T) { "addresses": [ "X-testing1lnk637g0edwnqc2tn8tel39652fswa3xk4r65e" ], - "amount": 999994946, + "amount": 999988192, "locktime": 0, "threshold": 1 } @@ -1008,12 +1024,12 @@ func TestServiceGetTxJSON_OperationTxWithNftxMintOp(t *testing.T) { ], "inputs": [ { - "txID": "5qm7raFsDQzXgWJ77ygRZ1Ey4qd1ru5sMhcB8iirkKyQQ736D", + "txID": "L46hctVP2oNMKje6VQdk6bSxbXbi2BCgWvWWmHhFJ3yGZMTJc", "outputIndex": 0, "assetID": "tvLKci3hNoCX4NijS6TfiT6XJJY3gGKd2git6SSVTG5J8Nfby", "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", "input": { - "amount": 999996646, + "amount": 999993292, "signatureIndices": [ 0 ] @@ -1057,7 +1073,7 @@ func TestServiceGetTxJSON_OperationTxWithNftxMintOp(t *testing.T) { "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", "credential": { "signatures": [ - "0x63ce475c0f2abf1d98c68034bdf1409c2ab6e0120753013886f184e5b13b85356ff793fdd38a5b6877022e0e584c610d6b3e077133ed8a7efab36fa631dcf34e01" + "0x3ca34a1e672a4d34b0ac30df5b90c0afeda87702464d13e9e69fb6173ae3537b5736c2d72848d86d99d7f91b3475abfba9c0cc32b10a9e29393144e4dedaf44800" ] } }, @@ -1065,7 +1081,7 @@ func TestServiceGetTxJSON_OperationTxWithNftxMintOp(t *testing.T) { "fxID": "qd2U4HDWUvMrVUeTcCHp6xH3Qpnn1XbU5MDdnBoiifFqvgXwT", "credential": { "signatures": [ - "0x63ce475c0f2abf1d98c68034bdf1409c2ab6e0120753013886f184e5b13b85356ff793fdd38a5b6877022e0e584c610d6b3e077133ed8a7efab36fa631dcf34e01" + "0x3ca34a1e672a4d34b0ac30df5b90c0afeda87702464d13e9e69fb6173ae3537b5736c2d72848d86d99d7f91b3475abfba9c0cc32b10a9e29393144e4dedaf44800" ] } } @@ -1102,6 +1118,10 @@ func TestServiceGetTxJSON_OperationTxWithMultipleNftxMintOp(t *testing.T) { env.vm.ctx.Lock.Unlock() }() + // to avoid tests flackiness we fix clock time wrt chain time + // so to have stable updated fee rates. + env.vm.clock.Set(env.vm.state.GetTimestamp().Add(time.Second)) + key := keys[0] initialStates := map[uint32][]verify.State{ uint32(0): { @@ -1154,7 +1174,7 @@ func TestServiceGetTxJSON_OperationTxWithMultipleNftxMintOp(t *testing.T) { "addresses": [ "X-testing1lnk637g0edwnqc2tn8tel39652fswa3xk4r65e" ], - "amount": 999994793, + "amount": 999987749, "locktime": 0, "threshold": 1 } @@ -1162,12 +1182,12 @@ func TestServiceGetTxJSON_OperationTxWithMultipleNftxMintOp(t *testing.T) { ], "inputs": [ { - "txID": "yKvG3o8msJ7QAv2T6pvqPbTc1hJpaFUhvsHepRZ9MayMLw2w6", + "txID": "2aTrnk4R7eRdaZjYi6JwwVmKkce8xqbXDubYE54q4ojUbkGx51", "outputIndex": 0, "assetID": "tvLKci3hNoCX4NijS6TfiT6XJJY3gGKd2git6SSVTG5J8Nfby", "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", "input": { - "amount": 999996630, + "amount": 999993260, "signatureIndices": [ 0 ] @@ -1239,7 +1259,7 @@ func TestServiceGetTxJSON_OperationTxWithMultipleNftxMintOp(t *testing.T) { "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", "credential": { "signatures": [ - "0xc222a8cd263bab6f3895b4623df8ca4346b02c32c9adc63c56d0c7dad5db5d7a0dd7e17ce07cec024de546015868239d04cff92f1c9fc46a9b54426f15d9ab1801" + "0x659fa1e905ccdb514746cee3f009d138e7a627504d9d1ac1f0bacfb31cef8250040db7ef63d6b941d3ffcbbd1f32ef236210a303d454a63ab9c7a1a51a07496c01" ] } }, @@ -1247,7 +1267,7 @@ func TestServiceGetTxJSON_OperationTxWithMultipleNftxMintOp(t *testing.T) { "fxID": "qd2U4HDWUvMrVUeTcCHp6xH3Qpnn1XbU5MDdnBoiifFqvgXwT", "credential": { "signatures": [ - "0xc222a8cd263bab6f3895b4623df8ca4346b02c32c9adc63c56d0c7dad5db5d7a0dd7e17ce07cec024de546015868239d04cff92f1c9fc46a9b54426f15d9ab1801" + "0x659fa1e905ccdb514746cee3f009d138e7a627504d9d1ac1f0bacfb31cef8250040db7ef63d6b941d3ffcbbd1f32ef236210a303d454a63ab9c7a1a51a07496c01" ] } }, @@ -1292,6 +1312,10 @@ func TestServiceGetTxJSON_OperationTxWithSecpMintOp(t *testing.T) { env.vm.ctx.Lock.Unlock() }() + // to avoid tests flackiness we fix clock time wrt chain time + // so to have stable updated fee rates. + env.vm.clock.Set(env.vm.state.GetTimestamp().Add(time.Second)) + key := keys[0] initialStates := map[uint32][]verify.State{ uint32(0): { @@ -1338,7 +1362,7 @@ func TestServiceGetTxJSON_OperationTxWithSecpMintOp(t *testing.T) { "addresses": [ "X-testing1lnk637g0edwnqc2tn8tel39652fswa3xk4r65e" ], - "amount": 999994927, + "amount": 999988127, "locktime": 0, "threshold": 1 } @@ -1346,12 +1370,12 @@ func TestServiceGetTxJSON_OperationTxWithSecpMintOp(t *testing.T) { ], "inputs": [ { - "txID": "2Pb53uW6P9BpQ9pN4PNffTi8AcLgeALjtTSFTeTL65baHicAR5", + "txID": "2amsBFNL9FXTY7A3jZegVgC2fkYcoSVAzUsoh4ywmrCbQXYYDt", "outputIndex": 0, "assetID": "tvLKci3hNoCX4NijS6TfiT6XJJY3gGKd2git6SSVTG5J8Nfby", "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", "input": { - "amount": 999996654, + "amount": 999993308, "signatureIndices": [ 0 ] @@ -1399,7 +1423,7 @@ func TestServiceGetTxJSON_OperationTxWithSecpMintOp(t *testing.T) { "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", "credential": { "signatures": [ - "0x67c966f5571b51b25d7890366ecc5548251618966ae1d20bddb89442999e8fda3691619295fdb821e1e8d16fc05e29e4d661535712143b84f1a43070a5e669db01" + "0x3398fcc938cf42475a65d1d748e782d0d5be8b0b9039a210e6abe943983953e451fceccc283eda0a93859ac920d0cf45e63b7f326667f7e79ae0573192556f4a00" ] } }, @@ -1407,7 +1431,7 @@ func TestServiceGetTxJSON_OperationTxWithSecpMintOp(t *testing.T) { "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", "credential": { "signatures": [ - "0x67c966f5571b51b25d7890366ecc5548251618966ae1d20bddb89442999e8fda3691619295fdb821e1e8d16fc05e29e4d661535712143b84f1a43070a5e669db01" + "0x3398fcc938cf42475a65d1d748e782d0d5be8b0b9039a210e6abe943983953e451fceccc283eda0a93859ac920d0cf45e63b7f326667f7e79ae0573192556f4a00" ] } } @@ -1444,6 +1468,10 @@ func TestServiceGetTxJSON_OperationTxWithMultipleSecpMintOp(t *testing.T) { env.vm.ctx.Lock.Unlock() }() + // to avoid tests flackiness we fix clock time wrt chain time + // so to have stable updated fee rates. + env.vm.clock.Set(env.vm.state.GetTimestamp().Add(time.Second)) + key := keys[0] initialStates := map[uint32][]verify.State{ uint32(0): { @@ -1494,7 +1522,7 @@ func TestServiceGetTxJSON_OperationTxWithMultipleSecpMintOp(t *testing.T) { "addresses": [ "X-testing1lnk637g0edwnqc2tn8tel39652fswa3xk4r65e" ], - "amount": 999994755, + "amount": 999987619, "locktime": 0, "threshold": 1 } @@ -1502,12 +1530,12 @@ func TestServiceGetTxJSON_OperationTxWithMultipleSecpMintOp(t *testing.T) { ], "inputs": [ { - "txID": "2SbcXEUatKafkjWi7ZAnTqjzumyHLM6LNSy2PC5PTqThdibZLZ", + "txID": "2XFtZCtpqfcQC8zGDTSfyy8v5ks2WX83Dj4iXfoUjcEcHBA1CJ", "outputIndex": 0, "assetID": "tvLKci3hNoCX4NijS6TfiT6XJJY3gGKd2git6SSVTG5J8Nfby", "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", "input": { - "amount": 999996646, + "amount": 999993292, "signatureIndices": [ 0 ] @@ -1595,7 +1623,7 @@ func TestServiceGetTxJSON_OperationTxWithMultipleSecpMintOp(t *testing.T) { "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", "credential": { "signatures": [ - "0xf592dc536526516c8df78d787845bb6ae367b0ae62a6db93e4ebc010347c15c704665dc2c6cca3acba2af45190c92fd038e3831aa72f9dad63cce6d56b53fe1e01" + "0xd47a9aadf3acb5e46eca69104142c0c9a5b1db36c47255b0b764f56a4e3d0d4769a4a6bb1ca3d5159722635198d1edb85d4914c3732a391a4e8a96cb84205ad001" ] } }, @@ -1603,7 +1631,7 @@ func TestServiceGetTxJSON_OperationTxWithMultipleSecpMintOp(t *testing.T) { "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", "credential": { "signatures": [ - "0xf592dc536526516c8df78d787845bb6ae367b0ae62a6db93e4ebc010347c15c704665dc2c6cca3acba2af45190c92fd038e3831aa72f9dad63cce6d56b53fe1e01" + "0xd47a9aadf3acb5e46eca69104142c0c9a5b1db36c47255b0b764f56a4e3d0d4769a4a6bb1ca3d5159722635198d1edb85d4914c3732a391a4e8a96cb84205ad001" ] } } @@ -1640,6 +1668,10 @@ func TestServiceGetTxJSON_OperationTxWithPropertyFxMintOp(t *testing.T) { env.vm.ctx.Lock.Unlock() }() + // to avoid tests flackiness we fix clock time wrt chain time + // so to have stable updated fee rates. + env.vm.clock.Set(env.vm.state.GetTimestamp().Add(time.Second)) + key := keys[0] initialStates := map[uint32][]verify.State{ uint32(2): { @@ -1681,7 +1713,7 @@ func TestServiceGetTxJSON_OperationTxWithPropertyFxMintOp(t *testing.T) { "addresses": [ "X-testing1lnk637g0edwnqc2tn8tel39652fswa3xk4r65e" ], - "amount": 999995043, + "amount": 999988387, "locktime": 0, "threshold": 1 } @@ -1689,12 +1721,12 @@ func TestServiceGetTxJSON_OperationTxWithPropertyFxMintOp(t *testing.T) { ], "inputs": [ { - "txID": "2QaaDARUZ3uEiGwFfdzhNQUNdFtJVqw7fDevM9evcqsCEyjXo7", + "txID": "2qYV13hjDYcy8KQTCT4pUGdN29MTqGHdcgXuZhHhrHAVW4W3Cu", "outputIndex": 0, "assetID": "tvLKci3hNoCX4NijS6TfiT6XJJY3gGKd2git6SSVTG5J8Nfby", "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", "input": { - "amount": 999996742, + "amount": 999993484, "signatureIndices": [ 0 ] @@ -1739,7 +1771,7 @@ func TestServiceGetTxJSON_OperationTxWithPropertyFxMintOp(t *testing.T) { "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", "credential": { "signatures": [ - "0x8c3c994f62e60944c73bab594c8ece929c99b0cc6cb5e67adf760e0ebaa210316599f1e9c51f4e8a703c7e6731a34ff710f06c511875be8d9f834dfd8e05596e01" + "0x5d55e6489ba9884d9fc88e1447d55e6a0fab85957e2afce004d85c5f34ce061e68c905707941fe16f59eb15df1ab1067c90c3102fea9e60d2ab505fbdf2d06fe00" ] } }, @@ -1784,6 +1816,10 @@ func TestServiceGetTxJSON_OperationTxWithPropertyFxMintOpMultiple(t *testing.T) env.vm.ctx.Lock.Unlock() }() + // to avoid tests flackiness we fix clock time wrt chain time + // so to have stable updated fee rates. + env.vm.clock.Set(env.vm.state.GetTimestamp().Add(time.Second)) + key := keys[0] initialStates := map[uint32][]verify.State{ uint32(2): { @@ -1832,7 +1868,7 @@ func TestServiceGetTxJSON_OperationTxWithPropertyFxMintOpMultiple(t *testing.T) "addresses": [ "X-testing1lnk637g0edwnqc2tn8tel39652fswa3xk4r65e" ], - "amount": 999994827, + "amount": 999987819, "locktime": 0, "threshold": 1 } @@ -1840,12 +1876,12 @@ func TestServiceGetTxJSON_OperationTxWithPropertyFxMintOpMultiple(t *testing.T) ], "inputs": [ { - "txID": "27GtULJnoV8AsmqF12nrPE6sMfLpmWxPWdCtnAHFbN1M9p39pG", + "txID": "vu6reemKheEHERYDUArcb6U1T3CJWP149ux1Liga1LrcoH7ta", "outputIndex": 0, "assetID": "tvLKci3hNoCX4NijS6TfiT6XJJY3gGKd2git6SSVTG5J8Nfby", "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", "input": { - "amount": 999996662, + "amount": 999993324, "signatureIndices": [ 0 ] @@ -1919,7 +1955,7 @@ func TestServiceGetTxJSON_OperationTxWithPropertyFxMintOpMultiple(t *testing.T) "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ", "credential": { "signatures": [ - "0xd3a729b8eea5a36ba20f376e190bac4eeaa634351bdf769baf74ce3c8bd4cb860ad85276ca1c9efd059a83690dee1f6d21bc2cf955c3a481cd67722be06d4d7601" + "0xbe32eb12a68afae7955b88519c4499ce045f8883076410573fdf00f47139f1533be66ffcce307426a828b8c9a1ea719eb2197bab033e88f0ce05fecdb61d438601" ] } }, diff --git a/vms/avm/vm_test.go b/vms/avm/vm_test.go index dde741e5d9d1..8e0279cca24d 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" @@ -741,6 +742,10 @@ func TestClearForceAcceptedExportTx(t *testing.T) { env.vm.ctx.Lock.Unlock() }() + // to avoid tests flackiness we fix clock time wrt chain time + // so to have stable updated fee rates. + env.vm.clock.Set(env.vm.state.GetTimestamp().Add(time.Second)) + genesisTx := getCreateTxFromGenesisTest(t, env.genesisBytes, "AVAX") var ( From 52f28c80e86033f5b69cac2123d6e6f4004eeb91 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 2 May 2024 13:56:23 +0200 Subject: [PATCH 131/132] aligned fee update algo --- vms/components/fees/manager.go | 16 +++-- vms/components/fees/manager_test.go | 108 ++++++++++++++-------------- 2 files changed, 66 insertions(+), 58 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]) } From b9fbcc8910db06b94279cace0734dfde29774a50 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 9 May 2024 12:01:58 +0200 Subject: [PATCH 132/132] fixed update fee algo --- vms/components/fees/manager.go | 157 +++++++++++++++++++--------- vms/components/fees/manager_test.go | 116 +++++++++++++------- 2 files changed, 188 insertions(+), 85 deletions(-) diff --git a/vms/components/fees/manager.go b/vms/components/fees/manager.go index d5cdf29021f3..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. @@ -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, @@ -106,46 +121,30 @@ func (m *Manager) UpdateFeeRates( elapsedTime := uint64(childBlkTime - parentBlkTime) for i := Dimension(0); i < FeeDimensions; i++ { - nextFeeRates := nextFeeRate( - m.feeRates[i], - feesConfig.UpdateCoefficient[i], - parentBlkComplexity[i], - feesConfig.BlockMaxComplexity[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 nextFeeRate( - currentFeeRate, - coeff, - parentBlkComplexity, - maxBlockComplexity, - targetComplexityRate, - elapsedTime uint64, -) uint64 { - // We update the fee rate with the formula: - // 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 approximate the exponential as follows: - // - // 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. - +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) @@ -156,9 +155,23 @@ func nextFeeRate( // regardless how low network load has been, we won't allow // blocks larger than max block complexity targetComplexity = min(targetComplexity, maxBlockComplexity) + return targetComplexity +} - if parentBlkComplexity == targetComplexity { - return currentFeeRate // complexity matches target, nothing to update +// 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 ( @@ -166,28 +179,78 @@ func nextFeeRate( delta uint64 ) - if targetComplexity < parentBlkComplexity { + if t < b { increaseFee = true - delta = parentBlkComplexity - targetComplexity + delta = b - t } else { increaseFee = false - delta = targetComplexity - parentBlkComplexity + delta = t - b } - num := coeff * coeff * delta * delta - denom := targetComplexity * targetComplexity * CoeffDenom * CoeffDenom + 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 { - res, over := safemath.Mul64(currentFeeRate, denom+num) - if over != nil { - res = math.MaxUint64 - } - return res / denom + 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. + var ( + m, q uint64 + sign bool + ) + + 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 } - res, over := safemath.Mul64(currentFeeRate, denom) + // 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 { - res = math.MaxUint64 + 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 res / (denom + num) + return n, b } diff --git a/vms/components/fees/manager_test.go b/vms/components/fees/manager_test.go index 453979550c3b..922183102f93 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" @@ -13,18 +14,13 @@ import ( "github.com/ava-labs/avalanchego/utils/units" ) -type blkTimeAndComplexity struct { - blkTime int64 - complexity Dimensions -} - func TestUpdateFeeRates(t *testing.T) { require := require.New(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}, } @@ -48,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(99), m.feeRates[UTXOWrite]) + require.Equal(uint64(90), 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(125), m.feeRates[Compute]) } func TestUpdateFeeRatesStability(t *testing.T) { @@ -137,16 +133,16 @@ func TestPChainFeeRateIncreaseDueToPeak(t *testing.T) { 35 * units.NanoAvax, }, UpdateCoefficient: Dimensions{ // over CoeffDenom - 5, - 2, + 3, + 1, + 1, 2, - 4, }, BlockTargetComplexityRate: Dimensions{ - 250, - 60, - 120, - 650, + 2500, + 600, + 1200, + 6500, }, BlockMaxComplexity: Dimensions{ 100_000, @@ -157,7 +153,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}}, @@ -172,26 +171,25 @@ 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{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}}, <-- 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}}, } ) @@ -249,3 +247,45 @@ 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) + } +}