Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
95 commits
Select commit Hold shift + click to select a range
10d71e7
fee manager draft
abi87 Jan 8, 2024
f4da004
fee calculator draft
abi87 Jan 8, 2024
c705d55
some more fee calculator drafting
abi87 Jan 8, 2024
75b93b7
wired in fee calculator
abi87 Jan 8, 2024
b7a539c
fixed leftovers
abi87 Jan 8, 2024
195741f
nit
abi87 Jan 8, 2024
b86f784
fixed EFork fork time
abi87 Jan 8, 2024
033abd0
fixed DefaultUnitPrices
abi87 Jan 8, 2024
6e24cea
added UTs
abi87 Jan 8, 2024
b79b295
nit
abi87 Jan 8, 2024
5a56f0e
added UTXORead fee dimension
abi87 Jan 8, 2024
23749c0
added UTXOWrite fee dimension
abi87 Jan 8, 2024
421032c
minor renaming
abi87 Jan 8, 2024
82fb788
nit
abi87 Jan 9, 2024
7f2c799
wip: improved utxos complexity metering
abi87 Jan 9, 2024
3cf241a
wip: adding UTs
abi87 Jan 9, 2024
2ffcd08
some more UTs
abi87 Jan 9, 2024
cceccfd
UTs cleanup
abi87 Jan 9, 2024
8df89e5
added feeCalculator to avm
abi87 Jan 9, 2024
136c812
fixed avm fee manager
abi87 Jan 10, 2024
fbf219f
added avm UTs for fee calculator
abi87 Jan 10, 2024
6c3939c
nit
abi87 Jan 10, 2024
52ea70d
Merge branch 'dev' into p-chain_dynamic-fees
abi87 Jan 10, 2024
6154ee7
Merge branch 'dev' into p-chain_dynamic-fees
abi87 Jan 10, 2024
8b45443
Merge branch 'e-fork-scaffolding' into p-chain_dynamic-fees
abi87 Jan 10, 2024
d77ee0e
refactored fees
abi87 Jan 11, 2024
85ae069
repackaging
abi87 Jan 11, 2024
e2742b1
p-chain fee calculator repackaging
abi87 Jan 11, 2024
687dcf0
EXTENDED CODEC SIZE TO PROCESS PARTIALLY FILLED TXS
abi87 Jan 11, 2024
f40fa5e
nit
abi87 Jan 11, 2024
5e74e36
Merge branch 'e-fork-scaffolding' into p-chain_dynamic-fees
abi87 Jan 12, 2024
3cd30f8
Merge branch 'p-chain_dynamic-fees' of github.com:ava-labs/avalancheg…
abi87 Jan 12, 2024
2123e4d
wip: draft of tx financing with dynamic fees
abi87 Jan 12, 2024
cf2c55c
UT for codec size additivity
abi87 Jan 12, 2024
b14d514
exported inputs and outputs fee dimensions calculations
abi87 Jan 12, 2024
3d6f980
wip: keep on drafting tx financing with dynamic fees
abi87 Jan 12, 2024
f472b39
wip: keep on drafting tx financing with dynamic fees
abi87 Jan 12, 2024
0b94f8e
Merge branch 'e-fork-scaffolding' into p-chain_dynamic-fees
abi87 Jan 15, 2024
8b8c1fa
some more UTs
abi87 Jan 15, 2024
2ff80c8
added UTs for stake amounts
abi87 Jan 15, 2024
1c151c0
nit: simplified UTs
abi87 Jan 15, 2024
c1b8f7a
extended UTs checks
abi87 Jan 15, 2024
67fa06e
nit
abi87 Jan 15, 2024
ac1d066
added UTs with locked UTXOs
abi87 Jan 15, 2024
7f9bc12
nit
abi87 Jan 15, 2024
dc85668
nits
abi87 Jan 15, 2024
5a684d3
wip: extended financing of txs with dynamic fees
abi87 Jan 15, 2024
a05df57
wip: drafted ImportTx builder
abi87 Jan 16, 2024
a4bdc70
added UTs
abi87 Jan 16, 2024
a196754
repackaged avm fee calculator
abi87 Jan 16, 2024
85bff3d
removed some code duplication
abi87 Jan 17, 2024
498112d
Merge branch 'e-fork-scaffolding' into p-chain_dynamic-fees
abi87 Jan 17, 2024
dea17c0
Merge branch 'introducing-fees-calculators' into p-chain_dynamic-fees
abi87 Jan 17, 2024
8dd8879
Merge branch 'codec-upgrades-for-dynamic-fees' into p-chain_dynamic-fees
abi87 Jan 18, 2024
524631c
reduced diff
abi87 Jan 18, 2024
8819964
Merge branch 'codec-upgrades-for-dynamic-fees' into p-chain_dynamic-fees
abi87 Jan 18, 2024
b881e92
Merge branch 'codec-upgrades-for-dynamic-fees' into p-chain_dynamic-fees
abi87 Jan 22, 2024
057a4e4
exported p-chain unit fees via API
abi87 Jan 22, 2024
27eb36d
exported p-chain block units cap via API
abi87 Jan 22, 2024
e9c440b
wip: restructured fees calculator
abi87 Jan 22, 2024
b417546
wip: moving multidimensional fees configs to state
abi87 Jan 22, 2024
02c6084
cleanup
abi87 Jan 22, 2024
9ed258d
wip: multifee tx construction in wallet
abi87 Jan 22, 2024
9c123f0
wip: multifee tx construction in wallet
abi87 Jan 22, 2024
cbe4b04
added builder backend mock
abi87 Jan 23, 2024
456cde9
wip adding UTs for dynamic fees builder
abi87 Jan 23, 2024
e0490ae
Merge branch 'p-chain_dynamic-fees' of github.com:ava-labs/avalancheg…
abi87 Jan 23, 2024
4170845
wip: adding UTs for dynamic fees builder
abi87 Jan 23, 2024
5b32e72
wip: fixing UTs
abi87 Jan 24, 2024
03d1829
moved wallet mocks
abi87 Jan 24, 2024
5854363
expanded UTXOs list
abi87 Jan 24, 2024
d78aeb3
wip: adding txs to dynamic fees builder
abi87 Jan 24, 2024
f7a7912
wip: adding some more txs to dynamic fees builder
abi87 Jan 24, 2024
c5182e8
added ExportTx to dynamic fees builder
abi87 Jan 25, 2024
728d8db
added BaseTx to dynamic fees builder
abi87 Jan 25, 2024
c76445d
fixed Add/RemoveFees
abi87 Jan 25, 2024
226e8db
added ImportTx to dynamic fees builder
abi87 Jan 26, 2024
c5f083b
integrated dynamic fees builder into wallet
abi87 Jan 26, 2024
0d90f0f
enabled E fork in testnet + minor fixes
abi87 Jan 26, 2024
b4f44c1
Merge branch 'codec-upgrades-for-dynamic-fees' into p-chain_dynamic-fees
abi87 Jan 26, 2024
f2b6b9b
Merge branch 'codec-upgrades-for-dynamic-fees' into p-chain_dynamic-fees
abi87 Jan 26, 2024
77e5779
fixed merge
abi87 Jan 26, 2024
5b35ad3
leftover from previous merge
abi87 Jan 26, 2024
7a2a673
wip: fixing e2e tests
abi87 Jan 26, 2024
9b32bb0
moved X-chain changes to different branch
abi87 Jan 26, 2024
921a7dd
fixed p-chain workflow e2e test
abi87 Jan 26, 2024
36399f4
nit
abi87 Jan 26, 2024
cb46cdf
nit
abi87 Jan 26, 2024
5bad537
leftover
abi87 Jan 26, 2024
93fff34
improved utxos selection to finance txs in wallet
abi87 Jan 29, 2024
1f3cece
fix CI compilation
abi87 Jan 29, 2024
7415a58
consolidated code in wallet
abi87 Jan 29, 2024
8197e72
fixed e2e test to account for fees
abi87 Jan 29, 2024
9e83485
Merge branch 'codec-upgrades-for-dynamic-fees' into p-chain_dynamic-fees
abi87 Jan 29, 2024
d7f7a57
wip:cleanup
abi87 Feb 4, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions scripts/mocks.mockgen.txt
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +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/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
24 changes: 18 additions & 6 deletions tests/e2e/p/staking_rewards.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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])
}
Expand Down
38 changes: 24 additions & 14 deletions tests/e2e/p/workflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,12 @@ 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"

