From 10d71e74ec6b1b590204e5d23cb5551e00702b2a Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 8 Jan 2024 10:33:16 +0100 Subject: [PATCH 01/80] 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 02/80] 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 03/80] 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 04/80] 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 05/80] 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 06/80] 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 07/80] 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 08/80] 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 09/80] 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 10/80] 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 11/80] 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 12/80] 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 13/80] 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 14/80] 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 15/80] 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 16/80] 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 17/80] 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 18/80] 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 19/80] 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 20/80] 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 21/80] 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 22/80] 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 23/80] 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 24/80] 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 25/80] 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 26/80] 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 27/80] 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 28/80] 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 29/80] 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 30/80] 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 31/80] 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 32/80] 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 33/80] 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 34/80] 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 35/80] 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 36/80] 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 37/80] 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 38/80] 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 39/80] 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 40/80] 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 41/80] 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 42/80] 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 43/80] 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 44/80] 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 45/80] 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 524631c04efac7cad01b1154980b0164a9e4852a Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 18 Jan 2024 12:13:46 +0100 Subject: [PATCH 46/80] 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 057a4e4d8902a6a457c1747d7b63f334189c362c Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 22 Jan 2024 11:07:00 +0100 Subject: [PATCH 47/80] 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 48/80] 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 49/80] 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 50/80] 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 51/80] 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 52/80] 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 53/80] 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 54/80] 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 55/80] 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 56/80] 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 57/80] 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 58/80] 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 59/80] 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 60/80] 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 61/80] 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 62/80] 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 63/80] 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 64/80] 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 65/80] 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 66/80] 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 67/80] 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 77e5779fbd2885f0567ee942e1aa0c90e7cde322 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Fri, 26 Jan 2024 16:15:05 +0100 Subject: [PATCH 68/80] 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 69/80] 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 70/80] 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 71/80] 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 72/80] 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 73/80] 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 74/80] 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 75/80] 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 76/80] 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 77/80] 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 78/80] 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 79/80] 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 d7f7a577782ea5a492d1bb124269b57ec436ff36 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Sun, 4 Feb 2024 13:42:40 +0100 Subject: [PATCH 80/80] wip:cleanup --- tests/e2e/p/workflow.go | 12 +- vms/components/fees/dimensions.go | 62 ++++++ vms/components/fees/manager.go | 44 +--- vms/platformvm/block/builder/builder.go | 17 +- vms/platformvm/block/builder/helpers_test.go | 11 +- vms/platformvm/block/executor/helpers_test.go | 14 +- vms/platformvm/block/executor/manager.go | 16 +- .../block/executor/proposal_block_test.go | 4 +- .../block/executor/standard_block_test.go | 8 +- vms/platformvm/block/executor/verifier.go | 18 +- .../block/executor/verifier_test.go | 11 +- vms/platformvm/client.go | 19 -- vms/platformvm/config/dynamic_fees_config.go | 45 +++++ vms/platformvm/service.go | 43 ---- vms/platformvm/service_test.go | 57 ------ vms/platformvm/state/diff.go | 21 +- vms/platformvm/state/mock_state.go | 119 ----------- vms/platformvm/state/state.go | 37 +--- vms/platformvm/txs/builder/builder.go | 190 +++--------------- .../txs/executor/atomic_tx_executor.go | 5 +- .../txs/executor/create_chain_test.go | 21 +- .../txs/executor/create_subnet_test.go | 5 +- vms/platformvm/txs/executor/helpers_test.go | 11 +- .../txs/executor/proposal_tx_executor.go | 7 +- .../executor/staker_tx_verification_test.go | 8 +- .../txs/executor/standard_tx_executor_test.go | 132 ++++++------ vms/platformvm/txs/fees/calculator.go | 26 +-- wallet/chain/p/wallet.go | 70 +------ 28 files changed, 282 insertions(+), 751 deletions(-) create mode 100644 vms/components/fees/dimensions.go create mode 100644 vms/platformvm/config/dynamic_fees_config.go diff --git a/tests/e2e/p/workflow.go b/tests/e2e/p/workflow.go index 3dc34afdf9de..a8b30579ec3d 100644 --- a/tests/e2e/p/workflow.go +++ b/tests/e2e/p/workflow.go @@ -19,6 +19,7 @@ import ( "github.com/ava-labs/avalanchego/utils/units" "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/platformvm" + "github.com/ava-labs/avalanchego/vms/platformvm/config" "github.com/ava-labs/avalanchego/vms/platformvm/txs" "github.com/ava-labs/avalanchego/vms/platformvm/txs/fees" "github.com/ava-labs/avalanchego/vms/secp256k1fx" @@ -124,12 +125,6 @@ var _ = e2e.DescribePChain("[Workflow]", func() { pChainExportFee := uint64(0) ginkgo.By("export avax from P to X chain", func() { - 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{ @@ -145,10 +140,11 @@ var _ = e2e.DescribePChain("[Workflow]", func() { require.NoError(err) // retrieve fees paid for the tx + feeCfg := config.EUpgradeDynamicFeesConfig feeCalc := fees.Calculator{ IsEForkActive: true, - FeeManager: commonfees.NewManager(unitFees), - ConsumedUnitsCap: unitCaps, + FeeManager: commonfees.NewManager(feeCfg.UnitFees), + ConsumedUnitsCap: feeCfg.BlockUnitsCap, Credentials: tx.Creds, } diff --git a/vms/components/fees/dimensions.go b/vms/components/fees/dimensions.go new file mode 100644 index 000000000000..31e46e246c7b --- /dev/null +++ b/vms/components/fees/dimensions.go @@ -0,0 +1,62 @@ +// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package fees + +import ( + "encoding/binary" + "fmt" + + "github.com/ava-labs/avalanchego/utils/math" +) + +const ( + Bandwidth Dimension = 0 + UTXORead Dimension = 1 + UTXOWrite Dimension = 2 // includes delete + Compute Dimension = 3 // signatures checks, tx-specific + + FeeDimensions = 4 + + uint64Len = 8 +) + +var Empty = Dimensions{} // helps avoiding reading unit fees from db for some pre E fork processing + +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 +} + +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/manager.go b/vms/components/fees/manager.go index cfcf2beab493..644cf37fa9b1 100644 --- a/vms/components/fees/manager.go +++ b/vms/components/fees/manager.go @@ -6,37 +6,9 @@ package fees import ( "fmt" - "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 @@ -52,16 +24,20 @@ func NewManager(unitFees Dimensions) *Manager { } } +func (m *Manager) GetUnitFees() Dimensions { + return m.unitFees +} + // CalculateFee must be a stateless method 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 +51,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 +62,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 +76,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) } diff --git a/vms/platformvm/block/builder/builder.go b/vms/platformvm/block/builder/builder.go index 0a4af120ba54..6a5be6cf3ad8 100644 --- a/vms/platformvm/block/builder/builder.go +++ b/vms/platformvm/block/builder/builder.go @@ -19,6 +19,7 @@ import ( "github.com/ava-labs/avalanchego/utils/units" "github.com/ava-labs/avalanchego/vms/components/fees" "github.com/ava-labs/avalanchego/vms/platformvm/block" + "github.com/ava-labs/avalanchego/vms/platformvm/config" "github.com/ava-labs/avalanchego/vms/platformvm/state" "github.com/ava-labs/avalanchego/vms/platformvm/status" "github.com/ava-labs/avalanchego/vms/platformvm/txs" @@ -353,6 +354,9 @@ func packBlockTxs( } var ( + feeCfg = config.EUpgradeDynamicFeesConfig + feeMan = fees.NewManager(feeCfg.UnitFees) + blockTxs []*txs.Tx inputs set.Set[ids.ID] ) @@ -375,19 +379,10 @@ func packBlockTxs( return nil, err } - unitFees, err := txDiff.GetUnitFees() - 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, + BlkFeeManager: feeMan, + UnitCaps: feeCfg.BlockUnitsCap, State: txDiff, Tx: tx, } diff --git a/vms/platformvm/block/builder/helpers_test.go b/vms/platformvm/block/builder/helpers_test.go index 3d9e1ebe7a04..8a8515257252 100644 --- a/vms/platformvm/block/builder/helpers_test.go +++ b/vms/platformvm/block/builder/helpers_test.go @@ -255,16 +255,11 @@ 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) - - unitCaps, err := env.state.GetBlockUnitCaps() - require.NoError(err) - + feeCfg := config.EUpgradeDynamicFeesConfig executor := txexecutor.StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(unitFees), - UnitCaps: unitCaps, + BlkFeeManager: fees.NewManager(feeCfg.UnitFees), + UnitCaps: feeCfg.BlockUnitsCap, State: stateDiff, Tx: testSubnet1, } diff --git a/vms/platformvm/block/executor/helpers_test.go b/vms/platformvm/block/executor/helpers_test.go index ebf951c62a2f..ccd320e774a6 100644 --- a/vms/platformvm/block/executor/helpers_test.go +++ b/vms/platformvm/block/executor/helpers_test.go @@ -275,19 +275,11 @@ func addSubnet(env *environment) { panic(err) } - unitFees, err := env.state.GetUnitFees() - if err != nil { - panic(err) - } - unitCaps, err := env.state.GetBlockUnitCaps() - if err != nil { - panic(err) - } - + feeCfg := config.EUpgradeDynamicFeesConfig executor := executor.StandardTxExecutor{ Backend: env.backend, - BlkFeeManager: fees.NewManager(unitFees), - UnitCaps: unitCaps, + BlkFeeManager: fees.NewManager(feeCfg.UnitFees), + UnitCaps: feeCfg.BlockUnitsCap, State: stateDiff, Tx: testSubnet1, } diff --git a/vms/platformvm/block/executor/manager.go b/vms/platformvm/block/executor/manager.go index fe2cbdf10a44..cc6b72a2813e 100644 --- a/vms/platformvm/block/executor/manager.go +++ b/vms/platformvm/block/executor/manager.go @@ -11,6 +11,7 @@ import ( "github.com/ava-labs/avalanchego/utils/set" "github.com/ava-labs/avalanchego/vms/components/fees" "github.com/ava-labs/avalanchego/vms/platformvm/block" + "github.com/ava-labs/avalanchego/vms/platformvm/config" "github.com/ava-labs/avalanchego/vms/platformvm/metrics" "github.com/ava-labs/avalanchego/vms/platformvm/state" "github.com/ava-labs/avalanchego/vms/platformvm/txs" @@ -143,20 +144,11 @@ 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 - } - + feesCfg := config.EUpgradeDynamicFeesConfig err = tx.Unsigned.Visit(&executor.StandardTxExecutor{ Backend: m.txExecutorBackend, - BlkFeeManager: fees.NewManager(unitFees), - UnitCaps: unitCaps, + BlkFeeManager: fees.NewManager(feesCfg.UnitFees), + 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 899c6ce54415..c092558fcf69 100644 --- a/vms/platformvm/block/executor/proposal_block_test.go +++ b/vms/platformvm/block/executor/proposal_block_test.go @@ -26,7 +26,6 @@ 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" ) @@ -141,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 @@ -160,8 +160,6 @@ 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 63424352cc5c..8faf5796554c 100644 --- a/vms/platformvm/block/executor/standard_block_test.go +++ b/vms/platformvm/block/executor/standard_block_test.go @@ -23,7 +23,6 @@ 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" ) @@ -57,8 +56,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) - onParentAccept.EXPECT().GetBlockUnitCaps().Return(fees.EmptyUnitCaps, nil) + // wrong height apricotChildBlk, err := block.NewApricotStandardBlock( apricotParentBlk.ID(), @@ -89,6 +87,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 @@ -152,8 +152,6 @@ 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 8fad999b4119..800a433db5f3 100644 --- a/vms/platformvm/block/executor/verifier.go +++ b/vms/platformvm/block/executor/verifier.go @@ -12,6 +12,7 @@ import ( "github.com/ava-labs/avalanchego/utils/set" "github.com/ava-labs/avalanchego/vms/components/fees" "github.com/ava-labs/avalanchego/vms/platformvm/block" + "github.com/ava-labs/avalanchego/vms/platformvm/config" "github.com/ava-labs/avalanchego/vms/platformvm/state" "github.com/ava-labs/avalanchego/vms/platformvm/status" "github.com/ava-labs/avalanchego/vms/platformvm/txs" @@ -439,28 +440,19 @@ func (v *verifier) processStandardTxs(txs []*txs.Tx, state state.Diff, parentID error, ) { var ( + feesCfg = config.EUpgradeDynamicFeesConfig + 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 - } - 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, + BlkFeeManager: fees.NewManager(feesCfg.UnitFees), + UnitCaps: feesCfg.BlockUnitsCap, State: state, Tx: tx, } diff --git a/vms/platformvm/block/executor/verifier_test.go b/vms/platformvm/block/executor/verifier_test.go index b77c54ac90ba..b22b2765753a 100644 --- a/vms/platformvm/block/executor/verifier_test.go +++ b/vms/platformvm/block/executor/verifier_test.go @@ -26,7 +26,6 @@ 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" ) @@ -233,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{}, }, @@ -286,8 +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(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) @@ -717,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{}, }, @@ -767,8 +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(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/client.go b/vms/platformvm/client.go index 1bccc9382139..9311fd290a7e 100644 --- a/vms/platformvm/client.go +++ b/vms/platformvm/client.go @@ -18,7 +18,6 @@ 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" ) @@ -264,12 +263,6 @@ 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) - - // 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 @@ -898,15 +891,3 @@ 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 -} - -func (c *client) GetBlockUnitsCap(ctx context.Context, options ...rpc.Option) (commonfees.Dimensions, error) { - res := &GetBlockUnitsCapReply{} - err := c.requester.SendRequest(ctx, "platform.getBlockUnitsCap", struct{}{}, res, options...) - return res.MaxUnits, err -} diff --git a/vms/platformvm/config/dynamic_fees_config.go b/vms/platformvm/config/dynamic_fees_config.go new file mode 100644 index 000000000000..d7994896c7da --- /dev/null +++ b/vms/platformvm/config/dynamic_fees_config.go @@ -0,0 +1,45 @@ +// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package config + +import ( + "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 + +// EUpgradeDynamicFeesConfig to be tuned TODO ABENEGIA +var EUpgradeDynamicFeesConfig = DynamicFeesConfig{ + UnitFees: commonfees.Dimensions{ + 1, + 2, + 3, + 4, + }, + + BlockUnitsCap: commonfees.Dimensions{ + math.MaxUint64, + math.MaxUint64, + math.MaxUint64, + math.MaxUint64, + }, +} + +type DynamicFeesConfig struct { + // UnitFees 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. + UnitFees commonfees.Dimensions + + // BlockUnitsCap contains, per each fee dimension, the + // maximal complexity a valid P-chain block can host + BlockUnitsCap commonfees.Dimensions +} diff --git a/vms/platformvm/service.go b/vms/platformvm/service.go index 2a211dd738f6..16e5b16844c6 100644 --- a/vms/platformvm/service.go +++ b/vms/platformvm/service.go @@ -44,7 +44,6 @@ 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" ) @@ -2811,48 +2810,6 @@ 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() - - var err error - reply.UnitFees, err = s.vm.state.GetUnitFees() - return err -} - -// 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() - - var err error - reply.MaxUnits, err = s.vm.state.GetBlockUnitCaps() - return err -} - 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 3700384068c4..d1a156e1acb8 100644 --- a/vms/platformvm/service_test.go +++ b/vms/platformvm/service_test.go @@ -36,7 +36,6 @@ 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" @@ -1014,59 +1013,3 @@ func TestServiceGetBlockByHeight(t *testing.T) { }) } } - -func TestGetUnitFees(t *testing.T) { - require := require.New(t) - service, _ := defaultService(t) - - reply := GetUnitFeesReply{} - require.NoError(service.GetUnitFees(nil, nil, &reply)) - - service.vm.ctx.Lock.Lock() - - unitFees, err := service.vm.state.GetUnitFees() - require.NoError(err) - - require.Equal(unitFees, reply.UnitFees) - - 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(updatedUnitFees, reply.UnitFees) -} - -func TestGetBlockUnitsCap(t *testing.T) { - require := require.New(t) - service, _ := defaultService(t) - - reply := GetBlockUnitsCapReply{} - require.NoError(service.GetBlockUnitsCap(nil, nil, &reply)) - - service.vm.ctx.Lock.Lock() - - unitCaps, err := service.vm.state.GetBlockUnitCaps() - require.NoError(err) - - require.Equal(unitCaps, reply.MaxUnits) - - 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(updatedUnitCaps, reply.MaxUnits) -} diff --git a/vms/platformvm/state/diff.go b/vms/platformvm/state/diff.go index d6fa41fcbe01..ebdd3363f705 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 ( @@ -36,6 +37,8 @@ type diff struct { timestamp time.Time + unitFees commonfees.Dimensions + // Subnet ID --> supply of native asset of the subnet currentSupply map[ids.ID]uint64 @@ -90,20 +93,8 @@ 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) GetUnitFees() commonfees.Dimensions { + return d.unitFees } func (d *diff) GetTimestamp() time.Time { diff --git a/vms/platformvm/state/mock_state.go b/vms/platformvm/state/mock_state.go index 573127bdbe32..cfb9dd16944a 100644 --- a/vms/platformvm/state/mock_state.go +++ b/vms/platformvm/state/mock_state.go @@ -20,7 +20,6 @@ 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" @@ -183,21 +182,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)) -} - // GetCurrentDelegatorIterator mocks base method. func (m *MockChain) GetCurrentDelegatorIterator(arg0 ids.ID, arg1 ids.NodeID) (StakerIterator, error) { m.ctrl.T.Helper() @@ -393,21 +377,6 @@ func (mr *MockChainMockRecorder) GetUTXO(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUTXO", reflect.TypeOf((*MockChain)(nil).GetUTXO), arg0) } -// GetUnitFees mocks base method. -func (m *MockChain) GetUnitFees() (fees.Dimensions, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetUnitFees") - ret0, _ := ret[0].(fees.Dimensions) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetUnitFees indicates an expected call of GetUnitFees. -func (mr *MockChainMockRecorder) GetUnitFees() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUnitFees", reflect.TypeOf((*MockChain)(nil).GetUnitFees)) -} - // PutCurrentDelegator mocks base method. func (m *MockChain) PutCurrentDelegator(arg0 *Staker) { m.ctrl.T.Helper() @@ -675,21 +644,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)) -} - // GetCurrentDelegatorIterator mocks base method. func (m *MockDiff) GetCurrentDelegatorIterator(arg0 ids.ID, arg1 ids.NodeID) (StakerIterator, error) { m.ctrl.T.Helper() @@ -885,21 +839,6 @@ func (mr *MockDiffMockRecorder) GetUTXO(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUTXO", reflect.TypeOf((*MockDiff)(nil).GetUTXO), arg0) } -// GetUnitFees mocks base method. -func (m *MockDiff) GetUnitFees() (fees.Dimensions, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetUnitFees") - ret0, _ := ret[0].(fees.Dimensions) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetUnitFees indicates an expected call of GetUnitFees. -func (mr *MockDiffMockRecorder) GetUnitFees() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUnitFees", reflect.TypeOf((*MockDiff)(nil).GetUnitFees)) -} - // PutCurrentDelegator mocks base method. func (m *MockDiff) PutCurrentDelegator(arg0 *Staker) { m.ctrl.T.Helper() @@ -1277,21 +1216,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() @@ -1576,21 +1500,6 @@ func (mr *MockStateMockRecorder) GetUTXO(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUTXO", reflect.TypeOf((*MockState)(nil).GetUTXO), arg0) } -// GetUnitFees mocks base method. -func (m *MockState) GetUnitFees() (fees.Dimensions, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetUnitFees") - ret0, _ := ret[0].(fees.Dimensions) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetUnitFees indicates an expected call of GetUnitFees. -func (mr *MockStateMockRecorder) GetUnitFees() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUnitFees", reflect.TypeOf((*MockState)(nil).GetUnitFees)) -} - // GetUptime mocks base method. func (m *MockState) GetUptime(arg0 ids.NodeID, arg1 ids.ID) (time.Duration, time.Time, error) { m.ctrl.T.Helper() @@ -1669,20 +1578,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) -} - // SetCurrentSupply mocks base method. func (m *MockState) SetCurrentSupply(arg0 ids.ID, arg1 uint64) { m.ctrl.T.Helper() @@ -1757,20 +1652,6 @@ func (mr *MockStateMockRecorder) SetTimestamp(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetTimestamp", reflect.TypeOf((*MockState)(nil).SetTimestamp), arg0) } -// SetUnitFees mocks base method. -func (m *MockState) SetUnitFees(arg0 fees.Dimensions) 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 f2374098c68b..e71bc550eb62 100644 --- a/vms/platformvm/state/state.go +++ b/vms/platformvm/state/state.go @@ -44,10 +44,8 @@ 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" ) const ( @@ -102,10 +100,6 @@ 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) @@ -147,10 +141,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 - 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]. @@ -381,15 +371,11 @@ type state struct { // The persisted fields represent the current database value timestamp, persistedTimestamp time.Time currentSupply, persistedCurrentSupply uint64 + // [lastAccepted] is the most recently accepted block. 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 @@ -719,9 +705,6 @@ func newState( chainDBCache: chainDBCache, singletonDB: prefixdb.New(SingletonPrefix, baseDB), - - unitFees: fees.DefaultUnitFees, - blockUnitCaps: fees.DefaultBlockMaxConsumedUnits, }, nil } @@ -1096,24 +1079,6 @@ 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 3b2ecb1f71d9..7335e81a8084 100644 --- a/vms/platformvm/txs/builder/builder.go +++ b/vms/platformvm/txs/builder/builder.go @@ -310,26 +310,13 @@ 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 + feeCfg := config.EUpgradeDynamicFeesConfig feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, - FeeManager: commonfees.NewManager(unitFees), - ConsumedUnitsCap: unitCaps, + FeeManager: commonfees.NewManager(feeCfg.UnitFees), + ConsumedUnitsCap: feeCfg.BlockUnitsCap, Credentials: txs.EmptyCredentials(signers), } @@ -478,24 +465,11 @@ 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 - } - + feeCfg := config.EUpgradeDynamicFeesConfig feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, - FeeManager: commonfees.NewManager(unitFees), - ConsumedUnitsCap: unitCaps, + FeeManager: commonfees.NewManager(feeCfg.UnitFees), + ConsumedUnitsCap: feeCfg.BlockUnitsCap, Credentials: txs.EmptyCredentials(signers), } @@ -573,24 +547,11 @@ 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 - } - + feeCfg := config.EUpgradeDynamicFeesConfig feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, - FeeManager: commonfees.NewManager(unitFees), - ConsumedUnitsCap: unitCaps, + FeeManager: commonfees.NewManager(feeCfg.UnitFees), + ConsumedUnitsCap: feeCfg.BlockUnitsCap, Credentials: txs.EmptyCredentials(signers), } @@ -657,24 +618,11 @@ 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 - } - + feeCfg := config.EUpgradeDynamicFeesConfig feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, - FeeManager: commonfees.NewManager(unitFees), - ConsumedUnitsCap: unitCaps, + FeeManager: commonfees.NewManager(feeCfg.UnitFees), + ConsumedUnitsCap: feeCfg.BlockUnitsCap, Credentials: txs.EmptyCredentials(signers), } @@ -750,24 +698,11 @@ 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 - } - + feeCfg := config.EUpgradeDynamicFeesConfig feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, - FeeManager: commonfees.NewManager(unitFees), - ConsumedUnitsCap: unitCaps, + FeeManager: commonfees.NewManager(feeCfg.UnitFees), + ConsumedUnitsCap: feeCfg.BlockUnitsCap, Credentials: txs.EmptyCredentials(signers), } @@ -841,24 +776,11 @@ 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 - } - + feeCfg := config.EUpgradeDynamicFeesConfig feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, - FeeManager: commonfees.NewManager(unitFees), - ConsumedUnitsCap: unitCaps, + FeeManager: commonfees.NewManager(feeCfg.UnitFees), + ConsumedUnitsCap: feeCfg.BlockUnitsCap, Credentials: txs.EmptyCredentials(signers), } @@ -933,24 +855,11 @@ 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 - } - + feeCfg := config.EUpgradeDynamicFeesConfig feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, - FeeManager: commonfees.NewManager(unitFees), - ConsumedUnitsCap: unitCaps, + FeeManager: commonfees.NewManager(feeCfg.UnitFees), + ConsumedUnitsCap: feeCfg.BlockUnitsCap, Credentials: txs.EmptyCredentials(signers), } @@ -1015,24 +924,11 @@ 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 - } - + feeCfg := config.EUpgradeDynamicFeesConfig feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, - FeeManager: commonfees.NewManager(unitFees), - ConsumedUnitsCap: unitCaps, + FeeManager: commonfees.NewManager(feeCfg.UnitFees), + ConsumedUnitsCap: feeCfg.BlockUnitsCap, Credentials: txs.EmptyCredentials(signers), } @@ -1111,24 +1007,11 @@ 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 - } - + feeCfg := config.EUpgradeDynamicFeesConfig feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, - FeeManager: commonfees.NewManager(unitFees), - ConsumedUnitsCap: unitCaps, + FeeManager: commonfees.NewManager(feeCfg.UnitFees), + ConsumedUnitsCap: feeCfg.BlockUnitsCap, Credentials: txs.EmptyCredentials(signers), } @@ -1187,24 +1070,11 @@ 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 - } - + feeCfg := config.EUpgradeDynamicFeesConfig feeCalc := &fees.Calculator{ IsEForkActive: isEForkActive, - FeeManager: commonfees.NewManager(unitFees), - ConsumedUnitsCap: unitCaps, + FeeManager: commonfees.NewManager(feeCfg.UnitFees), + ConsumedUnitsCap: feeCfg.BlockUnitsCap, 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 fc266f1b040a..a00d8381d7db 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.Empty), + 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 b55b016f9e75..eabf9d3f9239 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.Empty), + UnitCaps: commonfees.Empty, 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.Empty), + UnitCaps: commonfees.Empty, 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.Empty), + UnitCaps: commonfees.Empty, 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.Empty), + UnitCaps: commonfees.Empty, 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.Empty), + 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 f02f4e9d3260..d084fe473506 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.Empty), + 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 7ff5db6e1353..a80d81053e3a 100644 --- a/vms/platformvm/txs/executor/helpers_test.go +++ b/vms/platformvm/txs/executor/helpers_test.go @@ -229,16 +229,11 @@ func addSubnet( stateDiff, err := state.NewDiff(lastAcceptedID, env) require.NoError(err) - unitFees, err := env.state.GetUnitFees() - require.NoError(err) - - unitCaps, err := env.state.GetBlockUnitCaps() - require.NoError(err) - + feeCfg := config.EUpgradeDynamicFeesConfig executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: fees.NewManager(unitFees), - UnitCaps: unitCaps, + BlkFeeManager: fees.NewManager(feeCfg.UnitFees), + UnitCaps: feeCfg.BlockUnitsCap, 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 bbfbdeb5a338..0aaab27c5b4b 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.Empty, 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.Empty, 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.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 009605fceac2..11d1e3bd8bc6 100644 --- a/vms/platformvm/txs/executor/staker_tx_verification_test.go +++ b/vms/platformvm/txs/executor/staker_tx_verification_test.go @@ -19,15 +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/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) { @@ -603,13 +601,13 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { var ( backend = tt.backendF(ctrl) - feeManager = commonfees.NewManager(fees.EmptyUnitFees) + feeManager = fees.NewManager(fees.Empty) 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 098ffeae7aca..f50b7f643c96 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" @@ -33,12 +34,9 @@ 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" - - commonfees "github.com/ava-labs/avalanchego/vms/components/fees" ) // This tests that the math performed during TransformSubnetTx execution can @@ -94,8 +92,8 @@ func TestStandardTxExecutorAddValidatorTxEmptyID(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty), + UnitCaps: fees.Empty, State: stateDiff, Tx: tx, } @@ -352,8 +350,8 @@ func TestStandardTxExecutorAddDelegator(t *testing.T) { executor := StandardTxExecutor{ Backend: &freshTH.backend, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty), + UnitCaps: fees.Empty, State: onAcceptState, Tx: tx, } @@ -392,8 +390,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty), + UnitCaps: fees.Empty, State: onAcceptState, Tx: tx, } @@ -422,8 +420,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty), + UnitCaps: fees.Empty, State: onAcceptState, Tx: tx, } @@ -466,8 +464,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty), + UnitCaps: fees.Empty, State: onAcceptState, Tx: tx, } @@ -511,8 +509,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty), + UnitCaps: fees.Empty, State: onAcceptState, Tx: tx, } @@ -539,8 +537,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty), + UnitCaps: fees.Empty, State: onAcceptState, Tx: tx, } @@ -566,8 +564,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { require.NoError(err) executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty), + UnitCaps: fees.Empty, State: onAcceptState, Tx: tx, } @@ -596,8 +594,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty), + UnitCaps: fees.Empty, State: onAcceptState, Tx: tx, } @@ -654,8 +652,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty), + UnitCaps: fees.Empty, State: onAcceptState, Tx: duplicateSubnetTx, } @@ -693,8 +691,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty), + UnitCaps: fees.Empty, State: onAcceptState, Tx: tx, } @@ -728,8 +726,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty), + UnitCaps: fees.Empty, State: onAcceptState, Tx: tx, } @@ -761,8 +759,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty), + UnitCaps: fees.Empty, State: onAcceptState, Tx: tx, } @@ -804,8 +802,8 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty), + UnitCaps: fees.Empty, State: onAcceptState, Tx: tx, } @@ -841,8 +839,8 @@ func TestBanffStandardTxExecutorAddValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty), + UnitCaps: fees.Empty, State: onAcceptState, Tx: tx, } @@ -869,8 +867,8 @@ func TestBanffStandardTxExecutorAddValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty), + UnitCaps: fees.Empty, State: onAcceptState, Tx: tx, } @@ -910,8 +908,8 @@ func TestBanffStandardTxExecutorAddValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty), + UnitCaps: fees.Empty, State: onAcceptState, Tx: tx, } @@ -948,8 +946,8 @@ func TestBanffStandardTxExecutorAddValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty), + UnitCaps: fees.Empty, State: onAcceptState, Tx: tx, } @@ -985,8 +983,8 @@ func TestBanffStandardTxExecutorAddValidator(t *testing.T) { executor := StandardTxExecutor{ Backend: &env.backend, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty), + UnitCaps: fees.Empty, State: onAcceptState, Tx: tx, } @@ -1764,8 +1762,8 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty), + UnitCaps: fees.Empty, Tx: env.tx, State: env.state, } @@ -1796,8 +1794,8 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty), + UnitCaps: fees.Empty, Tx: env.tx, State: env.state, } @@ -1829,8 +1827,8 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty), + UnitCaps: fees.Empty, Tx: env.tx, State: env.state, } @@ -1865,8 +1863,8 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty), + UnitCaps: fees.Empty, Tx: env.tx, State: env.state, } @@ -1899,8 +1897,8 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty), + UnitCaps: fees.Empty, Tx: env.tx, State: env.state, } @@ -1932,8 +1930,8 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty), + UnitCaps: fees.Empty, Tx: env.tx, State: env.state, } @@ -1967,8 +1965,8 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty), + UnitCaps: fees.Empty, Tx: env.tx, State: env.state, } @@ -2005,8 +2003,8 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty), + UnitCaps: fees.Empty, Tx: env.tx, State: env.state, } @@ -2167,8 +2165,8 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty), + UnitCaps: fees.Empty, Tx: env.tx, State: env.state, } @@ -2199,8 +2197,8 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty), + UnitCaps: fees.Empty, Tx: env.tx, State: env.state, } @@ -2233,8 +2231,8 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty), + UnitCaps: fees.Empty, Tx: env.tx, State: env.state, } @@ -2272,8 +2270,8 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty), + UnitCaps: fees.Empty, Tx: env.tx, State: env.state, } @@ -2316,8 +2314,8 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { FlowChecker: env.flowChecker, Ctx: &snow.Context{}, }, - BlkFeeManager: commonfees.NewManager(fees.EmptyUnitFees), - UnitCaps: fees.EmptyUnitCaps, + BlkFeeManager: fees.NewManager(fees.Empty), + UnitCaps: fees.Empty, Tx: env.tx, State: env.state, } diff --git a/vms/platformvm/txs/fees/calculator.go b/vms/platformvm/txs/fees/calculator.go index 2db218df6333..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,33 +19,12 @@ 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{ - 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 @@ -57,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 diff --git a/wallet/chain/p/wallet.go b/wallet/chain/p/wallet.go index a528d6ddad79..e25e3dada140 100644 --- a/wallet/chain/p/wallet.go +++ b/wallet/chain/p/wallet.go @@ -13,6 +13,7 @@ import ( "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/components/fees" "github.com/ava-labs/avalanchego/vms/platformvm" + "github.com/ava-labs/avalanchego/vms/platformvm/config" "github.com/ava-labs/avalanchego/vms/platformvm/signer" "github.com/ava-labs/avalanchego/vms/platformvm/status" "github.com/ava-labs/avalanchego/vms/platformvm/txs" @@ -258,6 +259,8 @@ func NewWallet( Backend: backend, builder: builder, dynamicBuilder: dynFeesBuilder, + unitFees: config.EUpgradeDynamicFeesConfig.UnitFees, + unitCaps: config.EUpgradeDynamicFeesConfig.BlockUnitsCap, signer: signer, client: client, } @@ -295,10 +298,6 @@ func (w *wallet) IssueBaseTx( 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...) @@ -325,10 +324,6 @@ func (w *wallet) IssueAddValidatorTx( 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...) @@ -353,10 +348,6 @@ func (w *wallet) IssueAddSubnetValidatorTx( 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...) @@ -382,10 +373,6 @@ func (w *wallet) IssueRemoveSubnetValidatorTx( 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...) @@ -411,10 +398,6 @@ func (w *wallet) IssueAddDelegatorTx( 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...) @@ -443,10 +426,6 @@ func (w *wallet) IssueCreateChainTx( 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...) @@ -471,10 +450,6 @@ func (w *wallet) IssueCreateSubnetTx( 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...) @@ -500,10 +475,6 @@ func (w *wallet) IssueImportTx( 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...) @@ -529,10 +500,6 @@ func (w *wallet) IssueExportTx( 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...) @@ -570,10 +537,6 @@ func (w *wallet) IssueTransformSubnetTx( err error ) if w.isEForkActive { - if err := w.refreshFeesData(options...); err != nil { - return nil, err - } - utx, err = w.dynamicBuilder.NewTransformSubnetTx( subnetID, assetID, @@ -637,10 +600,6 @@ func (w *wallet) IssueAddPermissionlessValidatorTx( err error ) if w.isEForkActive { - if err := w.refreshFeesData(options...); err != nil { - return nil, err - } - utx, err = w.dynamicBuilder.NewAddPermissionlessValidatorTx( vdr, signer, @@ -685,10 +644,6 @@ func (w *wallet) IssueAddPermissionlessDelegatorTx( err error ) if w.isEForkActive { - if err := w.refreshFeesData(options...); err != nil { - return nil, err - } - utx, err = w.dynamicBuilder.NewAddPermissionlessDelegatorTx( vdr, assetID, @@ -781,22 +736,3 @@ func (w *wallet) refreshFork(options ...common.Option) error { 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 -}