commonfees "github.com/ava-labs/avalanchego/vms/components/fees"
)

// PChainWorkflow is an integration test for normal P-Chain operations
Expand Down Expand Up @@ -49,25 +53,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.
Expand Down Expand Up @@ -126,8 +123,9 @@ var _ = e2e.DescribePChain("[Workflow]", func() {
OutputOwners: outputOwner,
}

pChainExportFee := uint64(0)
ginkgo.By("export avax from P to X chain", func() {
_, err := pWallet.IssueExportTx(
tx, err := pWallet.IssueExportTx(
xWallet.BlockchainID(),
[]*avax.TransferableOutput{
{
Expand All @@ -140,6 +138,18 @@ var _ = e2e.DescribePChain("[Workflow]", func() {
e2e.WithDefaultContext(),
)
require.NoError(err)

// retrieve fees paid for the tx
feeCfg := config.EUpgradeDynamicFeesConfig
feeCalc := fees.Calculator{
IsEForkActive: true,
FeeManager: commonfees.NewManager(feeCfg.UnitFees),
ConsumedUnitsCap: feeCfg.BlockUnitsCap,
Credentials: tx.Creds,
}

require.NoError(tx.Unsigned.Visit(&feeCalc))
pChainExportFee = feeCalc.Fee
})

// check balances post export
Expand All @@ -154,7 +164,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(
Expand All @@ -176,7 +186,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)
})
})
62 changes: 62 additions & 0 deletions vms/components/fees/dimensions.go
Original file line number Diff line number Diff line change
@@ -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
}
71 changes: 71 additions & 0 deletions vms/components/fees/helpers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// 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/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"
)

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
}

func GetCredentialsDimensions(c codec.Manager, v uint16, inputSigIndices []uint32) (Dimensions, error) {
var consumedUnits Dimensions

// 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, 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
}
92 changes: 92 additions & 0 deletions vms/components/fees/manager.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package fees

import (
"fmt"

safemath "github.com/ava-labs/avalanchego/utils/math"
)

type Manager struct {
// 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(unitFees Dimensions) *Manager {
return &Manager{
unitFees: unitFees,
}
}

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 := safemath.Mul64(m.unitFees[i], units[i])
if err != nil {
return 0, err
}
fee, err = safemath.Add64(contribution, fee)
if err != nil {
return 0, err
}
}
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++ {
consumed, err := safemath.Add64(m.cumulatedUnits[i], units[i])
if err != nil {
return true, i
}
if consumed > bounds[i] {
return true, i
}
}

// Commit to consumption
for i := Dimension(0); i < FeeDimensions; i++ {
consumed, err := safemath.Add64(m.cumulatedUnits[i], units[i])
if err != nil {
return true, i
}
m.cumulatedUnits[i] = consumed
}
return false, 0
}

// Sometimes, e.g. while building a tx, we'd like freedom to speculatively add units
// and to remove them later on. [RemoveUnits] grants this freedom
func (m *Manager) RemoveUnits(unitsToRm Dimensions) error {
var revertedUnits Dimensions
for i := Dimension(0); i < FeeDimensions; i++ {
prev, err := safemath.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
}
Loading