From 1adc32865ef59f9157e2578e2739e5671d878aee Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Wed, 10 Jan 2024 13:52:05 +0100 Subject: [PATCH 01/27] E fork scaffolding --- node/node.go | 3 + version/constants.go | 13 ++ vms/avm/block/executor/block_test.go | 140 +++++++++++++++++- vms/avm/block/executor/manager_test.go | 25 +++- vms/avm/config/config.go | 7 + vms/avm/environment_test.go | 3 + vms/avm/index_test.go | 17 ++- vms/avm/service_test.go | 36 ++++- .../txs/executor/syntactic_verifier_test.go | 3 + vms/avm/vm_regression_test.go | 7 +- vms/avm/vm_test.go | 24 ++- vms/platformvm/block/builder/helpers_test.go | 2 + vms/platformvm/block/executor/helpers_test.go | 2 + vms/platformvm/config/config.go | 7 + vms/platformvm/txs/executor/helpers_test.go | 1 + .../executor/staker_tx_verification_test.go | 14 ++ .../txs/executor/standard_tx_executor_test.go | 14 ++ vms/platformvm/validator_set_property_test.go | 1 + vms/platformvm/vm_regression_test.go | 1 + vms/platformvm/vm_test.go | 8 + 20 files changed, 305 insertions(+), 23 deletions(-) diff --git a/node/node.go b/node/node.go index 45e2f6a506e..0c61b0ba848 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 } @@ -1120,6 +1121,7 @@ func (n *Node) initVMs() error { BanffTime: version.GetBanffTime(n.Config.NetworkID), CortinaTime: version.GetCortinaTime(n.Config.NetworkID), DurangoTime: durangoTime, + EForkTime: eForkTime, UseCurrentHeight: n.Config.UseCurrentHeight, }, }), @@ -1128,6 +1130,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/version/constants.go b/version/constants.go index 053a57a4585..4a4187bd277 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, diff --git a/vms/avm/block/executor/block_test.go b/vms/avm/block/executor/block_test.go index 0b6738822c6..c44a6938956 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_test.go b/vms/avm/block/executor/manager_test.go index 012428d582e..89b547eed96 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, @@ -142,6 +149,10 @@ func TestManagerVerifyTx(t *testing.T) { return &manager{ backend: &executor.Backend{ Bootstrapped: true, + Config: &config.Config{ + DurangoTime: time.Time{}, + EForkTime: mockable.MaxTime, + }, }, } }, @@ -170,6 +181,10 @@ func TestManagerVerifyTx(t *testing.T) { return &manager{ backend: &executor.Backend{ Bootstrapped: true, + Config: &config.Config{ + DurangoTime: time.Time{}, + EForkTime: mockable.MaxTime, + }, }, state: state, lastAccepted: lastAcceptedID, @@ -202,6 +217,10 @@ func TestManagerVerifyTx(t *testing.T) { return &manager{ backend: &executor.Backend{ Bootstrapped: true, + Config: &config.Config{ + DurangoTime: time.Time{}, + EForkTime: mockable.MaxTime, + }, }, state: state, lastAccepted: lastAcceptedID, @@ -234,6 +253,10 @@ func TestManagerVerifyTx(t *testing.T) { 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 df6e4f7de2a..b4da6e3781e 100644 --- a/vms/avm/config/config.go +++ b/vms/avm/config/config.go @@ -15,4 +15,11 @@ type Config struct { // 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) } diff --git a/vms/avm/environment_test.go b/vms/avm/environment_test.go index 236c2087579..00a1b2725e4 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 03a2fd863c6..642410951c9 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 c659b8e9de9..62f81d08f48 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/syntactic_verifier_test.go b/vms/avm/txs/executor/syntactic_verifier_test.go index 108ac9e94a6..3b5c05d42d0 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_regression_test.go b/vms/avm/vm_regression_test.go index c6ac40df845..1e4720f80fe 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 d8aeaf3b874..f7c7d11af0e 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())) diff --git a/vms/platformvm/block/builder/helpers_test.go b/vms/platformvm/block/builder/helpers_test.go index fa7339be6fd..7d84060b134 100644 --- a/vms/platformvm/block/builder/helpers_test.go +++ b/vms/platformvm/block/builder/helpers_test.go @@ -298,6 +298,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 5e7b5a3fce1..848cbdb5c62 100644 --- a/vms/platformvm/block/executor/helpers_test.go +++ b/vms/platformvm/block/executor/helpers_test.go @@ -316,6 +316,8 @@ func defaultConfig() *config.Config { ApricotPhase3Time: defaultValidateEndTime, ApricotPhase5Time: defaultValidateEndTime, BanffTime: mockable.MaxTime, + DurangoTime: mockable.MaxTime, + EForkTime: mockable.MaxTime, } } diff --git a/vms/platformvm/config/config.go b/vms/platformvm/config/config.go index 50628c422af..292981ddc02 100644 --- a/vms/platformvm/config/config.go +++ b/vms/platformvm/config/config.go @@ -107,6 +107,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 +140,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 diff --git a/vms/platformvm/txs/executor/helpers_test.go b/vms/platformvm/txs/executor/helpers_test.go index 1ea645efcfb..7f90b6ab785 100644 --- a/vms/platformvm/txs/executor/helpers_test.go +++ b/vms/platformvm/txs/executor/helpers_test.go @@ -284,6 +284,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/staker_tx_verification_test.go b/vms/platformvm/txs/executor/staker_tx_verification_test.go index b59daf0da2b..204ed382a2a 100644 --- a/vms/platformvm/txs/executor/staker_tx_verification_test.go +++ b/vms/platformvm/txs/executor/staker_tx_verification_test.go @@ -113,6 +113,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { Ctx: ctx, Config: &config.Config{ DurangoTime: activeForkTime, // activate latest fork + EForkTime: mockable.MaxTime, }, } }, @@ -134,6 +135,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 +161,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { Config: &config.Config{ CortinaTime: activeForkTime, DurangoTime: mockable.MaxTime, + EForkTime: mockable.MaxTime, }, Bootstrapped: bootstrapped, } @@ -185,6 +188,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { Ctx: ctx, Config: &config.Config{ DurangoTime: activeForkTime, // activate latest fork + EForkTime: mockable.MaxTime, }, Bootstrapped: bootstrapped, } @@ -214,6 +218,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { Ctx: ctx, Config: &config.Config{ DurangoTime: activeForkTime, // activate latest fork + EForkTime: mockable.MaxTime, }, Bootstrapped: bootstrapped, } @@ -243,6 +248,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { Ctx: ctx, Config: &config.Config{ DurangoTime: activeForkTime, // activate latest fork + EForkTime: mockable.MaxTime, }, Bootstrapped: bootstrapped, } @@ -273,6 +279,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { Ctx: ctx, Config: &config.Config{ DurangoTime: activeForkTime, // activate latest fork + EForkTime: mockable.MaxTime, }, Bootstrapped: bootstrapped, } @@ -306,6 +313,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { Ctx: ctx, Config: &config.Config{ DurangoTime: activeForkTime, // activate latest fork + EForkTime: mockable.MaxTime, }, Bootstrapped: bootstrapped, } @@ -339,6 +347,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { Ctx: ctx, Config: &config.Config{ DurangoTime: activeForkTime, // activate latest fork + EForkTime: mockable.MaxTime, }, Bootstrapped: bootstrapped, } @@ -374,6 +383,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { Ctx: ctx, Config: &config.Config{ DurangoTime: activeForkTime, // activate latest fork + EForkTime: mockable.MaxTime, }, Bootstrapped: bootstrapped, } @@ -403,6 +413,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { Ctx: ctx, Config: &config.Config{ DurangoTime: activeForkTime, // activate latest fork + EForkTime: mockable.MaxTime, }, Bootstrapped: bootstrapped, } @@ -449,6 +460,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 +507,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { Config: &config.Config{ CortinaTime: activeForkTime, DurangoTime: mockable.MaxTime, + EForkTime: mockable.MaxTime, AddSubnetValidatorFee: 1, }, Ctx: ctx, @@ -547,6 +560,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { Config: &config.Config{ AddSubnetValidatorFee: 1, DurangoTime: activeForkTime, // activate latest fork, + EForkTime: mockable.MaxTime, }, Ctx: ctx, Bootstrapped: bootstrapped, diff --git a/vms/platformvm/txs/executor/standard_tx_executor_test.go b/vms/platformvm/txs/executor/standard_tx_executor_test.go index a86c579fee7..de0e3eebecc 100644 --- a/vms/platformvm/txs/executor/standard_tx_executor_test.go +++ b/vms/platformvm/txs/executor/standard_tx_executor_test.go @@ -21,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/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" @@ -1150,6 +1151,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { BanffTime: env.latestForkTime, CortinaTime: env.latestForkTime, DurangoTime: env.latestForkTime, + EForkTime: mockable.MaxTime, }, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, @@ -1177,6 +1179,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { BanffTime: env.latestForkTime, CortinaTime: env.latestForkTime, DurangoTime: env.latestForkTime, + EForkTime: mockable.MaxTime, }, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, @@ -1204,6 +1207,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { BanffTime: env.latestForkTime, CortinaTime: env.latestForkTime, DurangoTime: env.latestForkTime, + EForkTime: mockable.MaxTime, }, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, @@ -1234,6 +1238,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { BanffTime: env.latestForkTime, CortinaTime: env.latestForkTime, DurangoTime: env.latestForkTime, + EForkTime: mockable.MaxTime, }, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, @@ -1262,6 +1267,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { BanffTime: env.latestForkTime, CortinaTime: env.latestForkTime, DurangoTime: env.latestForkTime, + EForkTime: mockable.MaxTime, }, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, @@ -1289,6 +1295,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { BanffTime: env.latestForkTime, CortinaTime: env.latestForkTime, DurangoTime: env.latestForkTime, + EForkTime: mockable.MaxTime, }, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, @@ -1318,6 +1325,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { BanffTime: env.latestForkTime, CortinaTime: env.latestForkTime, DurangoTime: env.latestForkTime, + EForkTime: mockable.MaxTime, }, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, @@ -1350,6 +1358,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { BanffTime: env.latestForkTime, CortinaTime: env.latestForkTime, DurangoTime: env.latestForkTime, + EForkTime: mockable.MaxTime, }, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, @@ -1507,6 +1516,7 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { BanffTime: env.latestForkTime, CortinaTime: env.latestForkTime, DurangoTime: env.latestForkTime, + EForkTime: mockable.MaxTime, }, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, @@ -1533,6 +1543,7 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { BanffTime: env.latestForkTime, CortinaTime: env.latestForkTime, DurangoTime: env.latestForkTime, + EForkTime: mockable.MaxTime, }, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, @@ -1561,6 +1572,7 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { CortinaTime: env.latestForkTime, DurangoTime: env.latestForkTime, MaxStakeDuration: math.MaxInt64, + EForkTime: mockable.MaxTime, }, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, @@ -1593,6 +1605,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]{}, @@ -1631,6 +1644,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]{}, diff --git a/vms/platformvm/validator_set_property_test.go b/vms/platformvm/validator_set_property_test.go index 5ca5bfd6c24..c2894e594f7 100644 --- a/vms/platformvm/validator_set_property_test.go +++ b/vms/platformvm/validator_set_property_test.go @@ -730,6 +730,7 @@ func buildVM(t *testing.T) (*VM, ids.ID, error) { ApricotPhase5Time: forkTime, BanffTime: forkTime, CortinaTime: 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 36186ec32ae..a82cf6f76c6 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 23e88a64636..6c8733550d0 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 e00d7c9953990f7758e3fb8aa201252e641252d4 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 29 Jan 2024 13:36:20 +0100 Subject: [PATCH 02/27] drop temporary fork time --- version/constants.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/version/constants.go b/version/constants.go index a535f2a0759..f90e1188ab3 100644 --- a/version/constants.go +++ b/version/constants.go @@ -135,7 +135,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() { @@ -263,7 +262,7 @@ func GetEForkTime(networkID uint32) time.Time { if upgradeTime, exists := EForkTimes[networkID]; exists { return upgradeTime } - return TempForkTime + return DefaultUpgradeTime } func GetCompatibility(networkID uint32) Compatibility { From f832034e7aadba290a87c2a88d6f40fa027919cb Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 1 Feb 2024 22:38:42 +0100 Subject: [PATCH 03/27] nits --- node/node.go | 6 +- version/constants.go | 6 +- vms/avm/block/executor/block_test.go | 96 +++++++++---------- vms/avm/block/executor/manager_test.go | 20 ++-- vms/avm/config/config.go | 6 +- vms/avm/environment_test.go | 2 +- vms/avm/index_test.go | 12 +-- vms/avm/service_test.go | 28 +++--- .../txs/executor/syntactic_verifier_test.go | 2 +- vms/avm/vm_regression_test.go | 4 +- vms/avm/vm_test.go | 16 ++-- vms/platformvm/block/builder/helpers_test.go | 2 +- vms/platformvm/block/executor/helpers_test.go | 2 +- vms/platformvm/config/config.go | 4 +- vms/platformvm/txs/executor/helpers_test.go | 2 +- .../executor/staker_tx_verification_test.go | 52 +++++----- .../txs/executor/standard_tx_executor_test.go | 86 ++++++++--------- vms/platformvm/validator_set_property_test.go | 2 +- vms/platformvm/vm_regression_test.go | 2 +- vms/platformvm/vm_test.go | 16 ++-- 20 files changed, 183 insertions(+), 183 deletions(-) diff --git a/node/node.go b/node/node.go index a9cfc4e951e..88c14ba3a08 100644 --- a/node/node.go +++ b/node/node.go @@ -1182,7 +1182,7 @@ func (n *Node) initVMs() error { } durangoTime := version.GetDurangoTime(n.Config.NetworkID) - eForkTime := version.GetEForkTime(n.Config.NetworkID) + eUpgradeTime := version.GetEUpgradeTime(n.Config.NetworkID) if err := txs.InitCodec(durangoTime); err != nil { return err } @@ -1225,7 +1225,7 @@ func (n *Node) initVMs() error { BanffTime: version.GetBanffTime(n.Config.NetworkID), CortinaTime: version.GetCortinaTime(n.Config.NetworkID), DurangoTime: durangoTime, - EForkTime: eForkTime, + EUpgradeTime: eUpgradeTime, UseCurrentHeight: n.Config.UseCurrentHeight, }, }), @@ -1234,7 +1234,7 @@ func (n *Node) initVMs() error { TxFee: n.Config.TxFee, CreateAssetTxFee: n.Config.CreateAssetTxFee, DurangoTime: durangoTime, - EForkTime: eForkTime, + EUpgradeTime: eUpgradeTime, }, }), n.VMManager.RegisterFactory(context.TODO(), constants.EVMID, &coreth.Factory{}), diff --git a/version/constants.go b/version/constants.go index 494448d0830..153c87a3381 100644 --- a/version/constants.go +++ b/version/constants.go @@ -142,7 +142,7 @@ var ( constants.FujiID: time.Date(10000, time.December, 1, 0, 0, 0, 0, time.UTC), } - EForkTimes = map[uint32]time.Time{ + EUpgradeTimes = 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), } @@ -246,8 +246,8 @@ func GetDurangoTime(networkID uint32) time.Time { return DefaultUpgradeTime } -func GetEForkTime(networkID uint32) time.Time { - if upgradeTime, exists := EForkTimes[networkID]; exists { +func GetEUpgradeTime(networkID uint32) time.Time { + if upgradeTime, exists := EUpgradeTimes[networkID]; exists { return upgradeTime } return DefaultUpgradeTime diff --git a/vms/avm/block/executor/block_test.go b/vms/avm/block/executor/block_test.go index c44a6938956..00d7c89264f 100644 --- a/vms/avm/block/executor/block_test.go +++ b/vms/avm/block/executor/block_test.go @@ -49,8 +49,8 @@ func TestBlockVerify(t *testing.T) { manager: &manager{ backend: &executor.Backend{ Config: &config.Config{ - DurangoTime: time.Time{}, - EForkTime: mockable.MaxTime, + DurangoTime: time.Time{}, + EUpgradeTime: mockable.MaxTime, }, }, blkIDToState: map[ids.ID]*blockState{}, @@ -74,8 +74,8 @@ func TestBlockVerify(t *testing.T) { manager: &manager{ backend: &executor.Backend{ Config: &config.Config{ - DurangoTime: time.Time{}, - EForkTime: mockable.MaxTime, + DurangoTime: time.Time{}, + EUpgradeTime: mockable.MaxTime, }, }, }, @@ -99,8 +99,8 @@ func TestBlockVerify(t *testing.T) { manager: &manager{ backend: &executor.Backend{ Config: &config.Config{ - DurangoTime: time.Time{}, - EForkTime: mockable.MaxTime, + DurangoTime: time.Time{}, + EUpgradeTime: mockable.MaxTime, }, }, clk: clk, @@ -122,8 +122,8 @@ func TestBlockVerify(t *testing.T) { manager: &manager{ backend: &executor.Backend{ Config: &config.Config{ - DurangoTime: time.Time{}, - EForkTime: mockable.MaxTime, + DurangoTime: time.Time{}, + EUpgradeTime: mockable.MaxTime, }, }, blkIDToState: map[ids.ID]*blockState{}, @@ -154,8 +154,8 @@ func TestBlockVerify(t *testing.T) { manager: &manager{ backend: &executor.Backend{ Config: &config.Config{ - DurangoTime: time.Time{}, - EForkTime: mockable.MaxTime, + DurangoTime: time.Time{}, + EUpgradeTime: mockable.MaxTime, }, }, mempool: mempool, @@ -192,8 +192,8 @@ func TestBlockVerify(t *testing.T) { manager: &manager{ backend: &executor.Backend{ Config: &config.Config{ - DurangoTime: time.Time{}, - EForkTime: mockable.MaxTime, + DurangoTime: time.Time{}, + EUpgradeTime: mockable.MaxTime, }, }, state: mockState, @@ -234,8 +234,8 @@ func TestBlockVerify(t *testing.T) { manager: &manager{ backend: &executor.Backend{ Config: &config.Config{ - DurangoTime: time.Time{}, - EForkTime: mockable.MaxTime, + DurangoTime: time.Time{}, + EUpgradeTime: mockable.MaxTime, }, }, state: mockState, @@ -279,8 +279,8 @@ func TestBlockVerify(t *testing.T) { manager: &manager{ backend: &executor.Backend{ Config: &config.Config{ - DurangoTime: time.Time{}, - EForkTime: mockable.MaxTime, + DurangoTime: time.Time{}, + EUpgradeTime: mockable.MaxTime, }, }, blkIDToState: map[ids.ID]*blockState{ @@ -332,8 +332,8 @@ func TestBlockVerify(t *testing.T) { manager: &manager{ backend: &executor.Backend{ Config: &config.Config{ - DurangoTime: time.Time{}, - EForkTime: mockable.MaxTime, + DurangoTime: time.Time{}, + EUpgradeTime: mockable.MaxTime, }, }, mempool: mempool, @@ -390,8 +390,8 @@ func TestBlockVerify(t *testing.T) { metrics: metrics.NewMockMetrics(ctrl), backend: &executor.Backend{ Config: &config.Config{ - DurangoTime: time.Time{}, - EForkTime: mockable.MaxTime, + DurangoTime: time.Time{}, + EUpgradeTime: mockable.MaxTime, }, }, blkIDToState: map[ids.ID]*blockState{ @@ -473,8 +473,8 @@ func TestBlockVerify(t *testing.T) { metrics: metrics.NewMockMetrics(ctrl), backend: &executor.Backend{ Config: &config.Config{ - DurangoTime: time.Time{}, - EForkTime: mockable.MaxTime, + DurangoTime: time.Time{}, + EUpgradeTime: mockable.MaxTime, }, }, blkIDToState: map[ids.ID]*blockState{ @@ -536,8 +536,8 @@ func TestBlockVerify(t *testing.T) { manager: &manager{ backend: &executor.Backend{ Config: &config.Config{ - DurangoTime: time.Time{}, - EForkTime: mockable.MaxTime, + DurangoTime: time.Time{}, + EUpgradeTime: mockable.MaxTime, }, }, blkIDToState: map[ids.ID]*blockState{ @@ -593,8 +593,8 @@ func TestBlockVerify(t *testing.T) { metrics: metrics.NewMockMetrics(ctrl), backend: &executor.Backend{ Config: &config.Config{ - DurangoTime: time.Time{}, - EForkTime: mockable.MaxTime, + DurangoTime: time.Time{}, + EUpgradeTime: mockable.MaxTime, }, }, blkIDToState: map[ids.ID]*blockState{ @@ -675,8 +675,8 @@ func TestBlockAccept(t *testing.T) { Log: logging.NoLog{}, }, Config: &config.Config{ - DurangoTime: time.Time{}, - EForkTime: mockable.MaxTime, + DurangoTime: time.Time{}, + EUpgradeTime: mockable.MaxTime, }, }, blkIDToState: map[ids.ID]*blockState{}, @@ -713,8 +713,8 @@ func TestBlockAccept(t *testing.T) { Log: logging.NoLog{}, }, Config: &config.Config{ - DurangoTime: time.Time{}, - EForkTime: mockable.MaxTime, + DurangoTime: time.Time{}, + EUpgradeTime: mockable.MaxTime, }, }, blkIDToState: map[ids.ID]*blockState{ @@ -761,8 +761,8 @@ func TestBlockAccept(t *testing.T) { Log: logging.NoLog{}, }, Config: &config.Config{ - DurangoTime: time.Time{}, - EForkTime: mockable.MaxTime, + DurangoTime: time.Time{}, + EUpgradeTime: mockable.MaxTime, }, }, blkIDToState: map[ids.ID]*blockState{ @@ -813,8 +813,8 @@ func TestBlockAccept(t *testing.T) { Log: logging.NoLog{}, }, Config: &config.Config{ - DurangoTime: time.Time{}, - EForkTime: mockable.MaxTime, + DurangoTime: time.Time{}, + EUpgradeTime: mockable.MaxTime, }, }, blkIDToState: map[ids.ID]*blockState{ @@ -868,8 +868,8 @@ func TestBlockAccept(t *testing.T) { Log: logging.NoLog{}, }, Config: &config.Config{ - DurangoTime: time.Time{}, - EForkTime: mockable.MaxTime, + DurangoTime: time.Time{}, + EUpgradeTime: mockable.MaxTime, }, }, blkIDToState: map[ids.ID]*blockState{ @@ -969,8 +969,8 @@ func TestBlockReject(t *testing.T) { backend: &executor.Backend{ Bootstrapped: true, Config: &config.Config{ - DurangoTime: time.Time{}, - EForkTime: mockable.MaxTime, + DurangoTime: time.Time{}, + EUpgradeTime: mockable.MaxTime, }, Ctx: &snow.Context{ Log: logging.NoLog{}, @@ -1034,8 +1034,8 @@ func TestBlockReject(t *testing.T) { Log: logging.NoLog{}, }, Config: &config.Config{ - DurangoTime: time.Time{}, - EForkTime: mockable.MaxTime, + DurangoTime: time.Time{}, + EUpgradeTime: mockable.MaxTime, }, }, state: mockState, @@ -1088,8 +1088,8 @@ func TestBlockStatus(t *testing.T) { manager: &manager{ backend: &executor.Backend{ Config: &config.Config{ - DurangoTime: time.Time{}, - EForkTime: mockable.MaxTime, + DurangoTime: time.Time{}, + EUpgradeTime: mockable.MaxTime, }, }, lastAccepted: blockID, @@ -1109,8 +1109,8 @@ func TestBlockStatus(t *testing.T) { manager: &manager{ backend: &executor.Backend{ Config: &config.Config{ - DurangoTime: time.Time{}, - EForkTime: mockable.MaxTime, + DurangoTime: time.Time{}, + EUpgradeTime: mockable.MaxTime, }, }, blkIDToState: map[ids.ID]*blockState{ @@ -1136,8 +1136,8 @@ func TestBlockStatus(t *testing.T) { manager: &manager{ backend: &executor.Backend{ Config: &config.Config{ - DurangoTime: time.Time{}, - EForkTime: mockable.MaxTime, + DurangoTime: time.Time{}, + EUpgradeTime: mockable.MaxTime, }, }, blkIDToState: map[ids.ID]*blockState{}, @@ -1162,8 +1162,8 @@ func TestBlockStatus(t *testing.T) { manager: &manager{ backend: &executor.Backend{ Config: &config.Config{ - DurangoTime: time.Time{}, - EForkTime: mockable.MaxTime, + DurangoTime: time.Time{}, + EUpgradeTime: mockable.MaxTime, }, }, blkIDToState: map[ids.ID]*blockState{}, diff --git a/vms/avm/block/executor/manager_test.go b/vms/avm/block/executor/manager_test.go index 89b547eed96..f0200f398a6 100644 --- a/vms/avm/block/executor/manager_test.go +++ b/vms/avm/block/executor/manager_test.go @@ -128,8 +128,8 @@ func TestManagerVerifyTx(t *testing.T) { return &manager{ backend: &executor.Backend{ Config: &config.Config{ - DurangoTime: time.Time{}, - EForkTime: mockable.MaxTime, + DurangoTime: time.Time{}, + EUpgradeTime: mockable.MaxTime, }, }, } @@ -150,8 +150,8 @@ func TestManagerVerifyTx(t *testing.T) { backend: &executor.Backend{ Bootstrapped: true, Config: &config.Config{ - DurangoTime: time.Time{}, - EForkTime: mockable.MaxTime, + DurangoTime: time.Time{}, + EUpgradeTime: mockable.MaxTime, }, }, } @@ -182,8 +182,8 @@ func TestManagerVerifyTx(t *testing.T) { backend: &executor.Backend{ Bootstrapped: true, Config: &config.Config{ - DurangoTime: time.Time{}, - EForkTime: mockable.MaxTime, + DurangoTime: time.Time{}, + EUpgradeTime: mockable.MaxTime, }, }, state: state, @@ -218,8 +218,8 @@ func TestManagerVerifyTx(t *testing.T) { backend: &executor.Backend{ Bootstrapped: true, Config: &config.Config{ - DurangoTime: time.Time{}, - EForkTime: mockable.MaxTime, + DurangoTime: time.Time{}, + EUpgradeTime: mockable.MaxTime, }, }, state: state, @@ -254,8 +254,8 @@ func TestManagerVerifyTx(t *testing.T) { backend: &executor.Backend{ Bootstrapped: true, Config: &config.Config{ - DurangoTime: time.Time{}, - EForkTime: mockable.MaxTime, + DurangoTime: time.Time{}, + EUpgradeTime: mockable.MaxTime, }, }, state: state, diff --git a/vms/avm/config/config.go b/vms/avm/config/config.go index b4da6e3781e..42e37b678a0 100644 --- a/vms/avm/config/config.go +++ b/vms/avm/config/config.go @@ -17,9 +17,9 @@ type Config struct { DurangoTime time.Time // Time of the E network upgrade - EForkTime time.Time + EUpgradeTime time.Time } -func (c *Config) IsEForkActivated(timestamp time.Time) bool { - return !timestamp.Before(c.EForkTime) +func (c *Config) IsEUpgradeActivated(timestamp time.Time) bool { + return !timestamp.Before(c.EUpgradeTime) } diff --git a/vms/avm/environment_test.go b/vms/avm/environment_test.go index 00a1b2725e4..5675964d1b7 100644 --- a/vms/avm/environment_test.go +++ b/vms/avm/environment_test.go @@ -151,7 +151,7 @@ func setup(tb testing.TB, c *envConfig) *environment { TxFee: testTxFee, CreateAssetTxFee: testTxFee, DurangoTime: time.Time{}, - EForkTime: mockable.MaxTime, + EUpgradeTime: mockable.MaxTime, } if c.vmStaticConfig != nil { vmStaticConfig = *c.vmStaticConfig diff --git a/vms/avm/index_test.go b/vms/avm/index_test.go index 642410951c9..f164481590e 100644 --- a/vms/avm/index_test.go +++ b/vms/avm/index_test.go @@ -34,8 +34,8 @@ func TestIndexTransaction_Ordered(t *testing.T) { env := setup(t, &envConfig{ vmStaticConfig: &config.Config{ - DurangoTime: time.Time{}, - EForkTime: mockable.MaxTime, + DurangoTime: time.Time{}, + EUpgradeTime: mockable.MaxTime, }, }) defer func() { @@ -81,8 +81,8 @@ func TestIndexTransaction_MultipleTransactions(t *testing.T) { env := setup(t, &envConfig{ vmStaticConfig: &config.Config{ - DurangoTime: time.Time{}, - EForkTime: mockable.MaxTime, + DurangoTime: time.Time{}, + EUpgradeTime: mockable.MaxTime, }, }) defer func() { @@ -132,8 +132,8 @@ func TestIndexTransaction_MultipleAddresses(t *testing.T) { env := setup(t, &envConfig{ vmStaticConfig: &config.Config{ - DurangoTime: time.Time{}, - EForkTime: mockable.MaxTime, + DurangoTime: time.Time{}, + EUpgradeTime: mockable.MaxTime, }, }) defer func() { diff --git a/vms/avm/service_test.go b/vms/avm/service_test.go index 62f81d08f48..8a080c6137b 100644 --- a/vms/avm/service_test.go +++ b/vms/avm/service_test.go @@ -705,8 +705,8 @@ func TestServiceGetTxJSON_CreateAssetTx(t *testing.T) { env := setup(t, &envConfig{ vmStaticConfig: &config.Config{ - DurangoTime: time.Time{}, - EForkTime: mockable.MaxTime, + DurangoTime: time.Time{}, + EUpgradeTime: mockable.MaxTime, }, additionalFxs: []*common.Fx{{ ID: propertyfx.ID, @@ -824,8 +824,8 @@ func TestServiceGetTxJSON_OperationTxWithNftxMintOp(t *testing.T) { env := setup(t, &envConfig{ vmStaticConfig: &config.Config{ - DurangoTime: time.Time{}, - EForkTime: mockable.MaxTime, + DurangoTime: time.Time{}, + EUpgradeTime: mockable.MaxTime, }, additionalFxs: []*common.Fx{{ ID: propertyfx.ID, @@ -926,8 +926,8 @@ func TestServiceGetTxJSON_OperationTxWithMultipleNftxMintOp(t *testing.T) { env := setup(t, &envConfig{ vmStaticConfig: &config.Config{ - DurangoTime: time.Time{}, - EForkTime: mockable.MaxTime, + DurangoTime: time.Time{}, + EUpgradeTime: mockable.MaxTime, }, additionalFxs: []*common.Fx{{ ID: propertyfx.ID, @@ -1067,8 +1067,8 @@ func TestServiceGetTxJSON_OperationTxWithSecpMintOp(t *testing.T) { env := setup(t, &envConfig{ vmStaticConfig: &config.Config{ - DurangoTime: time.Time{}, - EForkTime: mockable.MaxTime, + DurangoTime: time.Time{}, + EUpgradeTime: mockable.MaxTime, }, additionalFxs: []*common.Fx{{ ID: propertyfx.ID, @@ -1173,8 +1173,8 @@ func TestServiceGetTxJSON_OperationTxWithMultipleSecpMintOp(t *testing.T) { env := setup(t, &envConfig{ vmStaticConfig: &config.Config{ - DurangoTime: time.Time{}, - EForkTime: mockable.MaxTime, + DurangoTime: time.Time{}, + EUpgradeTime: mockable.MaxTime, }, additionalFxs: []*common.Fx{{ ID: propertyfx.ID, @@ -1322,8 +1322,8 @@ func TestServiceGetTxJSON_OperationTxWithPropertyFxMintOp(t *testing.T) { env := setup(t, &envConfig{ vmStaticConfig: &config.Config{ - DurangoTime: time.Time{}, - EForkTime: mockable.MaxTime, + DurangoTime: time.Time{}, + EUpgradeTime: mockable.MaxTime, }, additionalFxs: []*common.Fx{{ ID: propertyfx.ID, @@ -1425,8 +1425,8 @@ func TestServiceGetTxJSON_OperationTxWithPropertyFxMintOpMultiple(t *testing.T) env := setup(t, &envConfig{ vmStaticConfig: &config.Config{ - DurangoTime: time.Time{}, - EForkTime: mockable.MaxTime, + DurangoTime: time.Time{}, + EUpgradeTime: mockable.MaxTime, }, additionalFxs: []*common.Fx{{ ID: propertyfx.ID, diff --git a/vms/avm/txs/executor/syntactic_verifier_test.go b/vms/avm/txs/executor/syntactic_verifier_test.go index 3b5c05d42d0..cc160ed7982 100644 --- a/vms/avm/txs/executor/syntactic_verifier_test.go +++ b/vms/avm/txs/executor/syntactic_verifier_test.go @@ -32,7 +32,7 @@ var ( TxFee: 2, CreateAssetTxFee: 3, DurangoTime: time.Time{}, - EForkTime: mockable.MaxTime, + EUpgradeTime: mockable.MaxTime, } ) diff --git a/vms/avm/vm_regression_test.go b/vms/avm/vm_regression_test.go index 1e4720f80fe..2412c4e9a70 100644 --- a/vms/avm/vm_regression_test.go +++ b/vms/avm/vm_regression_test.go @@ -27,8 +27,8 @@ func TestVerifyFxUsage(t *testing.T) { env := setup(t, &envConfig{ vmStaticConfig: &config.Config{ - DurangoTime: time.Time{}, - EForkTime: mockable.MaxTime, + DurangoTime: time.Time{}, + EUpgradeTime: mockable.MaxTime, }, }) env.vm.ctx.Lock.Unlock() diff --git a/vms/avm/vm_test.go b/vms/avm/vm_test.go index f7c7d11af0e..a01aefd349d 100644 --- a/vms/avm/vm_test.go +++ b/vms/avm/vm_test.go @@ -135,8 +135,8 @@ func TestIssueNFT(t *testing.T) { env := setup(t, &envConfig{ vmStaticConfig: &config.Config{ - DurangoTime: time.Time{}, - EForkTime: mockable.MaxTime, + DurangoTime: time.Time{}, + EUpgradeTime: mockable.MaxTime, }, }) env.vm.ctx.Lock.Unlock() @@ -239,8 +239,8 @@ func TestIssueProperty(t *testing.T) { env := setup(t, &envConfig{ vmStaticConfig: &config.Config{ - DurangoTime: time.Time{}, - EForkTime: mockable.MaxTime, + DurangoTime: time.Time{}, + EUpgradeTime: mockable.MaxTime, }, additionalFxs: []*common.Fx{{ ID: propertyfx.ID, @@ -529,8 +529,8 @@ func TestIssueImportTx(t *testing.T) { env := setup(t, &envConfig{ vmStaticConfig: &config.Config{ - DurangoTime: time.Time{}, - EForkTime: mockable.MaxTime, + DurangoTime: time.Time{}, + EUpgradeTime: mockable.MaxTime, }, }) defer func() { @@ -632,8 +632,8 @@ func TestForceAcceptImportTx(t *testing.T) { env := setup(t, &envConfig{ vmStaticConfig: &config.Config{ - DurangoTime: time.Time{}, - EForkTime: mockable.MaxTime, + DurangoTime: time.Time{}, + EUpgradeTime: mockable.MaxTime, }, notLinearized: true, }) diff --git a/vms/platformvm/block/builder/helpers_test.go b/vms/platformvm/block/builder/helpers_test.go index 15ca13e2e10..92892df75ae 100644 --- a/vms/platformvm/block/builder/helpers_test.go +++ b/vms/platformvm/block/builder/helpers_test.go @@ -316,7 +316,7 @@ func defaultConfig() *config.Config { ApricotPhase5Time: defaultValidateEndTime, BanffTime: time.Time{}, // neglecting fork ordering this for package tests DurangoTime: time.Time{}, - EForkTime: mockable.MaxTime, + EUpgradeTime: mockable.MaxTime, } } diff --git a/vms/platformvm/block/executor/helpers_test.go b/vms/platformvm/block/executor/helpers_test.go index f134ecd73dd..9b98681c44c 100644 --- a/vms/platformvm/block/executor/helpers_test.go +++ b/vms/platformvm/block/executor/helpers_test.go @@ -344,7 +344,7 @@ func defaultConfig() *config.Config { ApricotPhase5Time: defaultValidateEndTime, BanffTime: mockable.MaxTime, DurangoTime: mockable.MaxTime, - EForkTime: mockable.MaxTime, + EUpgradeTime: mockable.MaxTime, } } diff --git a/vms/platformvm/config/config.go b/vms/platformvm/config/config.go index 292981ddc02..0ac37f81f08 100644 --- a/vms/platformvm/config/config.go +++ b/vms/platformvm/config/config.go @@ -108,7 +108,7 @@ type Config struct { DurangoTime time.Time // Time of the E network upgrade - EForkTime time.Time + EUpgradeTime time.Time // UseCurrentHeight forces [GetMinimumHeight] to return the current height // of the P-Chain instead of the oldest block in the [recentlyAccepted] @@ -141,7 +141,7 @@ func (c *Config) IsDurangoActivated(timestamp time.Time) bool { } func (c *Config) IsEForkActivated(timestamp time.Time) bool { - return !timestamp.Before(c.EForkTime) + return !timestamp.Before(c.EUpgradeTime) } func (c *Config) GetCreateBlockchainTxFee(timestamp time.Time) uint64 { diff --git a/vms/platformvm/txs/executor/helpers_test.go b/vms/platformvm/txs/executor/helpers_test.go index ce59a27e146..3d6683529cc 100644 --- a/vms/platformvm/txs/executor/helpers_test.go +++ b/vms/platformvm/txs/executor/helpers_test.go @@ -308,7 +308,7 @@ func defaultConfig(postBanff, postCortina, postDurango bool) *config.Config { BanffTime: banffTime, CortinaTime: cortinaTime, DurangoTime: durangoTime, - EForkTime: mockable.MaxTime, + EUpgradeTime: mockable.MaxTime, } } diff --git a/vms/platformvm/txs/executor/staker_tx_verification_test.go b/vms/platformvm/txs/executor/staker_tx_verification_test.go index c874e884561..aa602725083 100644 --- a/vms/platformvm/txs/executor/staker_tx_verification_test.go +++ b/vms/platformvm/txs/executor/staker_tx_verification_test.go @@ -112,8 +112,8 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { return &Backend{ Ctx: ctx, Config: &config.Config{ - DurangoTime: activeForkTime, // activate latest fork - EForkTime: mockable.MaxTime, + DurangoTime: activeForkTime, // activate latest fork + EUpgradeTime: mockable.MaxTime, }, } }, @@ -134,8 +134,8 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { return &Backend{ Ctx: ctx, Config: &config.Config{ - DurangoTime: activeForkTime, // activate latest fork - EForkTime: mockable.MaxTime, + DurangoTime: activeForkTime, // activate latest fork + EUpgradeTime: mockable.MaxTime, }, Bootstrapped: &utils.Atomic[bool]{}, } @@ -161,9 +161,9 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { return &Backend{ Ctx: ctx, Config: &config.Config{ - CortinaTime: activeForkTime, - DurangoTime: mockable.MaxTime, - EForkTime: mockable.MaxTime, + CortinaTime: activeForkTime, + DurangoTime: mockable.MaxTime, + EUpgradeTime: mockable.MaxTime, }, Bootstrapped: bootstrapped, } @@ -189,8 +189,8 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { return &Backend{ Ctx: ctx, Config: &config.Config{ - DurangoTime: activeForkTime, // activate latest fork - EForkTime: mockable.MaxTime, + DurangoTime: activeForkTime, // activate latest fork + EUpgradeTime: mockable.MaxTime, }, Bootstrapped: bootstrapped, } @@ -219,8 +219,8 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { return &Backend{ Ctx: ctx, Config: &config.Config{ - DurangoTime: activeForkTime, // activate latest fork - EForkTime: mockable.MaxTime, + DurangoTime: activeForkTime, // activate latest fork + EUpgradeTime: mockable.MaxTime, }, Bootstrapped: bootstrapped, } @@ -249,8 +249,8 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { return &Backend{ Ctx: ctx, Config: &config.Config{ - DurangoTime: activeForkTime, // activate latest fork - EForkTime: mockable.MaxTime, + DurangoTime: activeForkTime, // activate latest fork + EUpgradeTime: mockable.MaxTime, }, Bootstrapped: bootstrapped, } @@ -280,8 +280,8 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { return &Backend{ Ctx: ctx, Config: &config.Config{ - DurangoTime: activeForkTime, // activate latest fork - EForkTime: mockable.MaxTime, + DurangoTime: activeForkTime, // activate latest fork + EUpgradeTime: mockable.MaxTime, }, Bootstrapped: bootstrapped, } @@ -314,8 +314,8 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { return &Backend{ Ctx: ctx, Config: &config.Config{ - DurangoTime: activeForkTime, // activate latest fork - EForkTime: mockable.MaxTime, + DurangoTime: activeForkTime, // activate latest fork + EUpgradeTime: mockable.MaxTime, }, Bootstrapped: bootstrapped, } @@ -348,8 +348,8 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { return &Backend{ Ctx: ctx, Config: &config.Config{ - DurangoTime: activeForkTime, // activate latest fork - EForkTime: mockable.MaxTime, + DurangoTime: activeForkTime, // activate latest fork + EUpgradeTime: mockable.MaxTime, }, Bootstrapped: bootstrapped, } @@ -384,8 +384,8 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { return &Backend{ Ctx: ctx, Config: &config.Config{ - DurangoTime: activeForkTime, // activate latest fork - EForkTime: mockable.MaxTime, + DurangoTime: activeForkTime, // activate latest fork + EUpgradeTime: mockable.MaxTime, }, Bootstrapped: bootstrapped, } @@ -414,8 +414,8 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { return &Backend{ Ctx: ctx, Config: &config.Config{ - DurangoTime: activeForkTime, // activate latest fork - EForkTime: mockable.MaxTime, + DurangoTime: activeForkTime, // activate latest fork + EUpgradeTime: mockable.MaxTime, }, Bootstrapped: bootstrapped, } @@ -462,7 +462,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { Config: &config.Config{ AddSubnetValidatorFee: 1, DurangoTime: activeForkTime, // activate latest fork, - EForkTime: mockable.MaxTime, + EUpgradeTime: mockable.MaxTime, }, Ctx: ctx, Bootstrapped: bootstrapped, @@ -509,7 +509,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { Config: &config.Config{ CortinaTime: activeForkTime, DurangoTime: mockable.MaxTime, - EForkTime: mockable.MaxTime, + EUpgradeTime: mockable.MaxTime, AddSubnetValidatorFee: 1, }, Ctx: ctx, @@ -562,7 +562,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { Config: &config.Config{ AddSubnetValidatorFee: 1, DurangoTime: activeForkTime, // activate latest fork, - EForkTime: mockable.MaxTime, + EUpgradeTime: mockable.MaxTime, }, Ctx: ctx, Bootstrapped: bootstrapped, diff --git a/vms/platformvm/txs/executor/standard_tx_executor_test.go b/vms/platformvm/txs/executor/standard_tx_executor_test.go index aac52b57193..6fd7fd0bc1f 100644 --- a/vms/platformvm/txs/executor/standard_tx_executor_test.go +++ b/vms/platformvm/txs/executor/standard_tx_executor_test.go @@ -1749,10 +1749,10 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { e := &StandardTxExecutor{ Backend: &Backend{ Config: &config.Config{ - BanffTime: env.latestForkTime, - CortinaTime: env.latestForkTime, - DurangoTime: env.latestForkTime, - EForkTime: mockable.MaxTime, + BanffTime: env.latestForkTime, + CortinaTime: env.latestForkTime, + DurangoTime: env.latestForkTime, + EUpgradeTime: mockable.MaxTime, }, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, @@ -1777,10 +1777,10 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { e := &StandardTxExecutor{ Backend: &Backend{ Config: &config.Config{ - BanffTime: env.latestForkTime, - CortinaTime: env.latestForkTime, - DurangoTime: env.latestForkTime, - EForkTime: mockable.MaxTime, + BanffTime: env.latestForkTime, + CortinaTime: env.latestForkTime, + DurangoTime: env.latestForkTime, + EUpgradeTime: mockable.MaxTime, }, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, @@ -1806,10 +1806,10 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { e := &StandardTxExecutor{ Backend: &Backend{ Config: &config.Config{ - BanffTime: env.latestForkTime, - CortinaTime: env.latestForkTime, - DurangoTime: env.latestForkTime, - EForkTime: mockable.MaxTime, + BanffTime: env.latestForkTime, + CortinaTime: env.latestForkTime, + DurangoTime: env.latestForkTime, + EUpgradeTime: mockable.MaxTime, }, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, @@ -1838,10 +1838,10 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { e := &StandardTxExecutor{ Backend: &Backend{ Config: &config.Config{ - BanffTime: env.latestForkTime, - CortinaTime: env.latestForkTime, - DurangoTime: env.latestForkTime, - EForkTime: mockable.MaxTime, + BanffTime: env.latestForkTime, + CortinaTime: env.latestForkTime, + DurangoTime: env.latestForkTime, + EUpgradeTime: mockable.MaxTime, }, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, @@ -1868,10 +1868,10 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { e := &StandardTxExecutor{ Backend: &Backend{ Config: &config.Config{ - BanffTime: env.latestForkTime, - CortinaTime: env.latestForkTime, - DurangoTime: env.latestForkTime, - EForkTime: mockable.MaxTime, + BanffTime: env.latestForkTime, + CortinaTime: env.latestForkTime, + DurangoTime: env.latestForkTime, + EUpgradeTime: mockable.MaxTime, }, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, @@ -1897,10 +1897,10 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { e := &StandardTxExecutor{ Backend: &Backend{ Config: &config.Config{ - BanffTime: env.latestForkTime, - CortinaTime: env.latestForkTime, - DurangoTime: env.latestForkTime, - EForkTime: mockable.MaxTime, + BanffTime: env.latestForkTime, + CortinaTime: env.latestForkTime, + DurangoTime: env.latestForkTime, + EUpgradeTime: mockable.MaxTime, }, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, @@ -1928,10 +1928,10 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { e := &StandardTxExecutor{ Backend: &Backend{ Config: &config.Config{ - BanffTime: env.latestForkTime, - CortinaTime: env.latestForkTime, - DurangoTime: env.latestForkTime, - EForkTime: mockable.MaxTime, + BanffTime: env.latestForkTime, + CortinaTime: env.latestForkTime, + DurangoTime: env.latestForkTime, + EUpgradeTime: mockable.MaxTime, }, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, @@ -1962,10 +1962,10 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { e := &StandardTxExecutor{ Backend: &Backend{ Config: &config.Config{ - BanffTime: env.latestForkTime, - CortinaTime: env.latestForkTime, - DurangoTime: env.latestForkTime, - EForkTime: mockable.MaxTime, + BanffTime: env.latestForkTime, + CortinaTime: env.latestForkTime, + DurangoTime: env.latestForkTime, + EUpgradeTime: mockable.MaxTime, }, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, @@ -2120,10 +2120,10 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { e := &StandardTxExecutor{ Backend: &Backend{ Config: &config.Config{ - BanffTime: env.latestForkTime, - CortinaTime: env.latestForkTime, - DurangoTime: env.latestForkTime, - EForkTime: mockable.MaxTime, + BanffTime: env.latestForkTime, + CortinaTime: env.latestForkTime, + DurangoTime: env.latestForkTime, + EUpgradeTime: mockable.MaxTime, }, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, @@ -2148,10 +2148,10 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { e := &StandardTxExecutor{ Backend: &Backend{ Config: &config.Config{ - BanffTime: env.latestForkTime, - CortinaTime: env.latestForkTime, - DurangoTime: env.latestForkTime, - EForkTime: mockable.MaxTime, + BanffTime: env.latestForkTime, + CortinaTime: env.latestForkTime, + DurangoTime: env.latestForkTime, + EUpgradeTime: mockable.MaxTime, }, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, @@ -2181,7 +2181,7 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { CortinaTime: env.latestForkTime, DurangoTime: env.latestForkTime, MaxStakeDuration: math.MaxInt64, - EForkTime: mockable.MaxTime, + EUpgradeTime: mockable.MaxTime, }, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, @@ -2215,7 +2215,7 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { BanffTime: env.latestForkTime, CortinaTime: env.latestForkTime, DurangoTime: env.latestForkTime, - EForkTime: mockable.MaxTime, + EUpgradeTime: mockable.MaxTime, MaxStakeDuration: math.MaxInt64, }, Bootstrapped: &utils.Atomic[bool]{}, @@ -2255,7 +2255,7 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { BanffTime: env.latestForkTime, CortinaTime: env.latestForkTime, DurangoTime: env.latestForkTime, - EForkTime: mockable.MaxTime, + EUpgradeTime: mockable.MaxTime, MaxStakeDuration: math.MaxInt64, }, Bootstrapped: &utils.Atomic[bool]{}, diff --git a/vms/platformvm/validator_set_property_test.go b/vms/platformvm/validator_set_property_test.go index 7a879123af2..9a0fd7f8852 100644 --- a/vms/platformvm/validator_set_property_test.go +++ b/vms/platformvm/validator_set_property_test.go @@ -625,7 +625,7 @@ func buildVM(t *testing.T) (*VM, ids.ID, error) { ApricotPhase5Time: forkTime, BanffTime: forkTime, CortinaTime: forkTime, - EForkTime: mockable.MaxTime, + EUpgradeTime: mockable.MaxTime, }} vm.clock.Set(forkTime.Add(time.Second)) diff --git a/vms/platformvm/vm_regression_test.go b/vms/platformvm/vm_regression_test.go index 761a4ad0812..4335ae46003 100644 --- a/vms/platformvm/vm_regression_test.go +++ b/vms/platformvm/vm_regression_test.go @@ -374,7 +374,7 @@ func TestUnverifiedParentPanicRegression(t *testing.T) { BanffTime: latestForkTime, CortinaTime: mockable.MaxTime, DurangoTime: mockable.MaxTime, - EForkTime: mockable.MaxTime, + EUpgradeTime: mockable.MaxTime, }} ctx := snowtest.Context(t, snowtest.PChainID) diff --git a/vms/platformvm/vm_test.go b/vms/platformvm/vm_test.go index 5af9deb95db..94e158582cc 100644 --- a/vms/platformvm/vm_test.go +++ b/vms/platformvm/vm_test.go @@ -254,7 +254,7 @@ func defaultVM(t *testing.T, fork activeFork) (*VM, database.Database, *mutableS BanffTime: banffTime, CortinaTime: cortinaTime, DurangoTime: durangoTime, - EForkTime: mockable.MaxTime, + EUpgradeTime: mockable.MaxTime, }} db := memdb.New() @@ -1113,7 +1113,7 @@ func TestRestartFullyAccepted(t *testing.T) { BanffTime: latestForkTime, CortinaTime: latestForkTime, DurangoTime: latestForkTime, - EForkTime: mockable.MaxTime, + EUpgradeTime: mockable.MaxTime, }} firstCtx := snowtest.Context(t, snowtest.PChainID) @@ -1201,7 +1201,7 @@ func TestRestartFullyAccepted(t *testing.T) { BanffTime: latestForkTime, CortinaTime: latestForkTime, DurangoTime: latestForkTime, - EForkTime: mockable.MaxTime, + EUpgradeTime: mockable.MaxTime, }} secondCtx := snowtest.Context(t, snowtest.PChainID) @@ -1252,7 +1252,7 @@ func TestBootstrapPartiallyAccepted(t *testing.T) { BanffTime: latestForkTime, CortinaTime: latestForkTime, DurangoTime: latestForkTime, - EForkTime: mockable.MaxTime, + EUpgradeTime: mockable.MaxTime, }} initialClkTime := latestForkTime.Add(time.Second) @@ -1594,7 +1594,7 @@ func TestUnverifiedParent(t *testing.T) { BanffTime: latestForkTime, CortinaTime: latestForkTime, DurangoTime: latestForkTime, - EForkTime: mockable.MaxTime, + EUpgradeTime: mockable.MaxTime, }} initialClkTime := latestForkTime.Add(time.Second) @@ -1755,7 +1755,7 @@ func TestUptimeDisallowedWithRestart(t *testing.T) { BanffTime: latestForkTime, CortinaTime: latestForkTime, DurangoTime: latestForkTime, - EForkTime: mockable.MaxTime, + EUpgradeTime: mockable.MaxTime, }} firstCtx := snowtest.Context(t, snowtest.PChainID) @@ -1804,7 +1804,7 @@ func TestUptimeDisallowedWithRestart(t *testing.T) { BanffTime: latestForkTime, CortinaTime: latestForkTime, DurangoTime: latestForkTime, - EForkTime: mockable.MaxTime, + EUpgradeTime: mockable.MaxTime, }} secondCtx := snowtest.Context(t, snowtest.PChainID) @@ -1904,7 +1904,7 @@ func TestUptimeDisallowedAfterNeverConnecting(t *testing.T) { BanffTime: latestForkTime, CortinaTime: latestForkTime, DurangoTime: latestForkTime, - EForkTime: mockable.MaxTime, + EUpgradeTime: mockable.MaxTime, }} ctx := snowtest.Context(t, snowtest.PChainID) From 62ab6d03ec03bd6be3973820b56d11f9acd0efe1 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Fri, 2 Feb 2024 09:39:30 +0100 Subject: [PATCH 04/27] upgraded codec for dynamic fees --- codec/manager.go | 6 +- codec/reflectcodec/type_codec.go | 16 ++--- codec/test_codec.go | 81 ++++++++++++++++++++++ vms/platformvm/state/metadata_validator.go | 3 +- 4 files changed, 94 insertions(+), 12 deletions(-) diff --git a/codec/manager.go b/codec/manager.go index 6fb48aaad9f..bf1ad3af72b 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 @@ -102,8 +104,8 @@ 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 + // Add [CodecVersionSize] for the codec version + return CodecVersionSize + res, err } // To marshal an interface, [value] must be a pointer to the interface. diff --git a/codec/reflectcodec/type_codec.go b/codec/reflectcodec/type_codec.go index 31292755928..e8b19e80fe8 100644 --- a/codec/reflectcodec/type_codec.go +++ b/codec/reflectcodec/type_codec.go @@ -27,8 +27,6 @@ const ( var ( _ codec.Codec = (*genericCodec)(nil) - errMarshalNil = errors.New("can't marshal nil pointer or interface") - errUnmarshalNil = errors.New("can't unmarshal nil") errNeedPointer = errors.New("argument to unmarshal must be a pointer") errRecursiveInterfaceTypes = errors.New("recursive interface types") ) @@ -90,7 +88,7 @@ func New(typer TypeCodec, tagNames []string, durangoTime time.Time, maxSliceLen func (c *genericCodec) Size(value interface{}) (int, error) { if value == nil { - return 0, errMarshalNil // can't marshal nil + return 0, nil // can't marshal nil, we return zero size } size, _, err := c.size(reflect.ValueOf(value), nil /*=typeStack*/) @@ -126,14 +124,14 @@ func (c *genericCodec) size( return wrappers.StringLen(value.String()), false, nil case reflect.Ptr: if value.IsNil() { - return 0, false, errMarshalNil + return 0, false, nil // can't marshal nil, we return zero size } return c.size(value.Elem(), typeStack) case reflect.Interface: if value.IsNil() { - return 0, false, errMarshalNil + return 0, false, nil // can't marshal nil, we return zero size } underlyingValue := value.Interface() @@ -292,7 +290,7 @@ func (c *genericCodec) size( // To marshal an interface, [value] must be a pointer to the interface func (c *genericCodec) MarshalInto(value interface{}, p *wrappers.Packer) error { if value == nil { - return errMarshalNil // can't marshal nil + return codec.ErrMarshalNil // can't marshal nil } return c.marshal(reflect.ValueOf(value), p, nil /*=typeStack*/) @@ -339,13 +337,13 @@ func (c *genericCodec) marshal( return p.Err case reflect.Ptr: if value.IsNil() { - return errMarshalNil + return codec.ErrMarshalNil } return c.marshal(value.Elem(), p, typeStack) case reflect.Interface: if value.IsNil() { - return errMarshalNil + return codec.ErrMarshalNil } underlyingValue := value.Interface() @@ -505,7 +503,7 @@ func (c *genericCodec) marshal( // interface func (c *genericCodec) Unmarshal(bytes []byte, dest interface{}) error { if dest == nil { - return errUnmarshalNil + return codec.ErrUnmarshalNil } p := wrappers.Packer{ diff --git a/codec/test_codec.go b/codec/test_codec.go index d58e2d818f9..ed484042941 100644 --- a/codec/test_codec.go +++ b/codec/test_codec.go @@ -15,6 +15,8 @@ import ( var ( Tests = []func(c GeneralCodec, t testing.TB){ TestStruct, + TestPartiallyFilledStruct, + TestSliceWithEmptyElements, TestRegisterStructTwice, TestUInt32, TestUIntPtr, @@ -249,6 +251,85 @@ func TestStruct(codec GeneralCodec, t testing.TB) { require.Equal(myStructInstance, *myStructUnmarshaled) } +func TestPartiallyFilledStruct(codec GeneralCodec, t testing.TB) { + require := require.New(t) + + manager := NewDefaultManager() + require.NoError(manager.RegisterCodec(0, codec)) + + // a nil pointer cannot be marshalled but we can get its size + var nilStruct *myStruct + _, err := manager.Marshal(0, nilStruct) + require.ErrorIs(err, ErrMarshalNil) + + bytesLen, err := manager.Size(0, nilStruct) + require.NoError(err) + require.Equal(CodecVersionSize, bytesLen) + + // an empty struct cannot be marshalled but we can get its size + emptyStruct := &myStruct{} + _, err = manager.Marshal(0, nilStruct) + require.ErrorIs(err, ErrMarshalNil) + + emptyStructLen := CodecVersionSize + 117 + bytesLen, err = manager.Size(0, emptyStruct) + require.NoError(err) + require.Equal(emptyStructLen, bytesLen) + + // an partially filled struct cannot be marshalled but we can get its size + elem := &MyInnerStruct{ + Str: "a", + } + elemLen := CodecVersionSize + wrappers.StringLen(elem.Str) + + partialStruct := &myStruct{ + InnerStruct2: elem, + } + partialStructLen := emptyStructLen + elemLen - CodecVersionSize + bytesLen, err = manager.Size(0, partialStruct) + require.NoError(err) + require.Equal(partialStructLen, bytesLen) +} + +func TestSliceWithEmptyElements(codec GeneralCodec, t testing.TB) { + require := require.New(t) + + manager := NewDefaultManager() + require.NoError(manager.RegisterCodec(0, codec)) + + // a non-empty slice with nil pointers cannot be marshalled but we can get its size + slice := make([]*MyInnerStruct, 10) + + _, err := manager.Marshal(0, slice) + require.ErrorIs(err, ErrMarshalNil) + + emptySliceLen := CodecVersionSize + wrappers.IntLen // Codec version + slice size. Slice elements have zero size + bytesLen, err := manager.Size(0, slice) + require.NoError(err) + require.Equal(emptySliceLen, bytesLen) + + elem := &MyInnerStruct{ + Str: "aaa", + } + elemLen := CodecVersionSize + wrappers.StringLen(elem.Str) + bytesLen, err = manager.Size(0, elem) + require.NoError(err) + require.Equal(elemLen, bytesLen) + + // we can fill some elements and leave other empty. Size will be sub-additive + slice[1] = elem + sliceLen := emptySliceLen + elemLen - CodecVersionSize // codec version is marshelled only once + bytesLen, err = manager.Size(0, slice) + require.NoError(err) + require.Equal(sliceLen, bytesLen) + + slice[5] = elem + sliceLen += elemLen - CodecVersionSize // codec version is marshelled only once + bytesLen, err = manager.Size(0, slice) + require.NoError(err) + require.Equal(sliceLen, bytesLen) +} + func TestRegisterStructTwice(codec GeneralCodec, t testing.TB) { require := require.New(t) diff --git a/vms/platformvm/state/metadata_validator.go b/vms/platformvm/state/metadata_validator.go index 0c725368505..74242150d37 100644 --- a/vms/platformvm/state/metadata_validator.go +++ b/vms/platformvm/state/metadata_validator.go @@ -6,6 +6,7 @@ package state import ( "time" + "github.com/ava-labs/avalanchego/codec" "github.com/ava-labs/avalanchego/database" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils/constants" @@ -17,7 +18,7 @@ import ( // [preDelegateeRewardMetadata]. // // CodecVersionLen + UpDurationLen + LastUpdatedLen + PotentialRewardLen -const preDelegateeRewardSize = wrappers.ShortLen + 3*wrappers.LongLen +const preDelegateeRewardSize = codec.CodecVersionSize + 3*wrappers.LongLen var _ validatorState = (*metadata)(nil) From 22417110dfa25bd4b8f04d7fa7294375bfa5edba Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Fri, 2 Feb 2024 10:29:54 +0100 Subject: [PATCH 05/27] wip: introducing x-chain fee calculator --- vms/avm/txs/executor/semantic_verifier.go | 79 +- vms/avm/txs/executor/syntactic_verifier.go | 62 - .../txs/executor/syntactic_verifier_test.go | 2209 ++++++++--------- vms/avm/txs/fees/calculator.go | 44 + 4 files changed, 1200 insertions(+), 1194 deletions(-) create mode 100644 vms/avm/txs/fees/calculator.go diff --git a/vms/avm/txs/executor/semantic_verifier.go b/vms/avm/txs/executor/semantic_verifier.go index 946346bc064..d8d95d6313a 100644 --- a/vms/avm/txs/executor/semantic_verifier.go +++ b/vms/avm/txs/executor/semantic_verifier.go @@ -11,6 +11,7 @@ import ( "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/vms/avm/state" "github.com/ava-labs/avalanchego/vms/avm/txs" + "github.com/ava-labs/avalanchego/vms/avm/txs/fees" "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/components/verify" ) @@ -31,36 +32,15 @@ type SemanticVerifier struct { } func (v *SemanticVerifier) BaseTx(tx *txs.BaseTx) error { - for i, in := range tx.Ins { - // Note: Verification of the length of [t.tx.Creds] happens during - // syntactic verification, which happens before semantic verification. - cred := v.Tx.Creds[i].Credential - if err := v.verifyTransfer(tx, in, cred); err != nil { - return err - } - } - - for _, out := range tx.Outs { - fxIndex, err := v.getFx(out.Out) - if err != nil { - return err - } - - assetID := out.AssetID() - if err := v.verifyFxUsage(fxIndex, assetID); err != nil { - return err - } - } - - return nil + return v.verifyBaseTx(tx, nil, nil) } func (v *SemanticVerifier) CreateAssetTx(tx *txs.CreateAssetTx) error { - return v.BaseTx(&tx.BaseTx) + return v.verifyBaseTx(&tx.BaseTx, nil, nil) } func (v *SemanticVerifier) OperationTx(tx *txs.OperationTx) error { - if err := v.BaseTx(&tx.BaseTx); err != nil { + if err := v.verifyBaseTx(&tx.BaseTx, nil, nil); err != nil { return err } @@ -81,7 +61,7 @@ func (v *SemanticVerifier) OperationTx(tx *txs.OperationTx) error { } func (v *SemanticVerifier) ImportTx(tx *txs.ImportTx) error { - if err := v.BaseTx(&tx.BaseTx); err != nil { + if err := v.verifyBaseTx(&tx.BaseTx, tx.ImportedIns, nil); err != nil { return err } @@ -122,7 +102,7 @@ func (v *SemanticVerifier) ImportTx(tx *txs.ImportTx) error { } func (v *SemanticVerifier) ExportTx(tx *txs.ExportTx) error { - if err := v.BaseTx(&tx.BaseTx); err != nil { + if err := v.verifyBaseTx(&tx.BaseTx, nil, tx.ExportedOuts); err != nil { return err } @@ -146,6 +126,53 @@ func (v *SemanticVerifier) ExportTx(tx *txs.ExportTx) error { return nil } +func (v *SemanticVerifier) verifyBaseTx( + tx *txs.BaseTx, + importedIns []*avax.TransferableInput, + exportedOuts []*avax.TransferableOutput, +) error { + feeCalculator := fees.Calculator{ + Config: v.Config, + } + if err := tx.Visit(&feeCalculator); err != nil { + return err + } + + err := avax.VerifyTx( + feeCalculator.Fee, + v.FeeAssetID, + [][]*avax.TransferableInput{tx.Ins, importedIns}, + [][]*avax.TransferableOutput{tx.Outs, exportedOuts}, + v.Codec, + ) + if err != nil { + return err + } + + for i, in := range tx.Ins { + // Note: Verification of the length of [t.tx.Creds] happens during + // syntactic verification, which happens before semantic verification. + cred := v.Tx.Creds[i].Credential + if err := v.verifyTransfer(tx, in, cred); err != nil { + return err + } + } + + for _, out := range tx.Outs { + fxIndex, err := v.getFx(out.Out) + if err != nil { + return err + } + + assetID := out.AssetID() + if err := v.verifyFxUsage(fxIndex, assetID); err != nil { + return err + } + } + + return nil +} + func (v *SemanticVerifier) verifyTransfer( tx txs.UnsignedTx, in *avax.TransferableInput, diff --git a/vms/avm/txs/executor/syntactic_verifier.go b/vms/avm/txs/executor/syntactic_verifier.go index 81a2f2a715f..726f69644ee 100644 --- a/vms/avm/txs/executor/syntactic_verifier.go +++ b/vms/avm/txs/executor/syntactic_verifier.go @@ -13,7 +13,6 @@ 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/components/avax" ) const ( @@ -55,17 +54,6 @@ func (v *SyntacticVerifier) BaseTx(tx *txs.BaseTx) error { return err } - err := avax.VerifyTx( - v.Config.TxFee, - v.FeeAssetID, - [][]*avax.TransferableInput{tx.Ins}, - [][]*avax.TransferableOutput{tx.Outs}, - v.Codec, - ) - if err != nil { - return err - } - for _, cred := range v.Tx.Creds { if err := cred.Verify(); err != nil { return err @@ -118,17 +106,6 @@ func (v *SyntacticVerifier) CreateAssetTx(tx *txs.CreateAssetTx) error { return err } - err := avax.VerifyTx( - v.Config.CreateAssetTxFee, - v.FeeAssetID, - [][]*avax.TransferableInput{tx.Ins}, - [][]*avax.TransferableOutput{tx.Outs}, - v.Codec, - ) - if err != nil { - return err - } - for _, state := range tx.States { if err := state.Verify(v.Codec, len(v.Fxs)); err != nil { return err @@ -166,17 +143,6 @@ func (v *SyntacticVerifier) OperationTx(tx *txs.OperationTx) error { return err } - err := avax.VerifyTx( - v.Config.TxFee, - v.FeeAssetID, - [][]*avax.TransferableInput{tx.Ins}, - [][]*avax.TransferableOutput{tx.Outs}, - v.Codec, - ) - if err != nil { - return err - } - inputs := set.NewSet[ids.ID](len(tx.Ins)) for _, in := range tx.Ins { inputs.Add(in.InputID()) @@ -226,20 +192,6 @@ func (v *SyntacticVerifier) ImportTx(tx *txs.ImportTx) error { return err } - err := avax.VerifyTx( - v.Config.TxFee, - v.FeeAssetID, - [][]*avax.TransferableInput{ - tx.Ins, - tx.ImportedIns, - }, - [][]*avax.TransferableOutput{tx.Outs}, - v.Codec, - ) - if err != nil { - return err - } - for _, cred := range v.Tx.Creds { if err := cred.Verify(); err != nil { return err @@ -268,20 +220,6 @@ func (v *SyntacticVerifier) ExportTx(tx *txs.ExportTx) error { return err } - err := avax.VerifyTx( - v.Config.TxFee, - v.FeeAssetID, - [][]*avax.TransferableInput{tx.Ins}, - [][]*avax.TransferableOutput{ - tx.Outs, - tx.ExportedOuts, - }, - v.Codec, - ) - if err != nil { - return err - } - for _, cred := range v.Tx.Creds { if err := cred.Verify(); err != nil { return err diff --git a/vms/avm/txs/executor/syntactic_verifier_test.go b/vms/avm/txs/executor/syntactic_verifier_test.go index cc160ed7982..30a36fadc18 100644 --- a/vms/avm/txs/executor/syntactic_verifier_test.go +++ b/vms/avm/txs/executor/syntactic_verifier_test.go @@ -4,7 +4,6 @@ package executor import ( - "math" "strings" "testing" "time" @@ -22,8 +21,6 @@ import ( "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/components/verify" "github.com/ava-labs/avalanchego/vms/secp256k1fx" - - safemath "github.com/ava-labs/avalanchego/utils/math" ) var ( @@ -163,177 +160,177 @@ func TestSyntacticVerifierBaseTx(t *testing.T) { }, err: avax.ErrMemoTooLarge, }, - { - name: "invalid output", - txFunc: func() *txs.Tx { - output := output - output.Out = &secp256k1fx.TransferOutput{ - Amt: 0, - OutputOwners: outputOwners, - } - - baseTx := baseTx - baseTx.Outs = []*avax.TransferableOutput{ - &output, - } - return &txs.Tx{ - Unsigned: &txs.BaseTx{BaseTx: baseTx}, - Creds: creds, - } - }, - err: secp256k1fx.ErrNoValueOutput, - }, - { - name: "unsorted outputs", - txFunc: func() *txs.Tx { - output0 := output - output0.Out = &secp256k1fx.TransferOutput{ - Amt: 1, - OutputOwners: outputOwners, - } - - output1 := output - output1.Out = &secp256k1fx.TransferOutput{ - Amt: 2, - OutputOwners: outputOwners, - } - - outputs := []*avax.TransferableOutput{ - &output0, - &output1, - } - avax.SortTransferableOutputs(outputs, codec) - outputs[0], outputs[1] = outputs[1], outputs[0] - - baseTx := baseTx - baseTx.Outs = outputs - return &txs.Tx{ - Unsigned: &txs.BaseTx{BaseTx: baseTx}, - Creds: creds, - } - }, - err: avax.ErrOutputsNotSorted, - }, - { - name: "invalid input", - txFunc: func() *txs.Tx { - input := input - input.In = &secp256k1fx.TransferInput{ - Amt: 0, - Input: inputSigners, - } - - baseTx := baseTx - baseTx.Ins = []*avax.TransferableInput{ - &input, - } - return &txs.Tx{ - Unsigned: &txs.BaseTx{BaseTx: baseTx}, - Creds: creds, - } - }, - err: secp256k1fx.ErrNoValueInput, - }, - { - name: "duplicate inputs", - txFunc: func() *txs.Tx { - baseTx := baseTx - baseTx.Ins = []*avax.TransferableInput{ - &input, - &input, - } - return &txs.Tx{ - Unsigned: &txs.BaseTx{BaseTx: baseTx}, - Creds: []*fxs.FxCredential{ - &cred, - &cred, - }, - } - }, - err: avax.ErrInputsNotSortedUnique, - }, - { - name: "input overflow", - txFunc: func() *txs.Tx { - input0 := input - input0.In = &secp256k1fx.TransferInput{ - Amt: 1, - Input: inputSigners, - } - - input1 := input - input1.UTXOID.OutputIndex++ - input1.In = &secp256k1fx.TransferInput{ - Amt: math.MaxUint64, - Input: inputSigners, - } - - baseTx := baseTx - baseTx.Ins = []*avax.TransferableInput{ - &input0, - &input1, - } - avax.SortTransferableInputsWithSigners(baseTx.Ins, make([][]*secp256k1.PrivateKey, 2)) - return &txs.Tx{ - Unsigned: &txs.BaseTx{BaseTx: baseTx}, - Creds: []*fxs.FxCredential{ - &cred, - &cred, - }, - } - }, - err: safemath.ErrOverflow, - }, - { - name: "output overflow", - txFunc: func() *txs.Tx { - output0 := output - output0.Out = &secp256k1fx.TransferOutput{ - Amt: 1, - OutputOwners: outputOwners, - } - - output1 := output - output1.Out = &secp256k1fx.TransferOutput{ - Amt: math.MaxUint64, - OutputOwners: outputOwners, - } - - outputs := []*avax.TransferableOutput{ - &output0, - &output1, - } - avax.SortTransferableOutputs(outputs, codec) - - baseTx := baseTx - baseTx.Outs = outputs - return &txs.Tx{ - Unsigned: &txs.BaseTx{BaseTx: baseTx}, - Creds: creds, - } - }, - err: safemath.ErrOverflow, - }, - { - name: "insufficient funds", - txFunc: func() *txs.Tx { - input := input - input.In = &secp256k1fx.TransferInput{ - Amt: 1, - Input: inputSigners, - } - - baseTx := baseTx - baseTx.Ins = []*avax.TransferableInput{ - &input, - } - return &txs.Tx{ - Unsigned: &txs.BaseTx{BaseTx: baseTx}, - Creds: creds, - } - }, - err: avax.ErrInsufficientFunds, - }, + // { + // name: "invalid output", + // txFunc: func() *txs.Tx { + // output := output + // output.Out = &secp256k1fx.TransferOutput{ + // Amt: 0, + // OutputOwners: outputOwners, + // } + + // baseTx := baseTx + // baseTx.Outs = []*avax.TransferableOutput{ + // &output, + // } + // return &txs.Tx{ + // Unsigned: &txs.BaseTx{BaseTx: baseTx}, + // Creds: creds, + // } + // }, + // err: secp256k1fx.ErrNoValueOutput, + // }, + // { + // name: "unsorted outputs", + // txFunc: func() *txs.Tx { + // output0 := output + // output0.Out = &secp256k1fx.TransferOutput{ + // Amt: 1, + // OutputOwners: outputOwners, + // } + + // output1 := output + // output1.Out = &secp256k1fx.TransferOutput{ + // Amt: 2, + // OutputOwners: outputOwners, + // } + + // outputs := []*avax.TransferableOutput{ + // &output0, + // &output1, + // } + // avax.SortTransferableOutputs(outputs, codec) + // outputs[0], outputs[1] = outputs[1], outputs[0] + + // baseTx := baseTx + // baseTx.Outs = outputs + // return &txs.Tx{ + // Unsigned: &txs.BaseTx{BaseTx: baseTx}, + // Creds: creds, + // } + // }, + // err: avax.ErrOutputsNotSorted, + // }, + // { + // name: "invalid input", + // txFunc: func() *txs.Tx { + // input := input + // input.In = &secp256k1fx.TransferInput{ + // Amt: 0, + // Input: inputSigners, + // } + + // baseTx := baseTx + // baseTx.Ins = []*avax.TransferableInput{ + // &input, + // } + // return &txs.Tx{ + // Unsigned: &txs.BaseTx{BaseTx: baseTx}, + // Creds: creds, + // } + // }, + // err: secp256k1fx.ErrNoValueInput, + // }, + // { + // name: "duplicate inputs", + // txFunc: func() *txs.Tx { + // baseTx := baseTx + // baseTx.Ins = []*avax.TransferableInput{ + // &input, + // &input, + // } + // return &txs.Tx{ + // Unsigned: &txs.BaseTx{BaseTx: baseTx}, + // Creds: []*fxs.FxCredential{ + // &cred, + // &cred, + // }, + // } + // }, + // err: avax.ErrInputsNotSortedUnique, + // }, + // { + // name: "input overflow", + // txFunc: func() *txs.Tx { + // input0 := input + // input0.In = &secp256k1fx.TransferInput{ + // Amt: 1, + // Input: inputSigners, + // } + + // input1 := input + // input1.UTXOID.OutputIndex++ + // input1.In = &secp256k1fx.TransferInput{ + // Amt: math.MaxUint64, + // Input: inputSigners, + // } + + // baseTx := baseTx + // baseTx.Ins = []*avax.TransferableInput{ + // &input0, + // &input1, + // } + // avax.SortTransferableInputsWithSigners(baseTx.Ins, make([][]*secp256k1.PrivateKey, 2)) + // return &txs.Tx{ + // Unsigned: &txs.BaseTx{BaseTx: baseTx}, + // Creds: []*fxs.FxCredential{ + // &cred, + // &cred, + // }, + // } + // }, + // err: safemath.ErrOverflow, + // }, + // { + // name: "output overflow", + // txFunc: func() *txs.Tx { + // output0 := output + // output0.Out = &secp256k1fx.TransferOutput{ + // Amt: 1, + // OutputOwners: outputOwners, + // } + + // output1 := output + // output1.Out = &secp256k1fx.TransferOutput{ + // Amt: math.MaxUint64, + // OutputOwners: outputOwners, + // } + + // outputs := []*avax.TransferableOutput{ + // &output0, + // &output1, + // } + // avax.SortTransferableOutputs(outputs, codec) + + // baseTx := baseTx + // baseTx.Outs = outputs + // return &txs.Tx{ + // Unsigned: &txs.BaseTx{BaseTx: baseTx}, + // Creds: creds, + // } + // }, + // err: safemath.ErrOverflow, + // }, + // { + // name: "insufficient funds", + // txFunc: func() *txs.Tx { + // input := input + // input.In = &secp256k1fx.TransferInput{ + // Amt: 1, + // Input: inputSigners, + // } + + // baseTx := baseTx + // baseTx.Ins = []*avax.TransferableInput{ + // &input, + // } + // return &txs.Tx{ + // Unsigned: &txs.BaseTx{BaseTx: baseTx}, + // Creds: creds, + // } + // }, + // err: avax.ErrInsufficientFunds, + // }, { name: "invalid credential", txFunc: func() *txs.Tx { @@ -355,46 +352,46 @@ func TestSyntacticVerifierBaseTx(t *testing.T) { }, err: errWrongNumberOfCredentials, }, - { - name: "barely sufficient funds", - txFunc: func() *txs.Tx { - input := input - input.In = &secp256k1fx.TransferInput{ - Amt: fxOutput.Amt + feeConfig.TxFee, - Input: inputSigners, - } - - baseTx := baseTx - baseTx.Ins = []*avax.TransferableInput{ - &input, - } - return &txs.Tx{ - Unsigned: &txs.BaseTx{BaseTx: baseTx}, - Creds: creds, - } - }, - err: nil, - }, - { - name: "barely insufficient funds", - txFunc: func() *txs.Tx { - input := input - input.In = &secp256k1fx.TransferInput{ - Amt: fxOutput.Amt + feeConfig.TxFee - 1, - Input: inputSigners, - } - - baseTx := baseTx - baseTx.Ins = []*avax.TransferableInput{ - &input, - } - return &txs.Tx{ - Unsigned: &txs.BaseTx{BaseTx: baseTx}, - Creds: creds, - } - }, - err: avax.ErrInsufficientFunds, - }, + // { + // name: "barely sufficient funds", + // txFunc: func() *txs.Tx { + // input := input + // input.In = &secp256k1fx.TransferInput{ + // Amt: fxOutput.Amt + feeConfig.TxFee, + // Input: inputSigners, + // } + + // baseTx := baseTx + // baseTx.Ins = []*avax.TransferableInput{ + // &input, + // } + // return &txs.Tx{ + // Unsigned: &txs.BaseTx{BaseTx: baseTx}, + // Creds: creds, + // } + // }, + // err: nil, + // }, + // { + // name: "barely insufficient funds", + // txFunc: func() *txs.Tx { + // input := input + // input.In = &secp256k1fx.TransferInput{ + // Amt: fxOutput.Amt + feeConfig.TxFee - 1, + // Input: inputSigners, + // } + + // baseTx := baseTx + // baseTx.Ins = []*avax.TransferableInput{ + // &input, + // } + // return &txs.Tx{ + // Unsigned: &txs.BaseTx{BaseTx: baseTx}, + // Creds: creds, + // } + // }, + // err: avax.ErrInsufficientFunds, + // }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { @@ -659,177 +656,177 @@ func TestSyntacticVerifierCreateAssetTx(t *testing.T) { }, err: avax.ErrMemoTooLarge, }, - { - name: "invalid output", - txFunc: func() *txs.Tx { - output := output - output.Out = &secp256k1fx.TransferOutput{ - Amt: 0, - OutputOwners: outputOwners, - } - - tx := tx - tx.Outs = []*avax.TransferableOutput{ - &output, - } - return &txs.Tx{ - Unsigned: &tx, - Creds: creds, - } - }, - err: secp256k1fx.ErrNoValueOutput, - }, - { - name: "unsorted outputs", - txFunc: func() *txs.Tx { - output0 := output - output0.Out = &secp256k1fx.TransferOutput{ - Amt: 1, - OutputOwners: outputOwners, - } - - output1 := output - output1.Out = &secp256k1fx.TransferOutput{ - Amt: 2, - OutputOwners: outputOwners, - } - - outputs := []*avax.TransferableOutput{ - &output0, - &output1, - } - avax.SortTransferableOutputs(outputs, codec) - outputs[0], outputs[1] = outputs[1], outputs[0] - - tx := tx - tx.Outs = outputs - return &txs.Tx{ - Unsigned: &tx, - Creds: creds, - } - }, - err: avax.ErrOutputsNotSorted, - }, - { - name: "invalid input", - txFunc: func() *txs.Tx { - input := input - input.In = &secp256k1fx.TransferInput{ - Amt: 0, - Input: inputSigners, - } - - tx := tx - tx.Ins = []*avax.TransferableInput{ - &input, - } - return &txs.Tx{ - Unsigned: &tx, - Creds: creds, - } - }, - err: secp256k1fx.ErrNoValueInput, - }, - { - name: "duplicate inputs", - txFunc: func() *txs.Tx { - tx := tx - tx.Ins = []*avax.TransferableInput{ - &input, - &input, - } - return &txs.Tx{ - Unsigned: &tx, - Creds: []*fxs.FxCredential{ - &cred, - &cred, - }, - } - }, - err: avax.ErrInputsNotSortedUnique, - }, - { - name: "input overflow", - txFunc: func() *txs.Tx { - input0 := input - input0.In = &secp256k1fx.TransferInput{ - Amt: 1, - Input: inputSigners, - } - - input1 := input - input1.UTXOID.OutputIndex++ - input1.In = &secp256k1fx.TransferInput{ - Amt: math.MaxUint64, - Input: inputSigners, - } - - tx := tx - tx.Ins = []*avax.TransferableInput{ - &input0, - &input1, - } - avax.SortTransferableInputsWithSigners(baseTx.Ins, make([][]*secp256k1.PrivateKey, 2)) - return &txs.Tx{ - Unsigned: &tx, - Creds: []*fxs.FxCredential{ - &cred, - &cred, - }, - } - }, - err: safemath.ErrOverflow, - }, - { - name: "output overflow", - txFunc: func() *txs.Tx { - output0 := output - output0.Out = &secp256k1fx.TransferOutput{ - Amt: 1, - OutputOwners: outputOwners, - } - - output1 := output - output1.Out = &secp256k1fx.TransferOutput{ - Amt: math.MaxUint64, - OutputOwners: outputOwners, - } - - outputs := []*avax.TransferableOutput{ - &output0, - &output1, - } - avax.SortTransferableOutputs(outputs, codec) - - tx := tx - tx.Outs = outputs - return &txs.Tx{ - Unsigned: &tx, - Creds: creds, - } - }, - err: safemath.ErrOverflow, - }, - { - name: "insufficient funds", - txFunc: func() *txs.Tx { - input := input - input.In = &secp256k1fx.TransferInput{ - Amt: 1, - Input: inputSigners, - } - - tx := tx - tx.Ins = []*avax.TransferableInput{ - &input, - } - return &txs.Tx{ - Unsigned: &tx, - Creds: creds, - } - }, - err: avax.ErrInsufficientFunds, - }, + // { + // name: "invalid output", + // txFunc: func() *txs.Tx { + // output := output + // output.Out = &secp256k1fx.TransferOutput{ + // Amt: 0, + // OutputOwners: outputOwners, + // } + + // tx := tx + // tx.Outs = []*avax.TransferableOutput{ + // &output, + // } + // return &txs.Tx{ + // Unsigned: &tx, + // Creds: creds, + // } + // }, + // err: secp256k1fx.ErrNoValueOutput, + // }, + // { + // name: "unsorted outputs", + // txFunc: func() *txs.Tx { + // output0 := output + // output0.Out = &secp256k1fx.TransferOutput{ + // Amt: 1, + // OutputOwners: outputOwners, + // } + + // output1 := output + // output1.Out = &secp256k1fx.TransferOutput{ + // Amt: 2, + // OutputOwners: outputOwners, + // } + + // outputs := []*avax.TransferableOutput{ + // &output0, + // &output1, + // } + // avax.SortTransferableOutputs(outputs, codec) + // outputs[0], outputs[1] = outputs[1], outputs[0] + + // tx := tx + // tx.Outs = outputs + // return &txs.Tx{ + // Unsigned: &tx, + // Creds: creds, + // } + // }, + // err: avax.ErrOutputsNotSorted, + // }, + // { + // name: "invalid input", + // txFunc: func() *txs.Tx { + // input := input + // input.In = &secp256k1fx.TransferInput{ + // Amt: 0, + // Input: inputSigners, + // } + + // tx := tx + // tx.Ins = []*avax.TransferableInput{ + // &input, + // } + // return &txs.Tx{ + // Unsigned: &tx, + // Creds: creds, + // } + // }, + // err: secp256k1fx.ErrNoValueInput, + // }, + // { + // name: "duplicate inputs", + // txFunc: func() *txs.Tx { + // tx := tx + // tx.Ins = []*avax.TransferableInput{ + // &input, + // &input, + // } + // return &txs.Tx{ + // Unsigned: &tx, + // Creds: []*fxs.FxCredential{ + // &cred, + // &cred, + // }, + // } + // }, + // err: avax.ErrInputsNotSortedUnique, + // }, + // { + // name: "input overflow", + // txFunc: func() *txs.Tx { + // input0 := input + // input0.In = &secp256k1fx.TransferInput{ + // Amt: 1, + // Input: inputSigners, + // } + + // input1 := input + // input1.UTXOID.OutputIndex++ + // input1.In = &secp256k1fx.TransferInput{ + // Amt: math.MaxUint64, + // Input: inputSigners, + // } + + // tx := tx + // tx.Ins = []*avax.TransferableInput{ + // &input0, + // &input1, + // } + // avax.SortTransferableInputsWithSigners(baseTx.Ins, make([][]*secp256k1.PrivateKey, 2)) + // return &txs.Tx{ + // Unsigned: &tx, + // Creds: []*fxs.FxCredential{ + // &cred, + // &cred, + // }, + // } + // }, + // err: safemath.ErrOverflow, + // }, + // { + // name: "output overflow", + // txFunc: func() *txs.Tx { + // output0 := output + // output0.Out = &secp256k1fx.TransferOutput{ + // Amt: 1, + // OutputOwners: outputOwners, + // } + + // output1 := output + // output1.Out = &secp256k1fx.TransferOutput{ + // Amt: math.MaxUint64, + // OutputOwners: outputOwners, + // } + + // outputs := []*avax.TransferableOutput{ + // &output0, + // &output1, + // } + // avax.SortTransferableOutputs(outputs, codec) + + // tx := tx + // tx.Outs = outputs + // return &txs.Tx{ + // Unsigned: &tx, + // Creds: creds, + // } + // }, + // err: safemath.ErrOverflow, + // }, + // { + // name: "insufficient funds", + // txFunc: func() *txs.Tx { + // input := input + // input.In = &secp256k1fx.TransferInput{ + // Amt: 1, + // Input: inputSigners, + // } + + // tx := tx + // tx.Ins = []*avax.TransferableInput{ + // &input, + // } + // return &txs.Tx{ + // Unsigned: &tx, + // Creds: creds, + // } + // }, + // err: avax.ErrInsufficientFunds, + // }, { name: "invalid nil state", txFunc: func() *txs.Tx { @@ -965,46 +962,46 @@ func TestSyntacticVerifierCreateAssetTx(t *testing.T) { }, err: errWrongNumberOfCredentials, }, - { - name: "barely sufficient funds", - txFunc: func() *txs.Tx { - input := input - input.In = &secp256k1fx.TransferInput{ - Amt: fxOutput.Amt + feeConfig.CreateAssetTxFee, - Input: inputSigners, - } - - tx := tx - tx.Ins = []*avax.TransferableInput{ - &input, - } - return &txs.Tx{ - Unsigned: &tx, - Creds: creds, - } - }, - err: nil, - }, - { - name: "barely insufficient funds", - txFunc: func() *txs.Tx { - input := input - input.In = &secp256k1fx.TransferInput{ - Amt: fxOutput.Amt + feeConfig.CreateAssetTxFee - 1, - Input: inputSigners, - } - - tx := tx - tx.Ins = []*avax.TransferableInput{ - &input, - } - return &txs.Tx{ - Unsigned: &tx, - Creds: creds, - } - }, - err: avax.ErrInsufficientFunds, - }, + // { + // name: "barely sufficient funds", + // txFunc: func() *txs.Tx { + // input := input + // input.In = &secp256k1fx.TransferInput{ + // Amt: fxOutput.Amt + feeConfig.CreateAssetTxFee, + // Input: inputSigners, + // } + + // tx := tx + // tx.Ins = []*avax.TransferableInput{ + // &input, + // } + // return &txs.Tx{ + // Unsigned: &tx, + // Creds: creds, + // } + // }, + // err: nil, + // }, + // { + // name: "barely insufficient funds", + // txFunc: func() *txs.Tx { + // input := input + // input.In = &secp256k1fx.TransferInput{ + // Amt: fxOutput.Amt + feeConfig.CreateAssetTxFee - 1, + // Input: inputSigners, + // } + + // tx := tx + // tx.Ins = []*avax.TransferableInput{ + // &input, + // } + // return &txs.Tx{ + // Unsigned: &tx, + // Creds: creds, + // } + // }, + // err: avax.ErrInsufficientFunds, + // }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { @@ -1181,220 +1178,220 @@ func TestSyntacticVerifierOperationTx(t *testing.T) { }, err: avax.ErrMemoTooLarge, }, + // { + // name: "invalid output", + // txFunc: func() *txs.Tx { + // output := output + // output.Out = &secp256k1fx.TransferOutput{ + // Amt: 0, + // OutputOwners: outputOwners, + // } + + // tx := tx + // tx.Outs = []*avax.TransferableOutput{ + // &output, + // } + // return &txs.Tx{ + // Unsigned: &tx, + // Creds: creds, + // } + // }, + // err: secp256k1fx.ErrNoValueOutput, + // }, + // { + // name: "unsorted outputs", + // txFunc: func() *txs.Tx { + // output0 := output + // output0.Out = &secp256k1fx.TransferOutput{ + // Amt: 1, + // OutputOwners: outputOwners, + // } + + // output1 := output + // output1.Out = &secp256k1fx.TransferOutput{ + // Amt: 2, + // OutputOwners: outputOwners, + // } + + // outputs := []*avax.TransferableOutput{ + // &output0, + // &output1, + // } + // avax.SortTransferableOutputs(outputs, codec) + // outputs[0], outputs[1] = outputs[1], outputs[0] + + // tx := tx + // tx.Outs = outputs + // return &txs.Tx{ + // Unsigned: &tx, + // Creds: creds, + // } + // }, + // err: avax.ErrOutputsNotSorted, + // }, + // { + // name: "invalid input", + // txFunc: func() *txs.Tx { + // input := input + // input.In = &secp256k1fx.TransferInput{ + // Amt: 0, + // Input: inputSigners, + // } + + // tx := tx + // tx.Ins = []*avax.TransferableInput{ + // &input, + // } + // return &txs.Tx{ + // Unsigned: &tx, + // Creds: creds, + // } + // }, + // err: secp256k1fx.ErrNoValueInput, + // }, + // { + // name: "duplicate inputs", + // txFunc: func() *txs.Tx { + // tx := tx + // tx.Ins = []*avax.TransferableInput{ + // &input, + // &input, + // } + // return &txs.Tx{ + // Unsigned: &tx, + // Creds: []*fxs.FxCredential{ + // &cred, + // &cred, + // }, + // } + // }, + // err: avax.ErrInputsNotSortedUnique, + // }, + // { + // name: "input overflow", + // txFunc: func() *txs.Tx { + // input0 := input + // input0.In = &secp256k1fx.TransferInput{ + // Amt: 1, + // Input: inputSigners, + // } + + // input1 := input + // input1.UTXOID.OutputIndex++ + // input1.In = &secp256k1fx.TransferInput{ + // Amt: math.MaxUint64, + // Input: inputSigners, + // } + + // tx := tx + // tx.Ins = []*avax.TransferableInput{ + // &input0, + // &input1, + // } + // avax.SortTransferableInputsWithSigners(tx.Ins, make([][]*secp256k1.PrivateKey, 2)) + // return &txs.Tx{ + // Unsigned: &tx, + // Creds: []*fxs.FxCredential{ + // &cred, + // &cred, + // }, + // } + // }, + // err: safemath.ErrOverflow, + // }, + // { + // name: "output overflow", + // txFunc: func() *txs.Tx { + // output := output + // output.Out = &secp256k1fx.TransferOutput{ + // Amt: math.MaxUint64, + // OutputOwners: outputOwners, + // } + + // outputs := []*avax.TransferableOutput{ + // &output, + // } + // avax.SortTransferableOutputs(outputs, codec) + + // tx := tx + // tx.Outs = outputs + // return &txs.Tx{ + // Unsigned: &tx, + // Creds: creds, + // } + // }, + // err: safemath.ErrOverflow, + // }, + // { + // name: "insufficient funds", + // txFunc: func() *txs.Tx { + // input := input + // input.In = &secp256k1fx.TransferInput{ + // Amt: 1, + // Input: inputSigners, + // } + + // tx := tx + // tx.Ins = []*avax.TransferableInput{ + // &input, + // } + // return &txs.Tx{ + // Unsigned: &tx, + // Creds: creds, + // } + // }, + // err: avax.ErrInsufficientFunds, + // }, { - name: "invalid output", + name: "invalid nil op", txFunc: func() *txs.Tx { - output := output - output.Out = &secp256k1fx.TransferOutput{ - Amt: 0, - OutputOwners: outputOwners, - } - tx := tx - tx.Outs = []*avax.TransferableOutput{ - &output, + tx.Ops = []*txs.Operation{ + nil, } return &txs.Tx{ Unsigned: &tx, Creds: creds, } }, - err: secp256k1fx.ErrNoValueOutput, + err: txs.ErrNilOperation, }, { - name: "unsorted outputs", + name: "invalid nil fx op", txFunc: func() *txs.Tx { - output0 := output - output0.Out = &secp256k1fx.TransferOutput{ - Amt: 1, - OutputOwners: outputOwners, - } - - output1 := output - output1.Out = &secp256k1fx.TransferOutput{ - Amt: 2, - OutputOwners: outputOwners, - } - - outputs := []*avax.TransferableOutput{ - &output0, - &output1, - } - avax.SortTransferableOutputs(outputs, codec) - outputs[0], outputs[1] = outputs[1], outputs[0] + op := op + op.Op = nil tx := tx - tx.Outs = outputs + tx.Ops = []*txs.Operation{ + &op, + } return &txs.Tx{ Unsigned: &tx, Creds: creds, } }, - err: avax.ErrOutputsNotSorted, + err: txs.ErrNilFxOperation, }, { - name: "invalid input", + name: "invalid duplicated op UTXOs", txFunc: func() *txs.Tx { - input := input - input.In = &secp256k1fx.TransferInput{ - Amt: 0, - Input: inputSigners, + op := op + op.UTXOIDs = []*avax.UTXOID{ + &opUTXOID, + &opUTXOID, } tx := tx - tx.Ins = []*avax.TransferableInput{ - &input, + tx.Ops = []*txs.Operation{ + &op, } return &txs.Tx{ Unsigned: &tx, Creds: creds, } }, - err: secp256k1fx.ErrNoValueInput, - }, - { - name: "duplicate inputs", - txFunc: func() *txs.Tx { - tx := tx - tx.Ins = []*avax.TransferableInput{ - &input, - &input, - } - return &txs.Tx{ - Unsigned: &tx, - Creds: []*fxs.FxCredential{ - &cred, - &cred, - }, - } - }, - err: avax.ErrInputsNotSortedUnique, - }, - { - name: "input overflow", - txFunc: func() *txs.Tx { - input0 := input - input0.In = &secp256k1fx.TransferInput{ - Amt: 1, - Input: inputSigners, - } - - input1 := input - input1.UTXOID.OutputIndex++ - input1.In = &secp256k1fx.TransferInput{ - Amt: math.MaxUint64, - Input: inputSigners, - } - - tx := tx - tx.Ins = []*avax.TransferableInput{ - &input0, - &input1, - } - avax.SortTransferableInputsWithSigners(tx.Ins, make([][]*secp256k1.PrivateKey, 2)) - return &txs.Tx{ - Unsigned: &tx, - Creds: []*fxs.FxCredential{ - &cred, - &cred, - }, - } - }, - err: safemath.ErrOverflow, - }, - { - name: "output overflow", - txFunc: func() *txs.Tx { - output := output - output.Out = &secp256k1fx.TransferOutput{ - Amt: math.MaxUint64, - OutputOwners: outputOwners, - } - - outputs := []*avax.TransferableOutput{ - &output, - } - avax.SortTransferableOutputs(outputs, codec) - - tx := tx - tx.Outs = outputs - return &txs.Tx{ - Unsigned: &tx, - Creds: creds, - } - }, - err: safemath.ErrOverflow, - }, - { - name: "insufficient funds", - txFunc: func() *txs.Tx { - input := input - input.In = &secp256k1fx.TransferInput{ - Amt: 1, - Input: inputSigners, - } - - tx := tx - tx.Ins = []*avax.TransferableInput{ - &input, - } - return &txs.Tx{ - Unsigned: &tx, - Creds: creds, - } - }, - err: avax.ErrInsufficientFunds, - }, - { - name: "invalid nil op", - txFunc: func() *txs.Tx { - tx := tx - tx.Ops = []*txs.Operation{ - nil, - } - return &txs.Tx{ - Unsigned: &tx, - Creds: creds, - } - }, - err: txs.ErrNilOperation, - }, - { - name: "invalid nil fx op", - txFunc: func() *txs.Tx { - op := op - op.Op = nil - - tx := tx - tx.Ops = []*txs.Operation{ - &op, - } - return &txs.Tx{ - Unsigned: &tx, - Creds: creds, - } - }, - err: txs.ErrNilFxOperation, - }, - { - name: "invalid duplicated op UTXOs", - txFunc: func() *txs.Tx { - op := op - op.UTXOIDs = []*avax.UTXOID{ - &opUTXOID, - &opUTXOID, - } - - tx := tx - tx.Ops = []*txs.Operation{ - &op, - } - return &txs.Tx{ - Unsigned: &tx, - Creds: creds, - } - }, - err: txs.ErrNotSortedAndUniqueUTXOIDs, + err: txs.ErrNotSortedAndUniqueUTXOIDs, }, { name: "invalid duplicated UTXOs across ops", @@ -1455,46 +1452,46 @@ func TestSyntacticVerifierOperationTx(t *testing.T) { }, err: errWrongNumberOfCredentials, }, - { - name: "barely sufficient funds", - txFunc: func() *txs.Tx { - input := input - input.In = &secp256k1fx.TransferInput{ - Amt: fxOutput.Amt + feeConfig.TxFee, - Input: inputSigners, - } - - tx := tx - tx.Ins = []*avax.TransferableInput{ - &input, - } - return &txs.Tx{ - Unsigned: &tx, - Creds: creds, - } - }, - err: nil, - }, - { - name: "barely insufficient funds", - txFunc: func() *txs.Tx { - input := input - input.In = &secp256k1fx.TransferInput{ - Amt: fxOutput.Amt + feeConfig.TxFee - 1, - Input: inputSigners, - } - - tx := tx - tx.Ins = []*avax.TransferableInput{ - &input, - } - return &txs.Tx{ - Unsigned: &tx, - Creds: creds, - } - }, - err: avax.ErrInsufficientFunds, - }, + // { + // name: "barely sufficient funds", + // txFunc: func() *txs.Tx { + // input := input + // input.In = &secp256k1fx.TransferInput{ + // Amt: fxOutput.Amt + feeConfig.TxFee, + // Input: inputSigners, + // } + + // tx := tx + // tx.Ins = []*avax.TransferableInput{ + // &input, + // } + // return &txs.Tx{ + // Unsigned: &tx, + // Creds: creds, + // } + // }, + // err: nil, + // }, + // { + // name: "barely insufficient funds", + // txFunc: func() *txs.Tx { + // input := input + // input.In = &secp256k1fx.TransferInput{ + // Amt: fxOutput.Amt + feeConfig.TxFee - 1, + // Input: inputSigners, + // } + + // tx := tx + // tx.Ins = []*avax.TransferableInput{ + // &input, + // } + // return &txs.Tx{ + // Unsigned: &tx, + // Creds: creds, + // } + // }, + // err: avax.ErrInsufficientFunds, + // }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { @@ -1652,189 +1649,189 @@ func TestSyntacticVerifierImportTx(t *testing.T) { }, err: avax.ErrMemoTooLarge, }, - { - name: "invalid output", - txFunc: func() *txs.Tx { - output := output - output.Out = &secp256k1fx.TransferOutput{ - Amt: 0, - OutputOwners: outputOwners, - } - - tx := tx - tx.Outs = []*avax.TransferableOutput{ - &output, - } - return &txs.Tx{ - Unsigned: &tx, - Creds: creds, - } - }, - err: secp256k1fx.ErrNoValueOutput, - }, - { - name: "unsorted outputs", - txFunc: func() *txs.Tx { - output0 := output - output0.Out = &secp256k1fx.TransferOutput{ - Amt: 1, - OutputOwners: outputOwners, - } - - output1 := output - output1.Out = &secp256k1fx.TransferOutput{ - Amt: 2, - OutputOwners: outputOwners, - } - - outputs := []*avax.TransferableOutput{ - &output0, - &output1, - } - avax.SortTransferableOutputs(outputs, codec) - outputs[0], outputs[1] = outputs[1], outputs[0] - - tx := tx - tx.Outs = outputs - return &txs.Tx{ - Unsigned: &tx, - Creds: creds, - } - }, - err: avax.ErrOutputsNotSorted, - }, - { - name: "invalid input", - txFunc: func() *txs.Tx { - input := input - input.In = &secp256k1fx.TransferInput{ - Amt: 0, - Input: inputSigners, - } - - tx := tx - tx.Ins = []*avax.TransferableInput{ - &input, - } - return &txs.Tx{ - Unsigned: &tx, - Creds: creds, - } - }, - err: secp256k1fx.ErrNoValueInput, - }, - { - name: "duplicate inputs", - txFunc: func() *txs.Tx { - tx := tx - tx.Ins = []*avax.TransferableInput{ - &input, - &input, - } - return &txs.Tx{ - Unsigned: &tx, - Creds: []*fxs.FxCredential{ - &cred, - &cred, - &cred, - }, - } - }, - err: avax.ErrInputsNotSortedUnique, - }, - { - name: "duplicate imported inputs", - txFunc: func() *txs.Tx { - tx := tx - tx.ImportedIns = []*avax.TransferableInput{ - &input, - &input, - } - return &txs.Tx{ - Unsigned: &tx, - Creds: []*fxs.FxCredential{ - &cred, - &cred, - }, - } - }, - err: avax.ErrInputsNotSortedUnique, - }, - { - name: "input overflow", - txFunc: func() *txs.Tx { - input0 := input - input0.In = &secp256k1fx.TransferInput{ - Amt: 1, - Input: inputSigners, - } - - input1 := input - input1.UTXOID.OutputIndex++ - input1.In = &secp256k1fx.TransferInput{ - Amt: math.MaxUint64, - Input: inputSigners, - } - - tx := tx - tx.Ins = []*avax.TransferableInput{ - &input0, - &input1, - } - avax.SortTransferableInputsWithSigners(tx.Ins, make([][]*secp256k1.PrivateKey, 2)) - return &txs.Tx{ - Unsigned: &tx, - Creds: []*fxs.FxCredential{ - &cred, - &cred, - }, - } - }, - err: safemath.ErrOverflow, - }, - { - name: "output overflow", - txFunc: func() *txs.Tx { - output := output - output.Out = &secp256k1fx.TransferOutput{ - Amt: math.MaxUint64, - OutputOwners: outputOwners, - } - - outputs := []*avax.TransferableOutput{ - &output, - } - avax.SortTransferableOutputs(outputs, codec) - - tx := tx - tx.Outs = outputs - return &txs.Tx{ - Unsigned: &tx, - Creds: creds, - } - }, - err: safemath.ErrOverflow, - }, - { - name: "insufficient funds", - txFunc: func() *txs.Tx { - input := input - input.In = &secp256k1fx.TransferInput{ - Amt: 1, - Input: inputSigners, - } - - tx := tx - tx.ImportedIns = []*avax.TransferableInput{ - &input, - } - return &txs.Tx{ - Unsigned: &tx, - Creds: creds, - } - }, - err: avax.ErrInsufficientFunds, - }, + // { + // name: "invalid output", + // txFunc: func() *txs.Tx { + // output := output + // output.Out = &secp256k1fx.TransferOutput{ + // Amt: 0, + // OutputOwners: outputOwners, + // } + + // tx := tx + // tx.Outs = []*avax.TransferableOutput{ + // &output, + // } + // return &txs.Tx{ + // Unsigned: &tx, + // Creds: creds, + // } + // }, + // err: secp256k1fx.ErrNoValueOutput, + // }, + // { + // name: "unsorted outputs", + // txFunc: func() *txs.Tx { + // output0 := output + // output0.Out = &secp256k1fx.TransferOutput{ + // Amt: 1, + // OutputOwners: outputOwners, + // } + + // output1 := output + // output1.Out = &secp256k1fx.TransferOutput{ + // Amt: 2, + // OutputOwners: outputOwners, + // } + + // outputs := []*avax.TransferableOutput{ + // &output0, + // &output1, + // } + // avax.SortTransferableOutputs(outputs, codec) + // outputs[0], outputs[1] = outputs[1], outputs[0] + + // tx := tx + // tx.Outs = outputs + // return &txs.Tx{ + // Unsigned: &tx, + // Creds: creds, + // } + // }, + // err: avax.ErrOutputsNotSorted, + // }, + // { + // name: "invalid input", + // txFunc: func() *txs.Tx { + // input := input + // input.In = &secp256k1fx.TransferInput{ + // Amt: 0, + // Input: inputSigners, + // } + + // tx := tx + // tx.Ins = []*avax.TransferableInput{ + // &input, + // } + // return &txs.Tx{ + // Unsigned: &tx, + // Creds: creds, + // } + // }, + // err: secp256k1fx.ErrNoValueInput, + // }, + // { + // name: "duplicate inputs", + // txFunc: func() *txs.Tx { + // tx := tx + // tx.Ins = []*avax.TransferableInput{ + // &input, + // &input, + // } + // return &txs.Tx{ + // Unsigned: &tx, + // Creds: []*fxs.FxCredential{ + // &cred, + // &cred, + // &cred, + // }, + // } + // }, + // err: avax.ErrInputsNotSortedUnique, + // }, + // { + // name: "duplicate imported inputs", + // txFunc: func() *txs.Tx { + // tx := tx + // tx.ImportedIns = []*avax.TransferableInput{ + // &input, + // &input, + // } + // return &txs.Tx{ + // Unsigned: &tx, + // Creds: []*fxs.FxCredential{ + // &cred, + // &cred, + // }, + // } + // }, + // err: avax.ErrInputsNotSortedUnique, + // }, + // { + // name: "input overflow", + // txFunc: func() *txs.Tx { + // input0 := input + // input0.In = &secp256k1fx.TransferInput{ + // Amt: 1, + // Input: inputSigners, + // } + + // input1 := input + // input1.UTXOID.OutputIndex++ + // input1.In = &secp256k1fx.TransferInput{ + // Amt: math.MaxUint64, + // Input: inputSigners, + // } + + // tx := tx + // tx.Ins = []*avax.TransferableInput{ + // &input0, + // &input1, + // } + // avax.SortTransferableInputsWithSigners(tx.Ins, make([][]*secp256k1.PrivateKey, 2)) + // return &txs.Tx{ + // Unsigned: &tx, + // Creds: []*fxs.FxCredential{ + // &cred, + // &cred, + // }, + // } + // }, + // err: safemath.ErrOverflow, + // }, + // { + // name: "output overflow", + // txFunc: func() *txs.Tx { + // output := output + // output.Out = &secp256k1fx.TransferOutput{ + // Amt: math.MaxUint64, + // OutputOwners: outputOwners, + // } + + // outputs := []*avax.TransferableOutput{ + // &output, + // } + // avax.SortTransferableOutputs(outputs, codec) + + // tx := tx + // tx.Outs = outputs + // return &txs.Tx{ + // Unsigned: &tx, + // Creds: creds, + // } + // }, + // err: safemath.ErrOverflow, + // }, + // { + // name: "insufficient funds", + // txFunc: func() *txs.Tx { + // input := input + // input.In = &secp256k1fx.TransferInput{ + // Amt: 1, + // Input: inputSigners, + // } + + // tx := tx + // tx.ImportedIns = []*avax.TransferableInput{ + // &input, + // } + // return &txs.Tx{ + // Unsigned: &tx, + // Creds: creds, + // } + // }, + // err: avax.ErrInsufficientFunds, + // }, { name: "invalid credential", txFunc: func() *txs.Tx { @@ -1856,46 +1853,46 @@ func TestSyntacticVerifierImportTx(t *testing.T) { }, err: errWrongNumberOfCredentials, }, - { - name: "barely sufficient funds", - txFunc: func() *txs.Tx { - input := input - input.In = &secp256k1fx.TransferInput{ - Amt: fxOutput.Amt + feeConfig.TxFee, - Input: inputSigners, - } - - tx := tx - tx.ImportedIns = []*avax.TransferableInput{ - &input, - } - return &txs.Tx{ - Unsigned: &tx, - Creds: creds, - } - }, - err: nil, - }, - { - name: "barely insufficient funds", - txFunc: func() *txs.Tx { - input := input - input.In = &secp256k1fx.TransferInput{ - Amt: fxOutput.Amt + feeConfig.TxFee - 1, - Input: inputSigners, - } - - tx := tx - tx.ImportedIns = []*avax.TransferableInput{ - &input, - } - return &txs.Tx{ - Unsigned: &tx, - Creds: creds, - } - }, - err: avax.ErrInsufficientFunds, - }, + // { + // name: "barely sufficient funds", + // txFunc: func() *txs.Tx { + // input := input + // input.In = &secp256k1fx.TransferInput{ + // Amt: fxOutput.Amt + feeConfig.TxFee, + // Input: inputSigners, + // } + + // tx := tx + // tx.ImportedIns = []*avax.TransferableInput{ + // &input, + // } + // return &txs.Tx{ + // Unsigned: &tx, + // Creds: creds, + // } + // }, + // err: nil, + // }, + // { + // name: "barely insufficient funds", + // txFunc: func() *txs.Tx { + // input := input + // input.In = &secp256k1fx.TransferInput{ + // Amt: fxOutput.Amt + feeConfig.TxFee - 1, + // Input: inputSigners, + // } + + // tx := tx + // tx.ImportedIns = []*avax.TransferableInput{ + // &input, + // } + // return &txs.Tx{ + // Unsigned: &tx, + // Creds: creds, + // } + // }, + // err: avax.ErrInsufficientFunds, + // }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { @@ -2053,201 +2050,201 @@ func TestSyntacticVerifierExportTx(t *testing.T) { }, err: avax.ErrMemoTooLarge, }, - { - name: "invalid output", - txFunc: func() *txs.Tx { - output := output - output.Out = &secp256k1fx.TransferOutput{ - Amt: 0, - OutputOwners: outputOwners, - } - - tx := tx - tx.Outs = []*avax.TransferableOutput{ - &output, - } - return &txs.Tx{ - Unsigned: &tx, - Creds: creds, - } - }, - err: secp256k1fx.ErrNoValueOutput, - }, - { - name: "unsorted outputs", - txFunc: func() *txs.Tx { - output0 := output - output0.Out = &secp256k1fx.TransferOutput{ - Amt: 1, - OutputOwners: outputOwners, - } - - output1 := output - output1.Out = &secp256k1fx.TransferOutput{ - Amt: 2, - OutputOwners: outputOwners, - } - - outputs := []*avax.TransferableOutput{ - &output0, - &output1, - } - avax.SortTransferableOutputs(outputs, codec) - outputs[0], outputs[1] = outputs[1], outputs[0] - - tx := tx - tx.Outs = outputs - return &txs.Tx{ - Unsigned: &tx, - Creds: creds, - } - }, - err: avax.ErrOutputsNotSorted, - }, - { - name: "unsorted exported outputs", - txFunc: func() *txs.Tx { - output0 := output - output0.Out = &secp256k1fx.TransferOutput{ - Amt: 1, - OutputOwners: outputOwners, - } - - output1 := output - output1.Out = &secp256k1fx.TransferOutput{ - Amt: 2, - OutputOwners: outputOwners, - } - - outputs := []*avax.TransferableOutput{ - &output0, - &output1, - } - avax.SortTransferableOutputs(outputs, codec) - outputs[0], outputs[1] = outputs[1], outputs[0] - - tx := tx - tx.ExportedOuts = outputs - return &txs.Tx{ - Unsigned: &tx, - Creds: creds, - } - }, - err: avax.ErrOutputsNotSorted, - }, - { - name: "invalid input", - txFunc: func() *txs.Tx { - input := input - input.In = &secp256k1fx.TransferInput{ - Amt: 0, - Input: inputSigners, - } - - tx := tx - tx.Ins = []*avax.TransferableInput{ - &input, - } - return &txs.Tx{ - Unsigned: &tx, - Creds: creds, - } - }, - err: secp256k1fx.ErrNoValueInput, - }, - { - name: "duplicate inputs", - txFunc: func() *txs.Tx { - tx := tx - tx.Ins = []*avax.TransferableInput{ - &input, - &input, - } - return &txs.Tx{ - Unsigned: &tx, - Creds: []*fxs.FxCredential{ - &cred, - &cred, - }, - } - }, - err: avax.ErrInputsNotSortedUnique, - }, - { - name: "input overflow", - txFunc: func() *txs.Tx { - input0 := input - input0.In = &secp256k1fx.TransferInput{ - Amt: 1, - Input: inputSigners, - } - - input1 := input - input1.UTXOID.OutputIndex++ - input1.In = &secp256k1fx.TransferInput{ - Amt: math.MaxUint64, - Input: inputSigners, - } - - tx := tx - tx.Ins = []*avax.TransferableInput{ - &input0, - &input1, - } - avax.SortTransferableInputsWithSigners(tx.Ins, make([][]*secp256k1.PrivateKey, 2)) - return &txs.Tx{ - Unsigned: &tx, - Creds: []*fxs.FxCredential{ - &cred, - &cred, - }, - } - }, - err: safemath.ErrOverflow, - }, - { - name: "output overflow", - txFunc: func() *txs.Tx { - output := output - output.Out = &secp256k1fx.TransferOutput{ - Amt: math.MaxUint64, - OutputOwners: outputOwners, - } - - outputs := []*avax.TransferableOutput{ - &output, - } - avax.SortTransferableOutputs(outputs, codec) - - tx := tx - tx.Outs = outputs - return &txs.Tx{ - Unsigned: &tx, - Creds: creds, - } - }, - err: safemath.ErrOverflow, - }, - { - name: "insufficient funds", - txFunc: func() *txs.Tx { - input := input - input.In = &secp256k1fx.TransferInput{ - Amt: 1, - Input: inputSigners, - } - - tx := tx - tx.Ins = []*avax.TransferableInput{ - &input, - } - return &txs.Tx{ - Unsigned: &tx, - Creds: creds, - } - }, - err: avax.ErrInsufficientFunds, - }, + // { + // name: "invalid output", + // txFunc: func() *txs.Tx { + // output := output + // output.Out = &secp256k1fx.TransferOutput{ + // Amt: 0, + // OutputOwners: outputOwners, + // } + + // tx := tx + // tx.Outs = []*avax.TransferableOutput{ + // &output, + // } + // return &txs.Tx{ + // Unsigned: &tx, + // Creds: creds, + // } + // }, + // err: secp256k1fx.ErrNoValueOutput, + // }, + // { + // name: "unsorted outputs", + // txFunc: func() *txs.Tx { + // output0 := output + // output0.Out = &secp256k1fx.TransferOutput{ + // Amt: 1, + // OutputOwners: outputOwners, + // } + + // output1 := output + // output1.Out = &secp256k1fx.TransferOutput{ + // Amt: 2, + // OutputOwners: outputOwners, + // } + + // outputs := []*avax.TransferableOutput{ + // &output0, + // &output1, + // } + // avax.SortTransferableOutputs(outputs, codec) + // outputs[0], outputs[1] = outputs[1], outputs[0] + + // tx := tx + // tx.Outs = outputs + // return &txs.Tx{ + // Unsigned: &tx, + // Creds: creds, + // } + // }, + // err: avax.ErrOutputsNotSorted, + // }, + // { + // name: "unsorted exported outputs", + // txFunc: func() *txs.Tx { + // output0 := output + // output0.Out = &secp256k1fx.TransferOutput{ + // Amt: 1, + // OutputOwners: outputOwners, + // } + + // output1 := output + // output1.Out = &secp256k1fx.TransferOutput{ + // Amt: 2, + // OutputOwners: outputOwners, + // } + + // outputs := []*avax.TransferableOutput{ + // &output0, + // &output1, + // } + // avax.SortTransferableOutputs(outputs, codec) + // outputs[0], outputs[1] = outputs[1], outputs[0] + + // tx := tx + // tx.ExportedOuts = outputs + // return &txs.Tx{ + // Unsigned: &tx, + // Creds: creds, + // } + // }, + // err: avax.ErrOutputsNotSorted, + // }, + // { + // name: "invalid input", + // txFunc: func() *txs.Tx { + // input := input + // input.In = &secp256k1fx.TransferInput{ + // Amt: 0, + // Input: inputSigners, + // } + + // tx := tx + // tx.Ins = []*avax.TransferableInput{ + // &input, + // } + // return &txs.Tx{ + // Unsigned: &tx, + // Creds: creds, + // } + // }, + // err: secp256k1fx.ErrNoValueInput, + // }, + // { + // name: "duplicate inputs", + // txFunc: func() *txs.Tx { + // tx := tx + // tx.Ins = []*avax.TransferableInput{ + // &input, + // &input, + // } + // return &txs.Tx{ + // Unsigned: &tx, + // Creds: []*fxs.FxCredential{ + // &cred, + // &cred, + // }, + // } + // }, + // err: avax.ErrInputsNotSortedUnique, + // }, + // { + // name: "input overflow", + // txFunc: func() *txs.Tx { + // input0 := input + // input0.In = &secp256k1fx.TransferInput{ + // Amt: 1, + // Input: inputSigners, + // } + + // input1 := input + // input1.UTXOID.OutputIndex++ + // input1.In = &secp256k1fx.TransferInput{ + // Amt: math.MaxUint64, + // Input: inputSigners, + // } + + // tx := tx + // tx.Ins = []*avax.TransferableInput{ + // &input0, + // &input1, + // } + // avax.SortTransferableInputsWithSigners(tx.Ins, make([][]*secp256k1.PrivateKey, 2)) + // return &txs.Tx{ + // Unsigned: &tx, + // Creds: []*fxs.FxCredential{ + // &cred, + // &cred, + // }, + // } + // }, + // err: safemath.ErrOverflow, + // }, + // { + // name: "output overflow", + // txFunc: func() *txs.Tx { + // output := output + // output.Out = &secp256k1fx.TransferOutput{ + // Amt: math.MaxUint64, + // OutputOwners: outputOwners, + // } + + // outputs := []*avax.TransferableOutput{ + // &output, + // } + // avax.SortTransferableOutputs(outputs, codec) + + // tx := tx + // tx.Outs = outputs + // return &txs.Tx{ + // Unsigned: &tx, + // Creds: creds, + // } + // }, + // err: safemath.ErrOverflow, + // }, + // { + // name: "insufficient funds", + // txFunc: func() *txs.Tx { + // input := input + // input.In = &secp256k1fx.TransferInput{ + // Amt: 1, + // Input: inputSigners, + // } + + // tx := tx + // tx.Ins = []*avax.TransferableInput{ + // &input, + // } + // return &txs.Tx{ + // Unsigned: &tx, + // Creds: creds, + // } + // }, + // err: avax.ErrInsufficientFunds, + // }, { name: "invalid credential", txFunc: func() *txs.Tx { @@ -2269,46 +2266,46 @@ func TestSyntacticVerifierExportTx(t *testing.T) { }, err: errWrongNumberOfCredentials, }, - { - name: "barely sufficient funds", - txFunc: func() *txs.Tx { - input := input - input.In = &secp256k1fx.TransferInput{ - Amt: fxOutput.Amt + feeConfig.TxFee, - Input: inputSigners, - } - - tx := tx - tx.Ins = []*avax.TransferableInput{ - &input, - } - return &txs.Tx{ - Unsigned: &tx, - Creds: creds, - } - }, - err: nil, - }, - { - name: "barely insufficient funds", - txFunc: func() *txs.Tx { - input := input - input.In = &secp256k1fx.TransferInput{ - Amt: fxOutput.Amt + feeConfig.TxFee - 1, - Input: inputSigners, - } - - tx := tx - tx.Ins = []*avax.TransferableInput{ - &input, - } - return &txs.Tx{ - Unsigned: &tx, - Creds: creds, - } - }, - err: avax.ErrInsufficientFunds, - }, + // { + // name: "barely sufficient funds", + // txFunc: func() *txs.Tx { + // input := input + // input.In = &secp256k1fx.TransferInput{ + // Amt: fxOutput.Amt + feeConfig.TxFee, + // Input: inputSigners, + // } + + // tx := tx + // tx.Ins = []*avax.TransferableInput{ + // &input, + // } + // return &txs.Tx{ + // Unsigned: &tx, + // Creds: creds, + // } + // }, + // err: nil, + // }, + // { + // name: "barely insufficient funds", + // txFunc: func() *txs.Tx { + // input := input + // input.In = &secp256k1fx.TransferInput{ + // Amt: fxOutput.Amt + feeConfig.TxFee - 1, + // Input: inputSigners, + // } + + // tx := tx + // tx.Ins = []*avax.TransferableInput{ + // &input, + // } + // return &txs.Tx{ + // Unsigned: &tx, + // Creds: creds, + // } + // }, + // err: avax.ErrInsufficientFunds, + // }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { diff --git a/vms/avm/txs/fees/calculator.go b/vms/avm/txs/fees/calculator.go new file mode 100644 index 00000000000..5bcf9d77099 --- /dev/null +++ b/vms/avm/txs/fees/calculator.go @@ -0,0 +1,44 @@ +// 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/vms/avm/config" + "github.com/ava-labs/avalanchego/vms/avm/txs" +) + +var _ txs.Visitor = (*Calculator)(nil) + +type Calculator struct { + // Pre E-fork inputs + Config *config.Config + + // outputs of visitor execution + Fee uint64 +} + +func (fc *Calculator) BaseTx(*txs.BaseTx) error { + fc.Fee = fc.Config.TxFee + return nil +} + +func (fc *Calculator) CreateAssetTx(*txs.CreateAssetTx) error { + fc.Fee = fc.Config.CreateAssetTxFee + return nil +} + +func (fc *Calculator) OperationTx(*txs.OperationTx) error { + fc.Fee = fc.Config.TxFee + return nil +} + +func (fc *Calculator) ImportTx(*txs.ImportTx) error { + fc.Fee = fc.Config.TxFee + return nil +} + +func (fc *Calculator) ExportTx(*txs.ExportTx) error { + fc.Fee = fc.Config.TxFee + return nil +} From 0318ea81545cf63a7e47aacbb50f5777b5eb3c62 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Fri, 2 Feb 2024 12:36:02 +0100 Subject: [PATCH 06/27] wip:fixing UTs --- vms/avm/block/builder/builder_test.go | 4 + .../txs/executor/semantic_verifier_test.go | 1493 ++++++++++++++--- .../txs/executor/syntactic_verifier_test.go | 1022 +---------- 3 files changed, 1304 insertions(+), 1215 deletions(-) diff --git a/vms/avm/block/builder/builder_test.go b/vms/avm/block/builder/builder_test.go index 185c93260ec..091413c057e 100644 --- a/vms/avm/block/builder/builder_test.go +++ b/vms/avm/block/builder/builder_test.go @@ -27,6 +27,7 @@ import ( "github.com/ava-labs/avalanchego/utils/logging" "github.com/ava-labs/avalanchego/utils/timer/mockable" "github.com/ava-labs/avalanchego/vms/avm/block" + "github.com/ava-labs/avalanchego/vms/avm/config" "github.com/ava-labs/avalanchego/vms/avm/fxs" "github.com/ava-labs/avalanchego/vms/avm/metrics" "github.com/ava-labs/avalanchego/vms/avm/state" @@ -526,6 +527,9 @@ func TestBlockBuilderAddLocalTx(t *testing.T) { Ctx: &snow.Context{ Log: logging.NoLog{}, }, + Config: &config.Config{ + EUpgradeTime: mockable.MaxTime, + }, Codec: parser.Codec(), } diff --git a/vms/avm/txs/executor/semantic_verifier_test.go b/vms/avm/txs/executor/semantic_verifier_test.go index 6579e29784d..98b28ac5ea5 100644 --- a/vms/avm/txs/executor/semantic_verifier_test.go +++ b/vms/avm/txs/executor/semantic_verifier_test.go @@ -4,6 +4,7 @@ package executor import ( + "math" "reflect" "testing" "time" @@ -29,55 +30,87 @@ import ( "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/components/verify" "github.com/ava-labs/avalanchego/vms/secp256k1fx" + + safemath "github.com/ava-labs/avalanchego/utils/math" ) func TestSemanticVerifierBaseTx(t *testing.T) { ctx := snowtest.Context(t, snowtest.XChainID) - typeToFxIndex := make(map[reflect.Type]int) - secpFx := &secp256k1fx.Fx{} - parser, err := txs.NewCustomParser( - time.Time{}, - typeToFxIndex, - new(mockable.Clock), - logging.NoWarn{}, - []fxs.Fx{ - secpFx, - }, - ) - require.NoError(t, err) - - codec := parser.Codec() - txID := ids.GenerateTestID() + // UTXO to be spent + inputTxID := ids.GenerateTestID() utxoID := avax.UTXOID{ - TxID: txID, - OutputIndex: 2, + TxID: inputTxID, + OutputIndex: 0, } + + feeAssetID := ids.GenerateTestID() asset := avax.Asset{ - ID: ids.GenerateTestID(), + ID: feeAssetID, } - inputSigner := secp256k1fx.Input{ - SigIndices: []uint32{ - 0, - }, + outputOwners := secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{keys[0].PublicKey().Address()}, + } + utxoAmount := 100 + feeConfig.TxFee + 50 + utxoOut := secp256k1fx.TransferOutput{ + Amt: utxoAmount, + OutputOwners: outputOwners, + } + utxo := avax.UTXO{ + UTXOID: utxoID, + Asset: asset, + Out: &utxoOut, + } + + // Input spending the UTXO + inputSigners := secp256k1fx.Input{ + SigIndices: []uint32{0}, } fxInput := secp256k1fx.TransferInput{ - Amt: 12345, - Input: inputSigner, + Amt: utxoAmount, + Input: inputSigners, } input := avax.TransferableInput{ UTXOID: utxoID, Asset: asset, In: &fxInput, } - baseTx := txs.BaseTx{ - BaseTx: avax.BaseTx{ - Ins: []*avax.TransferableInput{ - &input, - }, + + // Output produced by BaseTx + fxOutput := secp256k1fx.TransferOutput{ + Amt: 100, + OutputOwners: outputOwners, + } + output := avax.TransferableOutput{ + Asset: asset, + Out: &fxOutput, + } + + // BaseTx + baseTx := avax.BaseTx{ + Outs: []*avax.TransferableOutput{ + &output, + }, + Ins: []*avax.TransferableInput{ + &input, }, } + // Backend + typeToFxIndex := make(map[reflect.Type]int) + secpFx := &secp256k1fx.Fx{} + parser, err := txs.NewCustomParser( + time.Time{}, + typeToFxIndex, + new(mockable.Clock), + logging.NoWarn{}, + []fxs.Fx{ + secpFx, + }, + ) + require.NoError(t, err) + codec := parser.Codec() backend := &Backend{ Ctx: ctx, Config: &feeConfig, @@ -89,26 +122,11 @@ func TestSemanticVerifierBaseTx(t *testing.T) { }, TypeToFxIndex: typeToFxIndex, Codec: codec, - FeeAssetID: ids.GenerateTestID(), + FeeAssetID: feeAssetID, Bootstrapped: true, } require.NoError(t, secpFx.Bootstrapped()) - outputOwners := secp256k1fx.OutputOwners{ - Threshold: 1, - Addrs: []ids.ShortID{ - keys[0].Address(), - }, - } - output := secp256k1fx.TransferOutput{ - Amt: 12345, - OutputOwners: outputOwners, - } - utxo := avax.UTXO{ - UTXOID: utxoID, - Asset: asset, - Out: &output, - } unsignedCreateAssetTx := txs.CreateAssetTx{ States: []*txs.InitialState{{ FxIndex: 0, @@ -130,13 +148,15 @@ func TestSemanticVerifierBaseTx(t *testing.T) { state := state.NewMockChain(ctrl) state.EXPECT().GetUTXO(utxoID.InputID()).Return(&utxo, nil) - state.EXPECT().GetTx(asset.ID).Return(&createAssetTx, nil) + state.EXPECT().GetTx(asset.ID).Return(&createAssetTx, nil).Times(2) return state }, txFunc: func(require *require.Assertions) *txs.Tx { tx := &txs.Tx{ - Unsigned: &baseTx, + Unsigned: &txs.BaseTx{ + BaseTx: baseTx, + }, } require.NoError(tx.SignSECP256K1Fx( codec, @@ -149,21 +169,90 @@ func TestSemanticVerifierBaseTx(t *testing.T) { err: nil, }, { - name: "assetID mismatch", + name: "invalid output", stateFunc: func(ctrl *gomock.Controller) state.Chain { - state := state.NewMockChain(ctrl) + return nil + }, + txFunc: func(require *require.Assertions) *txs.Tx { + output := output + output.Out = &secp256k1fx.TransferOutput{ + Amt: 0, + OutputOwners: outputOwners, + } - utxo := utxo - utxo.Asset.ID = ids.GenerateTestID() + baseTx := baseTx + baseTx.Outs = []*avax.TransferableOutput{ + &output, + } - state.EXPECT().GetUTXO(utxoID.InputID()).Return(&utxo, nil) + tx := &txs.Tx{Unsigned: &txs.BaseTx{BaseTx: baseTx}} + require.NoError(tx.SignSECP256K1Fx( + codec, + [][]*secp256k1.PrivateKey{ + {keys[0]}, + }, + )) + return tx + }, + err: secp256k1fx.ErrNoValueOutput, + }, + { + name: "unsorted outputs", + stateFunc: func(ctrl *gomock.Controller) state.Chain { + return nil + }, + txFunc: func(require *require.Assertions) *txs.Tx { + output0 := output + output0.Out = &secp256k1fx.TransferOutput{ + Amt: 1, + OutputOwners: outputOwners, + } - return state + output1 := output + output1.Out = &secp256k1fx.TransferOutput{ + Amt: 2, + OutputOwners: outputOwners, + } + + outputs := []*avax.TransferableOutput{ + &output0, + &output1, + } + avax.SortTransferableOutputs(outputs, codec) + outputs[0], outputs[1] = outputs[1], outputs[0] + + baseTx := baseTx + baseTx.Outs = outputs + + tx := &txs.Tx{Unsigned: &txs.BaseTx{BaseTx: baseTx}} + require.NoError(tx.SignSECP256K1Fx( + codec, + [][]*secp256k1.PrivateKey{ + {keys[0]}, + }, + )) + return tx + }, + err: avax.ErrOutputsNotSorted, + }, + { + name: "invalid input", + stateFunc: func(ctrl *gomock.Controller) state.Chain { + return nil }, txFunc: func(require *require.Assertions) *txs.Tx { - tx := &txs.Tx{ - Unsigned: &baseTx, + input := input + input.In = &secp256k1fx.TransferInput{ + Amt: 0, + Input: inputSigners, + } + + baseTx := baseTx + baseTx.Ins = []*avax.TransferableInput{ + &input, } + + tx := &txs.Tx{Unsigned: &txs.BaseTx{BaseTx: baseTx}} require.NoError(tx.SignSECP256K1Fx( codec, [][]*secp256k1.PrivateKey{ @@ -172,29 +261,97 @@ func TestSemanticVerifierBaseTx(t *testing.T) { )) return tx }, - err: errAssetIDMismatch, + err: secp256k1fx.ErrNoValueInput, }, { - name: "not allowed input feature extension", + name: "duplicate inputs", stateFunc: func(ctrl *gomock.Controller) state.Chain { - state := state.NewMockChain(ctrl) + return nil + }, + txFunc: func(require *require.Assertions) *txs.Tx { + baseTx := baseTx + baseTx.Ins = []*avax.TransferableInput{ + &input, + &input, + } - unsignedCreateAssetTx := unsignedCreateAssetTx - unsignedCreateAssetTx.States = nil + tx := &txs.Tx{Unsigned: &txs.BaseTx{BaseTx: baseTx}} + require.NoError(tx.SignSECP256K1Fx( + codec, + [][]*secp256k1.PrivateKey{ + {keys[0]}, + {keys[0]}, + }, + )) + return tx + }, + err: avax.ErrInputsNotSortedUnique, + }, + { + name: "input overflow", + stateFunc: func(ctrl *gomock.Controller) state.Chain { + return nil + }, + txFunc: func(require *require.Assertions) *txs.Tx { + input0 := input + input0.In = &secp256k1fx.TransferInput{ + Amt: 1, + Input: inputSigners, + } - createAssetTx := txs.Tx{ - Unsigned: &unsignedCreateAssetTx, + input1 := input + input1.UTXOID.OutputIndex++ + input1.In = &secp256k1fx.TransferInput{ + Amt: math.MaxUint64, + Input: inputSigners, } - state.EXPECT().GetUTXO(utxoID.InputID()).Return(&utxo, nil) - state.EXPECT().GetTx(asset.ID).Return(&createAssetTx, nil) + baseTx := baseTx + baseTx.Ins = []*avax.TransferableInput{ + &input0, + &input1, + } + avax.SortTransferableInputsWithSigners(baseTx.Ins, make([][]*secp256k1.PrivateKey, 2)) - return state + tx := &txs.Tx{Unsigned: &txs.BaseTx{BaseTx: baseTx}} + require.NoError(tx.SignSECP256K1Fx( + codec, + [][]*secp256k1.PrivateKey{ + {keys[0]}, + }, + )) + return tx + }, + err: safemath.ErrOverflow, + }, + { + name: "output overflow", + stateFunc: func(ctrl *gomock.Controller) state.Chain { + return nil }, txFunc: func(require *require.Assertions) *txs.Tx { - tx := &txs.Tx{ - Unsigned: &baseTx, + output0 := output + output0.Out = &secp256k1fx.TransferOutput{ + Amt: 1, + OutputOwners: outputOwners, + } + + output1 := output + output1.Out = &secp256k1fx.TransferOutput{ + Amt: math.MaxUint64, + OutputOwners: outputOwners, + } + + outputs := []*avax.TransferableOutput{ + &output0, + &output1, } + avax.SortTransferableOutputs(outputs, codec) + + baseTx := baseTx + baseTx.Outs = outputs + + tx := &txs.Tx{Unsigned: &txs.BaseTx{BaseTx: baseTx}} require.NoError(tx.SignSECP256K1Fx( codec, [][]*secp256k1.PrivateKey{ @@ -203,45 +360,98 @@ func TestSemanticVerifierBaseTx(t *testing.T) { )) return tx }, - err: errIncompatibleFx, + err: safemath.ErrOverflow, }, { - name: "invalid signature", + name: "barely sufficient funds", stateFunc: func(ctrl *gomock.Controller) state.Chain { state := state.NewMockChain(ctrl) + utxoAmount := 100 + feeConfig.TxFee + utxoOut := secp256k1fx.TransferOutput{ + Amt: utxoAmount, + OutputOwners: outputOwners, + } + utxo := avax.UTXO{ + UTXOID: utxoID, + Asset: asset, + Out: &utxoOut, + } + state.EXPECT().GetUTXO(utxoID.InputID()).Return(&utxo, nil) - state.EXPECT().GetTx(asset.ID).Return(&createAssetTx, nil) + state.EXPECT().GetTx(asset.ID).Return(&createAssetTx, nil).Times(2) return state }, txFunc: func(require *require.Assertions) *txs.Tx { - tx := &txs.Tx{ - Unsigned: &baseTx, + input := input + input.In = &secp256k1fx.TransferInput{ + Amt: fxOutput.Amt + feeConfig.TxFee, + Input: inputSigners, + } + + baseTx := baseTx + baseTx.Ins = []*avax.TransferableInput{ + &input, } + + tx := &txs.Tx{Unsigned: &txs.BaseTx{BaseTx: baseTx}} require.NoError(tx.SignSECP256K1Fx( codec, [][]*secp256k1.PrivateKey{ - {keys[1]}, + {keys[0]}, }, )) return tx }, - err: secp256k1fx.ErrWrongSig, + err: nil, }, { - name: "missing UTXO", + name: "insufficient funds", stateFunc: func(ctrl *gomock.Controller) state.Chain { - state := state.NewMockChain(ctrl) + return nil + }, + txFunc: func(require *require.Assertions) *txs.Tx { + input := input + input.In = &secp256k1fx.TransferInput{ + Amt: 1, + Input: inputSigners, + } - state.EXPECT().GetUTXO(utxoID.InputID()).Return(nil, database.ErrNotFound) + baseTx := baseTx + baseTx.Ins = []*avax.TransferableInput{ + &input, + } - return state + tx := &txs.Tx{Unsigned: &txs.BaseTx{BaseTx: baseTx}} + require.NoError(tx.SignSECP256K1Fx( + codec, + [][]*secp256k1.PrivateKey{ + {keys[0]}, + }, + )) + return tx + }, + err: avax.ErrInsufficientFunds, + }, + { + name: "barely insufficient funds", + stateFunc: func(ctrl *gomock.Controller) state.Chain { + return nil }, txFunc: func(require *require.Assertions) *txs.Tx { - tx := &txs.Tx{ - Unsigned: &baseTx, + input := input + input.In = &secp256k1fx.TransferInput{ + Amt: fxOutput.Amt + feeConfig.TxFee - 1, + Input: inputSigners, + } + + baseTx := baseTx + baseTx.Ins = []*avax.TransferableInput{ + &input, } + + tx := &txs.Tx{Unsigned: &txs.BaseTx{BaseTx: baseTx}} require.NoError(tx.SignSECP256K1Fx( codec, [][]*secp256k1.PrivateKey{ @@ -250,27 +460,25 @@ func TestSemanticVerifierBaseTx(t *testing.T) { )) return tx }, - err: database.ErrNotFound, + err: avax.ErrInsufficientFunds, }, { - name: "invalid UTXO amount", + name: "assetID mismatch", stateFunc: func(ctrl *gomock.Controller) state.Chain { state := state.NewMockChain(ctrl) - output := output - output.Amt-- - utxo := utxo - utxo.Out = &output + utxo.Asset.ID = ids.GenerateTestID() state.EXPECT().GetUTXO(utxoID.InputID()).Return(&utxo, nil) - state.EXPECT().GetTx(asset.ID).Return(&createAssetTx, nil) return state }, txFunc: func(require *require.Assertions) *txs.Tx { tx := &txs.Tx{ - Unsigned: &baseTx, + Unsigned: &txs.BaseTx{ + BaseTx: baseTx, + }, } require.NoError(tx.SignSECP256K1Fx( codec, @@ -280,10 +488,10 @@ func TestSemanticVerifierBaseTx(t *testing.T) { )) return tx }, - err: secp256k1fx.ErrMismatchedAmounts, + err: errAssetIDMismatch, }, { - name: "not allowed output feature extension", + name: "not allowed input feature extension", stateFunc: func(ctrl *gomock.Controller) state.Chain { state := state.NewMockChain(ctrl) @@ -294,71 +502,67 @@ func TestSemanticVerifierBaseTx(t *testing.T) { Unsigned: &unsignedCreateAssetTx, } + state.EXPECT().GetUTXO(utxoID.InputID()).Return(&utxo, nil) state.EXPECT().GetTx(asset.ID).Return(&createAssetTx, nil) return state }, txFunc: func(require *require.Assertions) *txs.Tx { - baseTx := baseTx - baseTx.Ins = nil - baseTx.Outs = []*avax.TransferableOutput{ - { - Asset: asset, - Out: &output, - }, - } tx := &txs.Tx{ - Unsigned: &baseTx, + Unsigned: &txs.BaseTx{ + BaseTx: baseTx, + }, } require.NoError(tx.SignSECP256K1Fx( codec, - [][]*secp256k1.PrivateKey{}, + [][]*secp256k1.PrivateKey{ + {keys[0]}, + }, )) return tx }, err: errIncompatibleFx, }, { - name: "unknown asset", + name: "invalid signature", stateFunc: func(ctrl *gomock.Controller) state.Chain { state := state.NewMockChain(ctrl) state.EXPECT().GetUTXO(utxoID.InputID()).Return(&utxo, nil) - state.EXPECT().GetTx(asset.ID).Return(nil, database.ErrNotFound) + state.EXPECT().GetTx(asset.ID).Return(&createAssetTx, nil) return state }, txFunc: func(require *require.Assertions) *txs.Tx { tx := &txs.Tx{ - Unsigned: &baseTx, + Unsigned: &txs.BaseTx{ + BaseTx: baseTx, + }, } require.NoError(tx.SignSECP256K1Fx( codec, [][]*secp256k1.PrivateKey{ - {keys[0]}, + {keys[1]}, }, )) return tx }, - err: database.ErrNotFound, + err: secp256k1fx.ErrWrongSig, }, { - name: "not an asset", + name: "missing UTXO", stateFunc: func(ctrl *gomock.Controller) state.Chain { state := state.NewMockChain(ctrl) - tx := txs.Tx{ - Unsigned: &baseTx, - } - - state.EXPECT().GetUTXO(utxoID.InputID()).Return(&utxo, nil) - state.EXPECT().GetTx(asset.ID).Return(&tx, nil) + state.EXPECT().GetUTXO(utxoID.InputID()).Return(nil, database.ErrNotFound) return state }, txFunc: func(require *require.Assertions) *txs.Tx { tx := &txs.Tx{ - Unsigned: &baseTx, + Unsigned: &txs.BaseTx{ + BaseTx: baseTx, + }, } require.NoError(tx.SignSECP256K1Fx( codec, @@ -368,10 +572,133 @@ func TestSemanticVerifierBaseTx(t *testing.T) { )) return tx }, - err: errNotAnAsset, + err: database.ErrNotFound, }, - } - for _, test := range tests { + { + name: "invalid UTXO amount", + stateFunc: func(ctrl *gomock.Controller) state.Chain { + state := state.NewMockChain(ctrl) + + utxoOut := utxoOut + utxoOut.Amt-- + + utxo := utxo + utxo.Out = &utxoOut + + state.EXPECT().GetUTXO(utxoID.InputID()).Return(&utxo, nil) + state.EXPECT().GetTx(asset.ID).Return(&createAssetTx, nil) + + return state + }, + txFunc: func(require *require.Assertions) *txs.Tx { + tx := &txs.Tx{ + Unsigned: &txs.BaseTx{ + BaseTx: baseTx, + }, + } + require.NoError(tx.SignSECP256K1Fx( + codec, + [][]*secp256k1.PrivateKey{ + {keys[0]}, + }, + )) + return tx + }, + err: secp256k1fx.ErrMismatchedAmounts, + }, + { + name: "not allowed output feature extension", + stateFunc: func(ctrl *gomock.Controller) state.Chain { + state := state.NewMockChain(ctrl) + + unsignedCreateAssetTx := unsignedCreateAssetTx + unsignedCreateAssetTx.States = nil + + createAssetTx := txs.Tx{ + Unsigned: &unsignedCreateAssetTx, + } + + state.EXPECT().GetTx(asset.ID).Return(&createAssetTx, nil) + state.EXPECT().GetUTXO(utxoID.InputID()).Return(&utxo, nil) + + return state + }, + txFunc: func(require *require.Assertions) *txs.Tx { + tx := &txs.Tx{ + Unsigned: &txs.BaseTx{ + BaseTx: baseTx, + }, + } + require.NoError(tx.SignSECP256K1Fx( + codec, + [][]*secp256k1.PrivateKey{ + {keys[0]}, + }, + )) + return tx + }, + err: errIncompatibleFx, + }, + { + name: "unknown asset", + stateFunc: func(ctrl *gomock.Controller) state.Chain { + state := state.NewMockChain(ctrl) + + state.EXPECT().GetUTXO(utxoID.InputID()).Return(&utxo, nil) + state.EXPECT().GetTx(asset.ID).Return(nil, database.ErrNotFound) + + return state + }, + txFunc: func(require *require.Assertions) *txs.Tx { + tx := &txs.Tx{ + Unsigned: &txs.BaseTx{ + BaseTx: baseTx, + }, + } + require.NoError(tx.SignSECP256K1Fx( + codec, + [][]*secp256k1.PrivateKey{ + {keys[0]}, + }, + )) + return tx + }, + err: database.ErrNotFound, + }, + { + name: "not an asset", + stateFunc: func(ctrl *gomock.Controller) state.Chain { + state := state.NewMockChain(ctrl) + + tx := txs.Tx{ + Unsigned: &txs.BaseTx{ + BaseTx: baseTx, + }, + } + + state.EXPECT().GetUTXO(utxoID.InputID()).Return(&utxo, nil) + state.EXPECT().GetTx(asset.ID).Return(&tx, nil) + + return state + }, + txFunc: func(require *require.Assertions) *txs.Tx { + tx := &txs.Tx{ + Unsigned: &txs.BaseTx{ + BaseTx: baseTx, + }, + } + require.NoError(tx.SignSECP256K1Fx( + codec, + [][]*secp256k1.PrivateKey{ + {keys[0]}, + }, + )) + return tx + }, + err: errNotAnAsset, + }, + } + for _, test := range tests { t.Run(test.name, func(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) @@ -392,54 +719,85 @@ func TestSemanticVerifierBaseTx(t *testing.T) { func TestSemanticVerifierExportTx(t *testing.T) { ctx := snowtest.Context(t, snowtest.XChainID) - typeToFxIndex := make(map[reflect.Type]int) - secpFx := &secp256k1fx.Fx{} - parser, err := txs.NewCustomParser( - time.Time{}, - typeToFxIndex, - new(mockable.Clock), - logging.NoWarn{}, - []fxs.Fx{ - secpFx, - }, - ) - require.NoError(t, err) - - codec := parser.Codec() - txID := ids.GenerateTestID() + // UTXO to be spent + inputTxID := ids.GenerateTestID() utxoID := avax.UTXOID{ - TxID: txID, - OutputIndex: 2, + TxID: inputTxID, + OutputIndex: 0, } + + feeAssetID := ids.GenerateTestID() asset := avax.Asset{ - ID: ids.GenerateTestID(), + ID: feeAssetID, } - inputSigner := secp256k1fx.Input{ - SigIndices: []uint32{ - 0, - }, + outputOwners := secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{keys[0].PublicKey().Address()}, + } + utxoAmount := 100 + feeConfig.TxFee + 50 + utxoOut := secp256k1fx.TransferOutput{ + Amt: utxoAmount, + OutputOwners: outputOwners, + } + utxo := avax.UTXO{ + UTXOID: utxoID, + Asset: asset, + Out: &utxoOut, + } + + // Input spending the UTXO + inputSigners := secp256k1fx.Input{ + SigIndices: []uint32{0}, } fxInput := secp256k1fx.TransferInput{ - Amt: 12345, - Input: inputSigner, + Amt: utxoAmount, + Input: inputSigners, } input := avax.TransferableInput{ UTXOID: utxoID, Asset: asset, In: &fxInput, } - baseTx := txs.BaseTx{ - BaseTx: avax.BaseTx{ - Ins: []*avax.TransferableInput{ - &input, - }, + + // Output produced by BaseTx + fxOutput := secp256k1fx.TransferOutput{ + Amt: 100, + OutputOwners: outputOwners, + } + output := avax.TransferableOutput{ + Asset: asset, + Out: &fxOutput, + } + + baseTx := avax.BaseTx{ + Outs: []*avax.TransferableOutput{ + &output, + }, + Ins: []*avax.TransferableInput{ + &input, }, } + exportTx := txs.ExportTx{ - BaseTx: baseTx, + BaseTx: txs.BaseTx{ + BaseTx: baseTx, + }, DestinationChain: ctx.CChainID, } + typeToFxIndex := make(map[reflect.Type]int) + secpFx := &secp256k1fx.Fx{} + parser, err := txs.NewCustomParser( + time.Time{}, + typeToFxIndex, + new(mockable.Clock), + logging.NoWarn{}, + []fxs.Fx{ + secpFx, + }, + ) + require.NoError(t, err) + codec := parser.Codec() backend := &Backend{ Ctx: ctx, Config: &feeConfig, @@ -451,26 +809,11 @@ func TestSemanticVerifierExportTx(t *testing.T) { }, TypeToFxIndex: typeToFxIndex, Codec: codec, - FeeAssetID: ids.GenerateTestID(), + FeeAssetID: feeAssetID, Bootstrapped: true, } require.NoError(t, secpFx.Bootstrapped()) - outputOwners := secp256k1fx.OutputOwners{ - Threshold: 1, - Addrs: []ids.ShortID{ - keys[0].Address(), - }, - } - output := secp256k1fx.TransferOutput{ - Amt: 12345, - OutputOwners: outputOwners, - } - utxo := avax.UTXO{ - UTXOID: utxoID, - Asset: asset, - Out: &output, - } unsignedCreateAssetTx := txs.CreateAssetTx{ States: []*txs.InitialState{{ FxIndex: 0, @@ -487,19 +830,369 @@ func TestSemanticVerifierExportTx(t *testing.T) { err error }{ { - name: "valid", + name: "valid", + stateFunc: func(ctrl *gomock.Controller) state.Chain { + state := state.NewMockChain(ctrl) + + state.EXPECT().GetUTXO(utxoID.InputID()).Return(&utxo, nil) + state.EXPECT().GetTx(asset.ID).Return(&createAssetTx, nil).Times(2) + + return state + }, + txFunc: func(require *require.Assertions) *txs.Tx { + tx := &txs.Tx{ + Unsigned: &exportTx, + } + require.NoError(tx.SignSECP256K1Fx( + codec, + [][]*secp256k1.PrivateKey{ + {keys[0]}, + }, + )) + return tx + }, + err: nil, + }, + { + name: "invalid output", + stateFunc: func(ctrl *gomock.Controller) state.Chain { + return nil + }, + txFunc: func(require *require.Assertions) *txs.Tx { + output := output + output.Out = &secp256k1fx.TransferOutput{ + Amt: 0, + OutputOwners: outputOwners, + } + + baseTx := baseTx + baseTx.Outs = []*avax.TransferableOutput{ + &output, + } + + eTx := exportTx + eTx.BaseTx.BaseTx = baseTx + tx := &txs.Tx{Unsigned: &eTx} + require.NoError(tx.SignSECP256K1Fx( + codec, + [][]*secp256k1.PrivateKey{ + {keys[0]}, + }, + )) + return tx + }, + err: secp256k1fx.ErrNoValueOutput, + }, + { + name: "unsorted outputs", + stateFunc: func(ctrl *gomock.Controller) state.Chain { + return nil + }, + txFunc: func(require *require.Assertions) *txs.Tx { + output0 := output + output0.Out = &secp256k1fx.TransferOutput{ + Amt: 1, + OutputOwners: outputOwners, + } + + output1 := output + output1.Out = &secp256k1fx.TransferOutput{ + Amt: 2, + OutputOwners: outputOwners, + } + + outputs := []*avax.TransferableOutput{ + &output0, + &output1, + } + avax.SortTransferableOutputs(outputs, codec) + outputs[0], outputs[1] = outputs[1], outputs[0] + + baseTx := baseTx + baseTx.Outs = outputs + + eTx := exportTx + eTx.BaseTx.BaseTx = baseTx + tx := &txs.Tx{Unsigned: &eTx} + require.NoError(tx.SignSECP256K1Fx( + codec, + [][]*secp256k1.PrivateKey{ + {keys[0]}, + }, + )) + return tx + }, + err: avax.ErrOutputsNotSorted, + }, + { + name: "unsorted exported outputs", + stateFunc: func(ctrl *gomock.Controller) state.Chain { + return nil + }, + txFunc: func(require *require.Assertions) *txs.Tx { + output0 := output + output0.Out = &secp256k1fx.TransferOutput{ + Amt: 1, + OutputOwners: outputOwners, + } + + output1 := output + output1.Out = &secp256k1fx.TransferOutput{ + Amt: 2, + OutputOwners: outputOwners, + } + + outputs := []*avax.TransferableOutput{ + &output0, + &output1, + } + avax.SortTransferableOutputs(outputs, codec) + outputs[0], outputs[1] = outputs[1], outputs[0] + + utx := exportTx + utx.ExportedOuts = outputs + tx := &txs.Tx{Unsigned: &utx} + require.NoError(tx.SignSECP256K1Fx( + codec, + [][]*secp256k1.PrivateKey{ + {keys[0]}, + }, + )) + return tx + }, + err: avax.ErrOutputsNotSorted, + }, + { + name: "invalid input", + stateFunc: func(ctrl *gomock.Controller) state.Chain { + return nil + }, + txFunc: func(require *require.Assertions) *txs.Tx { + input := input + input.In = &secp256k1fx.TransferInput{ + Amt: 0, + Input: inputSigners, + } + + baseTx := baseTx + baseTx.Ins = []*avax.TransferableInput{ + &input, + } + + eTx := exportTx + eTx.BaseTx.BaseTx = baseTx + tx := &txs.Tx{Unsigned: &eTx} + require.NoError(tx.SignSECP256K1Fx( + codec, + [][]*secp256k1.PrivateKey{ + {keys[0]}, + }, + )) + return tx + }, + err: secp256k1fx.ErrNoValueInput, + }, + { + name: "duplicate inputs", + stateFunc: func(ctrl *gomock.Controller) state.Chain { + return nil + }, + txFunc: func(require *require.Assertions) *txs.Tx { + baseTx := baseTx + baseTx.Ins = []*avax.TransferableInput{ + &input, + &input, + } + + eTx := exportTx + eTx.BaseTx.BaseTx = baseTx + tx := &txs.Tx{Unsigned: &eTx} + require.NoError(tx.SignSECP256K1Fx( + codec, + [][]*secp256k1.PrivateKey{ + {keys[0]}, + {keys[0]}, + }, + )) + return tx + }, + err: avax.ErrInputsNotSortedUnique, + }, + { + name: "input overflow", + stateFunc: func(ctrl *gomock.Controller) state.Chain { + return nil + }, + txFunc: func(require *require.Assertions) *txs.Tx { + input0 := input + input0.In = &secp256k1fx.TransferInput{ + Amt: 1, + Input: inputSigners, + } + + input1 := input + input1.UTXOID.OutputIndex++ + input1.In = &secp256k1fx.TransferInput{ + Amt: math.MaxUint64, + Input: inputSigners, + } + + baseTx := baseTx + baseTx.Ins = []*avax.TransferableInput{ + &input0, + &input1, + } + avax.SortTransferableInputsWithSigners(baseTx.Ins, make([][]*secp256k1.PrivateKey, 2)) + + eTx := exportTx + eTx.BaseTx.BaseTx = baseTx + tx := &txs.Tx{Unsigned: &eTx} + require.NoError(tx.SignSECP256K1Fx( + codec, + [][]*secp256k1.PrivateKey{ + {keys[0]}, + }, + )) + return tx + }, + err: safemath.ErrOverflow, + }, + { + name: "output overflow", + stateFunc: func(ctrl *gomock.Controller) state.Chain { + return nil + }, + txFunc: func(require *require.Assertions) *txs.Tx { + output0 := output + output0.Out = &secp256k1fx.TransferOutput{ + Amt: 1, + OutputOwners: outputOwners, + } + + output1 := output + output1.Out = &secp256k1fx.TransferOutput{ + Amt: math.MaxUint64, + OutputOwners: outputOwners, + } + + outputs := []*avax.TransferableOutput{ + &output0, + &output1, + } + avax.SortTransferableOutputs(outputs, codec) + + baseTx := baseTx + baseTx.Outs = outputs + + eTx := exportTx + eTx.BaseTx.BaseTx = baseTx + tx := &txs.Tx{Unsigned: &eTx} + require.NoError(tx.SignSECP256K1Fx( + codec, + [][]*secp256k1.PrivateKey{ + {keys[0]}, + }, + )) + return tx + }, + err: safemath.ErrOverflow, + }, + { + name: "barely sufficient funds", + stateFunc: func(ctrl *gomock.Controller) state.Chain { + state := state.NewMockChain(ctrl) + + utxoAmount := 100 + feeConfig.TxFee + utxoOut := secp256k1fx.TransferOutput{ + Amt: utxoAmount, + OutputOwners: outputOwners, + } + utxo := avax.UTXO{ + UTXOID: utxoID, + Asset: asset, + Out: &utxoOut, + } + + state.EXPECT().GetUTXO(utxoID.InputID()).Return(&utxo, nil) + state.EXPECT().GetTx(asset.ID).Return(&createAssetTx, nil).Times(2) + + return state + }, + txFunc: func(require *require.Assertions) *txs.Tx { + input := input + input.In = &secp256k1fx.TransferInput{ + Amt: fxOutput.Amt + feeConfig.TxFee, + Input: inputSigners, + } + + baseTx := baseTx + baseTx.Ins = []*avax.TransferableInput{ + &input, + } + + eTx := exportTx + eTx.BaseTx.BaseTx = baseTx + tx := &txs.Tx{Unsigned: &eTx} + require.NoError(tx.SignSECP256K1Fx( + codec, + [][]*secp256k1.PrivateKey{ + {keys[0]}, + }, + )) + return tx + }, + err: nil, + }, + { + name: "insufficient funds", + stateFunc: func(ctrl *gomock.Controller) state.Chain { + return nil + }, + txFunc: func(require *require.Assertions) *txs.Tx { + input := input + input.In = &secp256k1fx.TransferInput{ + Amt: 1, + Input: inputSigners, + } + + baseTx := baseTx + baseTx.Ins = []*avax.TransferableInput{ + &input, + } + + eTx := exportTx + eTx.BaseTx.BaseTx = baseTx + tx := &txs.Tx{Unsigned: &eTx} + require.NoError(tx.SignSECP256K1Fx( + codec, + [][]*secp256k1.PrivateKey{ + {keys[0]}, + }, + )) + return tx + }, + err: avax.ErrInsufficientFunds, + }, + { + name: "barely insufficient funds", stateFunc: func(ctrl *gomock.Controller) state.Chain { - state := state.NewMockChain(ctrl) - - state.EXPECT().GetUTXO(utxoID.InputID()).Return(&utxo, nil) - state.EXPECT().GetTx(asset.ID).Return(&createAssetTx, nil) - - return state + return nil }, txFunc: func(require *require.Assertions) *txs.Tx { - tx := &txs.Tx{ - Unsigned: &exportTx, + input := input + input.In = &secp256k1fx.TransferInput{ + Amt: fxOutput.Amt + feeConfig.TxFee - 1, + Input: inputSigners, + } + + baseTx := baseTx + baseTx.Ins = []*avax.TransferableInput{ + &input, } + + eTx := exportTx + eTx.BaseTx.BaseTx = baseTx + tx := &txs.Tx{Unsigned: &eTx} require.NoError(tx.SignSECP256K1Fx( codec, [][]*secp256k1.PrivateKey{ @@ -508,7 +1201,7 @@ func TestSemanticVerifierExportTx(t *testing.T) { )) return tx }, - err: nil, + err: avax.ErrInsufficientFunds, }, { name: "assetID mismatch", @@ -619,7 +1312,7 @@ func TestSemanticVerifierExportTx(t *testing.T) { stateFunc: func(ctrl *gomock.Controller) state.Chain { state := state.NewMockChain(ctrl) - output := output + output := utxoOut output.Amt-- utxo := utxo @@ -657,24 +1350,19 @@ func TestSemanticVerifierExportTx(t *testing.T) { } state.EXPECT().GetTx(asset.ID).Return(&createAssetTx, nil) + state.EXPECT().GetUTXO(utxoID.InputID()).Return(&utxo, nil) return state }, txFunc: func(require *require.Assertions) *txs.Tx { - exportTx := exportTx - exportTx.Ins = nil - exportTx.ExportedOuts = []*avax.TransferableOutput{ - { - Asset: asset, - Out: &output, - }, - } tx := &txs.Tx{ Unsigned: &exportTx, } require.NoError(tx.SignSECP256K1Fx( codec, - [][]*secp256k1.PrivateKey{}, + [][]*secp256k1.PrivateKey{ + {keys[0]}, + }, )) return tx }, @@ -710,7 +1398,7 @@ func TestSemanticVerifierExportTx(t *testing.T) { state := state.NewMockChain(ctrl) tx := txs.Tx{ - Unsigned: &baseTx, + Unsigned: &exportTx, } state.EXPECT().GetUTXO(utxoID.InputID()).Return(&utxo, nil) @@ -761,54 +1449,87 @@ func TestSemanticVerifierExportTxDifferentSubnet(t *testing.T) { validatorState.EXPECT().GetSubnetID(gomock.Any(), ctx.CChainID).AnyTimes().Return(ids.GenerateTestID(), nil) ctx.ValidatorState = validatorState - typeToFxIndex := make(map[reflect.Type]int) - secpFx := &secp256k1fx.Fx{} - parser, err := txs.NewCustomParser( - time.Time{}, - typeToFxIndex, - new(mockable.Clock), - logging.NoWarn{}, - []fxs.Fx{ - secpFx, - }, - ) - require.NoError(err) - - codec := parser.Codec() - txID := ids.GenerateTestID() + // UTXO to be spent + inputTxID := ids.GenerateTestID() utxoID := avax.UTXOID{ - TxID: txID, - OutputIndex: 2, + TxID: inputTxID, + OutputIndex: 0, } + + feeAssetID := ids.GenerateTestID() asset := avax.Asset{ - ID: ids.GenerateTestID(), + ID: feeAssetID, } - inputSigner := secp256k1fx.Input{ - SigIndices: []uint32{ - 0, - }, + outputOwners := secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{keys[0].PublicKey().Address()}, + } + utxoAmount := 100 + feeConfig.TxFee + utxoOut := secp256k1fx.TransferOutput{ + Amt: utxoAmount, + OutputOwners: outputOwners, + } + utxo := avax.UTXO{ + UTXOID: utxoID, + Asset: asset, + Out: &utxoOut, + } + + // Input spending the UTXO + inputSigners := secp256k1fx.Input{ + SigIndices: []uint32{0}, } fxInput := secp256k1fx.TransferInput{ - Amt: 12345, - Input: inputSigner, + Amt: utxoAmount, + Input: inputSigners, } input := avax.TransferableInput{ UTXOID: utxoID, Asset: asset, In: &fxInput, } - baseTx := txs.BaseTx{ - BaseTx: avax.BaseTx{ - Ins: []*avax.TransferableInput{ - &input, - }, + + // Output produced by BaseTx + fxOutput := secp256k1fx.TransferOutput{ + Amt: 100, + OutputOwners: outputOwners, + } + output := avax.TransferableOutput{ + Asset: asset, + Out: &fxOutput, + } + + // BaseTx + baseTx := avax.BaseTx{ + Outs: []*avax.TransferableOutput{ + &output, + }, + Ins: []*avax.TransferableInput{ + &input, }, } + exportTx := txs.ExportTx{ - BaseTx: baseTx, + BaseTx: txs.BaseTx{ + BaseTx: baseTx, + }, DestinationChain: ctx.CChainID, } + typeToFxIndex := make(map[reflect.Type]int) + secpFx := &secp256k1fx.Fx{} + parser, err := txs.NewCustomParser( + time.Time{}, + typeToFxIndex, + new(mockable.Clock), + logging.NoWarn{}, + []fxs.Fx{ + secpFx, + }, + ) + require.NoError(err) + + codec := parser.Codec() backend := &Backend{ Ctx: ctx, Config: &feeConfig, @@ -820,26 +1541,11 @@ func TestSemanticVerifierExportTxDifferentSubnet(t *testing.T) { }, TypeToFxIndex: typeToFxIndex, Codec: codec, - FeeAssetID: ids.GenerateTestID(), + FeeAssetID: feeAssetID, Bootstrapped: true, } require.NoError(secpFx.Bootstrapped()) - outputOwners := secp256k1fx.OutputOwners{ - Threshold: 1, - Addrs: []ids.ShortID{ - keys[0].Address(), - }, - } - output := secp256k1fx.TransferOutput{ - Amt: 12345, - OutputOwners: outputOwners, - } - utxo := avax.UTXO{ - UTXOID: utxoID, - Asset: asset, - Out: &output, - } unsignedCreateAssetTx := txs.CreateAssetTx{ States: []*txs.InitialState{{ FxIndex: 0, @@ -852,7 +1558,7 @@ func TestSemanticVerifierExportTxDifferentSubnet(t *testing.T) { state := state.NewMockChain(ctrl) state.EXPECT().GetUTXO(utxoID.InputID()).Return(&utxo, nil) - state.EXPECT().GetTx(asset.ID).Return(&createAssetTx, nil) + state.EXPECT().GetTx(asset.ID).Return(&createAssetTx, nil).Times(2) tx := &txs.Tx{ Unsigned: &exportTx, @@ -890,50 +1596,84 @@ func TestSemanticVerifierImportTx(t *testing.T) { }, ) require.NoError(t, err) - codec := parser.Codec() + + // UTXOs to be spent + utxoAmount := 100 + feeConfig.TxFee + inputTxID := ids.GenerateTestID() utxoID := avax.UTXOID{ - TxID: ids.GenerateTestID(), - OutputIndex: 2, + TxID: inputTxID, + OutputIndex: 0, } + feeAssetID := ids.GenerateTestID() asset := avax.Asset{ - ID: ids.GenerateTestID(), + ID: feeAssetID, } outputOwners := secp256k1fx.OutputOwners{ Threshold: 1, - Addrs: []ids.ShortID{ - keys[0].Address(), - }, - } - baseTx := txs.BaseTx{ - BaseTx: avax.BaseTx{ - NetworkID: constants.UnitTestID, - BlockchainID: ctx.ChainID, - Outs: []*avax.TransferableOutput{{ - Asset: asset, - Out: &secp256k1fx.TransferOutput{ - Amt: 1000, - OutputOwners: outputOwners, - }, - }}, - }, + Addrs: []ids.ShortID{keys[0].PublicKey().Address()}, + } + utxoOut := secp256k1fx.TransferOutput{ + Amt: utxoAmount, + OutputOwners: outputOwners, + } + utxo := avax.UTXO{ + UTXOID: utxoID, + Asset: asset, + Out: &utxoOut, + } + + // Input spending the UTXO + inputSigners := secp256k1fx.Input{ + SigIndices: []uint32{0}, + } + fxInput := secp256k1fx.TransferInput{ + Amt: utxoAmount, + Input: inputSigners, } input := avax.TransferableInput{ + UTXOID: utxoID, + Asset: asset, + In: &fxInput, + } + + // Output produced by BaseTx + fxOutput := secp256k1fx.TransferOutput{ + Amt: 100, + OutputOwners: outputOwners, + } + output := avax.TransferableOutput{ + Asset: asset, + Out: &fxOutput, + } + + baseTx := avax.BaseTx{ + NetworkID: constants.UnitTestID, + BlockchainID: ctx.ChainID, + Outs: []*avax.TransferableOutput{ + &output, + }, + // no inputs here, only imported ones + } + + importedInput := avax.TransferableInput{ UTXOID: utxoID, Asset: asset, In: &secp256k1fx.TransferInput{ - Amt: 12345, + Amt: utxoAmount, Input: secp256k1fx.Input{ SigIndices: []uint32{0}, }, }, } unsignedImportTx := txs.ImportTx{ - BaseTx: baseTx, + BaseTx: txs.BaseTx{ + BaseTx: baseTx, + }, SourceChain: ctx.CChainID, ImportedIns: []*avax.TransferableInput{ - &input, + &importedInput, }, } importTx := &txs.Tx{ @@ -943,6 +1683,7 @@ func TestSemanticVerifierImportTx(t *testing.T) { codec, [][]*secp256k1.PrivateKey{ {keys[0]}, + {keys[0]}, }, )) @@ -957,20 +1698,11 @@ func TestSemanticVerifierImportTx(t *testing.T) { }, TypeToFxIndex: typeToFxIndex, Codec: codec, - FeeAssetID: ids.GenerateTestID(), + FeeAssetID: feeAssetID, Bootstrapped: true, } require.NoError(t, fx.Bootstrapped()) - output := secp256k1fx.TransferOutput{ - Amt: 12345, - OutputOwners: outputOwners, - } - utxo := avax.UTXO{ - UTXOID: utxoID, - Asset: asset, - Out: &output, - } utxoBytes, err := codec.Marshal(txs.CodecVersion, utxo) require.NoError(t, err) @@ -1011,6 +1743,237 @@ func TestSemanticVerifierImportTx(t *testing.T) { }, expectedErr: nil, }, + { + name: "invalid output", + stateFunc: func(c *gomock.Controller) state.Chain { + return nil + }, + txFunc: func(require *require.Assertions) *txs.Tx { + output := output + output.Out = &secp256k1fx.TransferOutput{ + Amt: 0, + OutputOwners: outputOwners, + } + + utx := unsignedImportTx + utx.Outs = []*avax.TransferableOutput{ + &output, + } + + tx := &txs.Tx{Unsigned: &utx} + require.NoError(tx.SignSECP256K1Fx( + codec, + [][]*secp256k1.PrivateKey{ + {keys[0]}, + }, + )) + return tx + }, + expectedErr: secp256k1fx.ErrNoValueOutput, + }, + { + name: "unsorted outputs", + stateFunc: func(c *gomock.Controller) state.Chain { + return nil + }, + txFunc: func(require *require.Assertions) *txs.Tx { + output0 := output + output0.Out = &secp256k1fx.TransferOutput{ + Amt: 1, + OutputOwners: outputOwners, + } + + output1 := output + output1.Out = &secp256k1fx.TransferOutput{ + Amt: 2, + OutputOwners: outputOwners, + } + + outputs := []*avax.TransferableOutput{ + &output0, + &output1, + } + avax.SortTransferableOutputs(outputs, codec) + outputs[0], outputs[1] = outputs[1], outputs[0] + + utx := unsignedImportTx + utx.Outs = outputs + tx := &txs.Tx{Unsigned: &utx} + require.NoError(tx.SignSECP256K1Fx( + codec, + [][]*secp256k1.PrivateKey{ + {keys[0]}, + }, + )) + return tx + }, + expectedErr: avax.ErrOutputsNotSorted, + }, + { + name: "invalid input", + stateFunc: func(c *gomock.Controller) state.Chain { + return nil + }, + txFunc: func(require *require.Assertions) *txs.Tx { + input := input + input.In = &secp256k1fx.TransferInput{ + Amt: 0, + Input: inputSigners, + } + + utx := unsignedImportTx + utx.Ins = []*avax.TransferableInput{ + &input, + } + tx := &txs.Tx{Unsigned: &utx} + require.NoError(tx.SignSECP256K1Fx( + codec, + [][]*secp256k1.PrivateKey{ + {keys[0]}, + }, + )) + return tx + }, + expectedErr: secp256k1fx.ErrNoValueInput, + }, + { + name: "duplicate inputs", + stateFunc: func(c *gomock.Controller) state.Chain { + return nil + }, + txFunc: func(require *require.Assertions) *txs.Tx { + utx := unsignedImportTx + utx.Ins = []*avax.TransferableInput{ + &input, + &input, + } + tx := &txs.Tx{Unsigned: &utx} + require.NoError(tx.SignSECP256K1Fx( + codec, + [][]*secp256k1.PrivateKey{ + {keys[0]}, + {keys[0]}, + {keys[0]}, + })) + return tx + }, + expectedErr: avax.ErrInputsNotSortedUnique, + }, + { + name: "duplicate imported inputs", + stateFunc: func(c *gomock.Controller) state.Chain { + return nil + }, + txFunc: func(require *require.Assertions) *txs.Tx { + utx := unsignedImportTx + utx.ImportedIns = []*avax.TransferableInput{ + &input, + &input, + } + tx := &txs.Tx{Unsigned: &utx} + require.NoError(tx.SignSECP256K1Fx( + codec, + [][]*secp256k1.PrivateKey{ + {keys[0]}, + {keys[0]}, + })) + return tx + }, + expectedErr: avax.ErrInputsNotSortedUnique, + }, + { + name: "input overflow", + stateFunc: func(c *gomock.Controller) state.Chain { + return nil + }, + txFunc: func(require *require.Assertions) *txs.Tx { + input0 := input + input0.In = &secp256k1fx.TransferInput{ + Amt: 1, + Input: inputSigners, + } + + input1 := input + input1.UTXOID.OutputIndex++ + input1.In = &secp256k1fx.TransferInput{ + Amt: math.MaxUint64, + Input: inputSigners, + } + + utx := unsignedImportTx + utx.Ins = []*avax.TransferableInput{ + &input0, + &input1, + } + avax.SortTransferableInputsWithSigners(utx.Ins, make([][]*secp256k1.PrivateKey, 2)) + tx := &txs.Tx{Unsigned: &utx} + require.NoError(tx.SignSECP256K1Fx( + codec, + [][]*secp256k1.PrivateKey{ + {keys[0]}, + {keys[0]}, + })) + return tx + }, + expectedErr: safemath.ErrOverflow, + }, + { + name: "output overflow", + stateFunc: func(c *gomock.Controller) state.Chain { + return nil + }, + txFunc: func(require *require.Assertions) *txs.Tx { + output := output + output.Out = &secp256k1fx.TransferOutput{ + Amt: math.MaxUint64, + OutputOwners: outputOwners, + } + + outputs := []*avax.TransferableOutput{ + &output, + } + avax.SortTransferableOutputs(outputs, codec) + + utx := unsignedImportTx + utx.Outs = outputs + tx := &txs.Tx{Unsigned: &utx} + require.NoError(tx.SignSECP256K1Fx( + codec, + [][]*secp256k1.PrivateKey{ + {keys[0]}, + {keys[0]}, + })) + return tx + }, + expectedErr: safemath.ErrOverflow, + }, + { + name: "insufficient funds", + stateFunc: func(c *gomock.Controller) state.Chain { + return nil + }, + txFunc: func(require *require.Assertions) *txs.Tx { + input := input + input.In = &secp256k1fx.TransferInput{ + Amt: 1, + Input: inputSigners, + } + + utx := unsignedImportTx + utx.ImportedIns = []*avax.TransferableInput{ + &input, + } + tx := &txs.Tx{Unsigned: &utx} + require.NoError(tx.SignSECP256K1Fx( + codec, + [][]*secp256k1.PrivateKey{ + {keys[0]}, + {keys[0]}, + })) + return tx + }, + expectedErr: avax.ErrInsufficientFunds, + }, { name: "not allowed input feature extension", stateFunc: func(ctrl *gomock.Controller) state.Chain { @@ -1098,7 +2061,9 @@ func TestSemanticVerifierImportTx(t *testing.T) { stateFunc: func(ctrl *gomock.Controller) state.Chain { state := state.NewMockChain(ctrl) tx := txs.Tx{ - Unsigned: &baseTx, + Unsigned: &txs.BaseTx{ + BaseTx: baseTx, + }, } state.EXPECT().GetUTXO(utxoID.InputID()).Return(&utxo, nil).AnyTimes() state.EXPECT().GetTx(asset.ID).Return(&tx, nil) diff --git a/vms/avm/txs/executor/syntactic_verifier_test.go b/vms/avm/txs/executor/syntactic_verifier_test.go index 30a36fadc18..050491109f3 100644 --- a/vms/avm/txs/executor/syntactic_verifier_test.go +++ b/vms/avm/txs/executor/syntactic_verifier_test.go @@ -160,177 +160,6 @@ func TestSyntacticVerifierBaseTx(t *testing.T) { }, err: avax.ErrMemoTooLarge, }, - // { - // name: "invalid output", - // txFunc: func() *txs.Tx { - // output := output - // output.Out = &secp256k1fx.TransferOutput{ - // Amt: 0, - // OutputOwners: outputOwners, - // } - - // baseTx := baseTx - // baseTx.Outs = []*avax.TransferableOutput{ - // &output, - // } - // return &txs.Tx{ - // Unsigned: &txs.BaseTx{BaseTx: baseTx}, - // Creds: creds, - // } - // }, - // err: secp256k1fx.ErrNoValueOutput, - // }, - // { - // name: "unsorted outputs", - // txFunc: func() *txs.Tx { - // output0 := output - // output0.Out = &secp256k1fx.TransferOutput{ - // Amt: 1, - // OutputOwners: outputOwners, - // } - - // output1 := output - // output1.Out = &secp256k1fx.TransferOutput{ - // Amt: 2, - // OutputOwners: outputOwners, - // } - - // outputs := []*avax.TransferableOutput{ - // &output0, - // &output1, - // } - // avax.SortTransferableOutputs(outputs, codec) - // outputs[0], outputs[1] = outputs[1], outputs[0] - - // baseTx := baseTx - // baseTx.Outs = outputs - // return &txs.Tx{ - // Unsigned: &txs.BaseTx{BaseTx: baseTx}, - // Creds: creds, - // } - // }, - // err: avax.ErrOutputsNotSorted, - // }, - // { - // name: "invalid input", - // txFunc: func() *txs.Tx { - // input := input - // input.In = &secp256k1fx.TransferInput{ - // Amt: 0, - // Input: inputSigners, - // } - - // baseTx := baseTx - // baseTx.Ins = []*avax.TransferableInput{ - // &input, - // } - // return &txs.Tx{ - // Unsigned: &txs.BaseTx{BaseTx: baseTx}, - // Creds: creds, - // } - // }, - // err: secp256k1fx.ErrNoValueInput, - // }, - // { - // name: "duplicate inputs", - // txFunc: func() *txs.Tx { - // baseTx := baseTx - // baseTx.Ins = []*avax.TransferableInput{ - // &input, - // &input, - // } - // return &txs.Tx{ - // Unsigned: &txs.BaseTx{BaseTx: baseTx}, - // Creds: []*fxs.FxCredential{ - // &cred, - // &cred, - // }, - // } - // }, - // err: avax.ErrInputsNotSortedUnique, - // }, - // { - // name: "input overflow", - // txFunc: func() *txs.Tx { - // input0 := input - // input0.In = &secp256k1fx.TransferInput{ - // Amt: 1, - // Input: inputSigners, - // } - - // input1 := input - // input1.UTXOID.OutputIndex++ - // input1.In = &secp256k1fx.TransferInput{ - // Amt: math.MaxUint64, - // Input: inputSigners, - // } - - // baseTx := baseTx - // baseTx.Ins = []*avax.TransferableInput{ - // &input0, - // &input1, - // } - // avax.SortTransferableInputsWithSigners(baseTx.Ins, make([][]*secp256k1.PrivateKey, 2)) - // return &txs.Tx{ - // Unsigned: &txs.BaseTx{BaseTx: baseTx}, - // Creds: []*fxs.FxCredential{ - // &cred, - // &cred, - // }, - // } - // }, - // err: safemath.ErrOverflow, - // }, - // { - // name: "output overflow", - // txFunc: func() *txs.Tx { - // output0 := output - // output0.Out = &secp256k1fx.TransferOutput{ - // Amt: 1, - // OutputOwners: outputOwners, - // } - - // output1 := output - // output1.Out = &secp256k1fx.TransferOutput{ - // Amt: math.MaxUint64, - // OutputOwners: outputOwners, - // } - - // outputs := []*avax.TransferableOutput{ - // &output0, - // &output1, - // } - // avax.SortTransferableOutputs(outputs, codec) - - // baseTx := baseTx - // baseTx.Outs = outputs - // return &txs.Tx{ - // Unsigned: &txs.BaseTx{BaseTx: baseTx}, - // Creds: creds, - // } - // }, - // err: safemath.ErrOverflow, - // }, - // { - // name: "insufficient funds", - // txFunc: func() *txs.Tx { - // input := input - // input.In = &secp256k1fx.TransferInput{ - // Amt: 1, - // Input: inputSigners, - // } - - // baseTx := baseTx - // baseTx.Ins = []*avax.TransferableInput{ - // &input, - // } - // return &txs.Tx{ - // Unsigned: &txs.BaseTx{BaseTx: baseTx}, - // Creds: creds, - // } - // }, - // err: avax.ErrInsufficientFunds, - // }, { name: "invalid credential", txFunc: func() *txs.Tx { @@ -352,46 +181,6 @@ func TestSyntacticVerifierBaseTx(t *testing.T) { }, err: errWrongNumberOfCredentials, }, - // { - // name: "barely sufficient funds", - // txFunc: func() *txs.Tx { - // input := input - // input.In = &secp256k1fx.TransferInput{ - // Amt: fxOutput.Amt + feeConfig.TxFee, - // Input: inputSigners, - // } - - // baseTx := baseTx - // baseTx.Ins = []*avax.TransferableInput{ - // &input, - // } - // return &txs.Tx{ - // Unsigned: &txs.BaseTx{BaseTx: baseTx}, - // Creds: creds, - // } - // }, - // err: nil, - // }, - // { - // name: "barely insufficient funds", - // txFunc: func() *txs.Tx { - // input := input - // input.In = &secp256k1fx.TransferInput{ - // Amt: fxOutput.Amt + feeConfig.TxFee - 1, - // Input: inputSigners, - // } - - // baseTx := baseTx - // baseTx.Ins = []*avax.TransferableInput{ - // &input, - // } - // return &txs.Tx{ - // Unsigned: &txs.BaseTx{BaseTx: baseTx}, - // Creds: creds, - // } - // }, - // err: avax.ErrInsufficientFunds, - // }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { @@ -656,215 +445,44 @@ func TestSyntacticVerifierCreateAssetTx(t *testing.T) { }, err: avax.ErrMemoTooLarge, }, - // { - // name: "invalid output", - // txFunc: func() *txs.Tx { - // output := output - // output.Out = &secp256k1fx.TransferOutput{ - // Amt: 0, - // OutputOwners: outputOwners, - // } - - // tx := tx - // tx.Outs = []*avax.TransferableOutput{ - // &output, - // } - // return &txs.Tx{ - // Unsigned: &tx, - // Creds: creds, - // } - // }, - // err: secp256k1fx.ErrNoValueOutput, - // }, - // { - // name: "unsorted outputs", - // txFunc: func() *txs.Tx { - // output0 := output - // output0.Out = &secp256k1fx.TransferOutput{ - // Amt: 1, - // OutputOwners: outputOwners, - // } + { + name: "invalid nil state", + txFunc: func() *txs.Tx { + tx := tx + tx.States = []*txs.InitialState{ + nil, + } + return &txs.Tx{ + Unsigned: &tx, + Creds: creds, + } + }, + err: txs.ErrNilInitialState, + }, + { + name: "invalid fx", + txFunc: func() *txs.Tx { + initialState := initialState + initialState.FxIndex = 1 - // output1 := output - // output1.Out = &secp256k1fx.TransferOutput{ - // Amt: 2, - // OutputOwners: outputOwners, - // } - - // outputs := []*avax.TransferableOutput{ - // &output0, - // &output1, - // } - // avax.SortTransferableOutputs(outputs, codec) - // outputs[0], outputs[1] = outputs[1], outputs[0] - - // tx := tx - // tx.Outs = outputs - // return &txs.Tx{ - // Unsigned: &tx, - // Creds: creds, - // } - // }, - // err: avax.ErrOutputsNotSorted, - // }, - // { - // name: "invalid input", - // txFunc: func() *txs.Tx { - // input := input - // input.In = &secp256k1fx.TransferInput{ - // Amt: 0, - // Input: inputSigners, - // } - - // tx := tx - // tx.Ins = []*avax.TransferableInput{ - // &input, - // } - // return &txs.Tx{ - // Unsigned: &tx, - // Creds: creds, - // } - // }, - // err: secp256k1fx.ErrNoValueInput, - // }, - // { - // name: "duplicate inputs", - // txFunc: func() *txs.Tx { - // tx := tx - // tx.Ins = []*avax.TransferableInput{ - // &input, - // &input, - // } - // return &txs.Tx{ - // Unsigned: &tx, - // Creds: []*fxs.FxCredential{ - // &cred, - // &cred, - // }, - // } - // }, - // err: avax.ErrInputsNotSortedUnique, - // }, - // { - // name: "input overflow", - // txFunc: func() *txs.Tx { - // input0 := input - // input0.In = &secp256k1fx.TransferInput{ - // Amt: 1, - // Input: inputSigners, - // } - - // input1 := input - // input1.UTXOID.OutputIndex++ - // input1.In = &secp256k1fx.TransferInput{ - // Amt: math.MaxUint64, - // Input: inputSigners, - // } - - // tx := tx - // tx.Ins = []*avax.TransferableInput{ - // &input0, - // &input1, - // } - // avax.SortTransferableInputsWithSigners(baseTx.Ins, make([][]*secp256k1.PrivateKey, 2)) - // return &txs.Tx{ - // Unsigned: &tx, - // Creds: []*fxs.FxCredential{ - // &cred, - // &cred, - // }, - // } - // }, - // err: safemath.ErrOverflow, - // }, - // { - // name: "output overflow", - // txFunc: func() *txs.Tx { - // output0 := output - // output0.Out = &secp256k1fx.TransferOutput{ - // Amt: 1, - // OutputOwners: outputOwners, - // } - - // output1 := output - // output1.Out = &secp256k1fx.TransferOutput{ - // Amt: math.MaxUint64, - // OutputOwners: outputOwners, - // } - - // outputs := []*avax.TransferableOutput{ - // &output0, - // &output1, - // } - // avax.SortTransferableOutputs(outputs, codec) - - // tx := tx - // tx.Outs = outputs - // return &txs.Tx{ - // Unsigned: &tx, - // Creds: creds, - // } - // }, - // err: safemath.ErrOverflow, - // }, - // { - // name: "insufficient funds", - // txFunc: func() *txs.Tx { - // input := input - // input.In = &secp256k1fx.TransferInput{ - // Amt: 1, - // Input: inputSigners, - // } - - // tx := tx - // tx.Ins = []*avax.TransferableInput{ - // &input, - // } - // return &txs.Tx{ - // Unsigned: &tx, - // Creds: creds, - // } - // }, - // err: avax.ErrInsufficientFunds, - // }, - { - name: "invalid nil state", - txFunc: func() *txs.Tx { - tx := tx - tx.States = []*txs.InitialState{ - nil, - } - return &txs.Tx{ - Unsigned: &tx, - Creds: creds, - } - }, - err: txs.ErrNilInitialState, - }, - { - name: "invalid fx", - txFunc: func() *txs.Tx { - initialState := initialState - initialState.FxIndex = 1 - - tx := tx - tx.States = []*txs.InitialState{ - &initialState, - } - return &txs.Tx{ - Unsigned: &tx, - Creds: creds, - } - }, - err: txs.ErrUnknownFx, - }, - { - name: "invalid nil state output", - txFunc: func() *txs.Tx { - initialState := initialState - initialState.Outs = []verify.State{ - nil, - } + tx := tx + tx.States = []*txs.InitialState{ + &initialState, + } + return &txs.Tx{ + Unsigned: &tx, + Creds: creds, + } + }, + err: txs.ErrUnknownFx, + }, + { + name: "invalid nil state output", + txFunc: func() *txs.Tx { + initialState := initialState + initialState.Outs = []verify.State{ + nil, + } tx := tx tx.States = []*txs.InitialState{ @@ -962,46 +580,6 @@ func TestSyntacticVerifierCreateAssetTx(t *testing.T) { }, err: errWrongNumberOfCredentials, }, - // { - // name: "barely sufficient funds", - // txFunc: func() *txs.Tx { - // input := input - // input.In = &secp256k1fx.TransferInput{ - // Amt: fxOutput.Amt + feeConfig.CreateAssetTxFee, - // Input: inputSigners, - // } - - // tx := tx - // tx.Ins = []*avax.TransferableInput{ - // &input, - // } - // return &txs.Tx{ - // Unsigned: &tx, - // Creds: creds, - // } - // }, - // err: nil, - // }, - // { - // name: "barely insufficient funds", - // txFunc: func() *txs.Tx { - // input := input - // input.In = &secp256k1fx.TransferInput{ - // Amt: fxOutput.Amt + feeConfig.CreateAssetTxFee - 1, - // Input: inputSigners, - // } - - // tx := tx - // tx.Ins = []*avax.TransferableInput{ - // &input, - // } - // return &txs.Tx{ - // Unsigned: &tx, - // Creds: creds, - // } - // }, - // err: avax.ErrInsufficientFunds, - // }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { @@ -1649,263 +1227,40 @@ func TestSyntacticVerifierImportTx(t *testing.T) { }, err: avax.ErrMemoTooLarge, }, - // { - // name: "invalid output", - // txFunc: func() *txs.Tx { - // output := output - // output.Out = &secp256k1fx.TransferOutput{ - // Amt: 0, - // OutputOwners: outputOwners, - // } - - // tx := tx - // tx.Outs = []*avax.TransferableOutput{ - // &output, - // } - // return &txs.Tx{ - // Unsigned: &tx, - // Creds: creds, - // } - // }, - // err: secp256k1fx.ErrNoValueOutput, - // }, - // { - // name: "unsorted outputs", - // txFunc: func() *txs.Tx { - // output0 := output - // output0.Out = &secp256k1fx.TransferOutput{ - // Amt: 1, - // OutputOwners: outputOwners, - // } - - // output1 := output - // output1.Out = &secp256k1fx.TransferOutput{ - // Amt: 2, - // OutputOwners: outputOwners, - // } - - // outputs := []*avax.TransferableOutput{ - // &output0, - // &output1, - // } - // avax.SortTransferableOutputs(outputs, codec) - // outputs[0], outputs[1] = outputs[1], outputs[0] - - // tx := tx - // tx.Outs = outputs - // return &txs.Tx{ - // Unsigned: &tx, - // Creds: creds, - // } - // }, - // err: avax.ErrOutputsNotSorted, - // }, - // { - // name: "invalid input", - // txFunc: func() *txs.Tx { - // input := input - // input.In = &secp256k1fx.TransferInput{ - // Amt: 0, - // Input: inputSigners, - // } - - // tx := tx - // tx.Ins = []*avax.TransferableInput{ - // &input, - // } - // return &txs.Tx{ - // Unsigned: &tx, - // Creds: creds, - // } - // }, - // err: secp256k1fx.ErrNoValueInput, - // }, - // { - // name: "duplicate inputs", - // txFunc: func() *txs.Tx { - // tx := tx - // tx.Ins = []*avax.TransferableInput{ - // &input, - // &input, - // } - // return &txs.Tx{ - // Unsigned: &tx, - // Creds: []*fxs.FxCredential{ - // &cred, - // &cred, - // &cred, - // }, - // } - // }, - // err: avax.ErrInputsNotSortedUnique, - // }, - // { - // name: "duplicate imported inputs", - // txFunc: func() *txs.Tx { - // tx := tx - // tx.ImportedIns = []*avax.TransferableInput{ - // &input, - // &input, - // } - // return &txs.Tx{ - // Unsigned: &tx, - // Creds: []*fxs.FxCredential{ - // &cred, - // &cred, - // }, - // } - // }, - // err: avax.ErrInputsNotSortedUnique, - // }, - // { - // name: "input overflow", - // txFunc: func() *txs.Tx { - // input0 := input - // input0.In = &secp256k1fx.TransferInput{ - // Amt: 1, - // Input: inputSigners, - // } - - // input1 := input - // input1.UTXOID.OutputIndex++ - // input1.In = &secp256k1fx.TransferInput{ - // Amt: math.MaxUint64, - // Input: inputSigners, - // } - - // tx := tx - // tx.Ins = []*avax.TransferableInput{ - // &input0, - // &input1, - // } - // avax.SortTransferableInputsWithSigners(tx.Ins, make([][]*secp256k1.PrivateKey, 2)) - // return &txs.Tx{ - // Unsigned: &tx, - // Creds: []*fxs.FxCredential{ - // &cred, - // &cred, - // }, - // } - // }, - // err: safemath.ErrOverflow, - // }, - // { - // name: "output overflow", - // txFunc: func() *txs.Tx { - // output := output - // output.Out = &secp256k1fx.TransferOutput{ - // Amt: math.MaxUint64, - // OutputOwners: outputOwners, - // } - - // outputs := []*avax.TransferableOutput{ - // &output, - // } - // avax.SortTransferableOutputs(outputs, codec) - - // tx := tx - // tx.Outs = outputs - // return &txs.Tx{ - // Unsigned: &tx, - // Creds: creds, - // } - // }, - // err: safemath.ErrOverflow, - // }, - // { - // name: "insufficient funds", - // txFunc: func() *txs.Tx { - // input := input - // input.In = &secp256k1fx.TransferInput{ - // Amt: 1, - // Input: inputSigners, - // } - - // tx := tx - // tx.ImportedIns = []*avax.TransferableInput{ - // &input, - // } - // return &txs.Tx{ - // Unsigned: &tx, - // Creds: creds, - // } - // }, - // err: avax.ErrInsufficientFunds, - // }, - { - name: "invalid credential", - txFunc: func() *txs.Tx { - return &txs.Tx{ - Unsigned: &tx, - Creds: []*fxs.FxCredential{{ - Credential: (*secp256k1fx.Credential)(nil), - }}, - } - }, - err: secp256k1fx.ErrNilCredential, - }, - { - name: "wrong number of credentials", - txFunc: func() *txs.Tx { - return &txs.Tx{ - Unsigned: &tx, - } - }, - err: errWrongNumberOfCredentials, - }, - // { - // name: "barely sufficient funds", - // txFunc: func() *txs.Tx { - // input := input - // input.In = &secp256k1fx.TransferInput{ - // Amt: fxOutput.Amt + feeConfig.TxFee, - // Input: inputSigners, - // } - - // tx := tx - // tx.ImportedIns = []*avax.TransferableInput{ - // &input, - // } - // return &txs.Tx{ - // Unsigned: &tx, - // Creds: creds, - // } - // }, - // err: nil, - // }, - // { - // name: "barely insufficient funds", - // txFunc: func() *txs.Tx { - // input := input - // input.In = &secp256k1fx.TransferInput{ - // Amt: fxOutput.Amt + feeConfig.TxFee - 1, - // Input: inputSigners, - // } - - // tx := tx - // tx.ImportedIns = []*avax.TransferableInput{ - // &input, - // } - // return &txs.Tx{ - // Unsigned: &tx, - // Creds: creds, - // } - // }, - // err: avax.ErrInsufficientFunds, - // }, - } - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - tx := test.txFunc() - verifier := &SyntacticVerifier{ - Backend: backend, - Tx: tx, - } - err := tx.Unsigned.Visit(verifier) - require.ErrorIs(t, err, test.err) - }) - } -} + { + name: "invalid credential", + txFunc: func() *txs.Tx { + return &txs.Tx{ + Unsigned: &tx, + Creds: []*fxs.FxCredential{{ + Credential: (*secp256k1fx.Credential)(nil), + }}, + } + }, + err: secp256k1fx.ErrNilCredential, + }, + { + name: "wrong number of credentials", + txFunc: func() *txs.Tx { + return &txs.Tx{ + Unsigned: &tx, + } + }, + err: errWrongNumberOfCredentials, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + tx := test.txFunc() + verifier := &SyntacticVerifier{ + Backend: backend, + Tx: tx, + } + err := tx.Unsigned.Visit(verifier) + require.ErrorIs(t, err, test.err) + }) + } +} func TestSyntacticVerifierExportTx(t *testing.T) { ctx := snowtest.Context(t, snowtest.XChainID) @@ -2050,201 +1405,6 @@ func TestSyntacticVerifierExportTx(t *testing.T) { }, err: avax.ErrMemoTooLarge, }, - // { - // name: "invalid output", - // txFunc: func() *txs.Tx { - // output := output - // output.Out = &secp256k1fx.TransferOutput{ - // Amt: 0, - // OutputOwners: outputOwners, - // } - - // tx := tx - // tx.Outs = []*avax.TransferableOutput{ - // &output, - // } - // return &txs.Tx{ - // Unsigned: &tx, - // Creds: creds, - // } - // }, - // err: secp256k1fx.ErrNoValueOutput, - // }, - // { - // name: "unsorted outputs", - // txFunc: func() *txs.Tx { - // output0 := output - // output0.Out = &secp256k1fx.TransferOutput{ - // Amt: 1, - // OutputOwners: outputOwners, - // } - - // output1 := output - // output1.Out = &secp256k1fx.TransferOutput{ - // Amt: 2, - // OutputOwners: outputOwners, - // } - - // outputs := []*avax.TransferableOutput{ - // &output0, - // &output1, - // } - // avax.SortTransferableOutputs(outputs, codec) - // outputs[0], outputs[1] = outputs[1], outputs[0] - - // tx := tx - // tx.Outs = outputs - // return &txs.Tx{ - // Unsigned: &tx, - // Creds: creds, - // } - // }, - // err: avax.ErrOutputsNotSorted, - // }, - // { - // name: "unsorted exported outputs", - // txFunc: func() *txs.Tx { - // output0 := output - // output0.Out = &secp256k1fx.TransferOutput{ - // Amt: 1, - // OutputOwners: outputOwners, - // } - - // output1 := output - // output1.Out = &secp256k1fx.TransferOutput{ - // Amt: 2, - // OutputOwners: outputOwners, - // } - - // outputs := []*avax.TransferableOutput{ - // &output0, - // &output1, - // } - // avax.SortTransferableOutputs(outputs, codec) - // outputs[0], outputs[1] = outputs[1], outputs[0] - - // tx := tx - // tx.ExportedOuts = outputs - // return &txs.Tx{ - // Unsigned: &tx, - // Creds: creds, - // } - // }, - // err: avax.ErrOutputsNotSorted, - // }, - // { - // name: "invalid input", - // txFunc: func() *txs.Tx { - // input := input - // input.In = &secp256k1fx.TransferInput{ - // Amt: 0, - // Input: inputSigners, - // } - - // tx := tx - // tx.Ins = []*avax.TransferableInput{ - // &input, - // } - // return &txs.Tx{ - // Unsigned: &tx, - // Creds: creds, - // } - // }, - // err: secp256k1fx.ErrNoValueInput, - // }, - // { - // name: "duplicate inputs", - // txFunc: func() *txs.Tx { - // tx := tx - // tx.Ins = []*avax.TransferableInput{ - // &input, - // &input, - // } - // return &txs.Tx{ - // Unsigned: &tx, - // Creds: []*fxs.FxCredential{ - // &cred, - // &cred, - // }, - // } - // }, - // err: avax.ErrInputsNotSortedUnique, - // }, - // { - // name: "input overflow", - // txFunc: func() *txs.Tx { - // input0 := input - // input0.In = &secp256k1fx.TransferInput{ - // Amt: 1, - // Input: inputSigners, - // } - - // input1 := input - // input1.UTXOID.OutputIndex++ - // input1.In = &secp256k1fx.TransferInput{ - // Amt: math.MaxUint64, - // Input: inputSigners, - // } - - // tx := tx - // tx.Ins = []*avax.TransferableInput{ - // &input0, - // &input1, - // } - // avax.SortTransferableInputsWithSigners(tx.Ins, make([][]*secp256k1.PrivateKey, 2)) - // return &txs.Tx{ - // Unsigned: &tx, - // Creds: []*fxs.FxCredential{ - // &cred, - // &cred, - // }, - // } - // }, - // err: safemath.ErrOverflow, - // }, - // { - // name: "output overflow", - // txFunc: func() *txs.Tx { - // output := output - // output.Out = &secp256k1fx.TransferOutput{ - // Amt: math.MaxUint64, - // OutputOwners: outputOwners, - // } - - // outputs := []*avax.TransferableOutput{ - // &output, - // } - // avax.SortTransferableOutputs(outputs, codec) - - // tx := tx - // tx.Outs = outputs - // return &txs.Tx{ - // Unsigned: &tx, - // Creds: creds, - // } - // }, - // err: safemath.ErrOverflow, - // }, - // { - // name: "insufficient funds", - // txFunc: func() *txs.Tx { - // input := input - // input.In = &secp256k1fx.TransferInput{ - // Amt: 1, - // Input: inputSigners, - // } - - // tx := tx - // tx.Ins = []*avax.TransferableInput{ - // &input, - // } - // return &txs.Tx{ - // Unsigned: &tx, - // Creds: creds, - // } - // }, - // err: avax.ErrInsufficientFunds, - // }, { name: "invalid credential", txFunc: func() *txs.Tx { @@ -2266,46 +1426,6 @@ func TestSyntacticVerifierExportTx(t *testing.T) { }, err: errWrongNumberOfCredentials, }, - // { - // name: "barely sufficient funds", - // txFunc: func() *txs.Tx { - // input := input - // input.In = &secp256k1fx.TransferInput{ - // Amt: fxOutput.Amt + feeConfig.TxFee, - // Input: inputSigners, - // } - - // tx := tx - // tx.Ins = []*avax.TransferableInput{ - // &input, - // } - // return &txs.Tx{ - // Unsigned: &tx, - // Creds: creds, - // } - // }, - // err: nil, - // }, - // { - // name: "barely insufficient funds", - // txFunc: func() *txs.Tx { - // input := input - // input.In = &secp256k1fx.TransferInput{ - // Amt: fxOutput.Amt + feeConfig.TxFee - 1, - // Input: inputSigners, - // } - - // tx := tx - // tx.Ins = []*avax.TransferableInput{ - // &input, - // } - // return &txs.Tx{ - // Unsigned: &tx, - // Creds: creds, - // } - // }, - // err: avax.ErrInsufficientFunds, - // }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { From 3daec3411519365d01497e0e7a920e110b2e245d Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 8 Feb 2024 23:36:17 +0100 Subject: [PATCH 07/27] cleanup --- vms/platformvm/block/builder/builder_test.go | 18 ++--- vms/platformvm/block/builder/helpers_test.go | 58 ++++++++++++++--- .../block/builder/standard_block_test.go | 2 +- vms/platformvm/block/executor/helpers_test.go | 57 +++++++++++++--- .../block/executor/proposal_block_test.go | 16 ++--- .../block/executor/standard_block_test.go | 14 ++-- .../txs/executor/advance_time_test.go | 22 +++---- .../txs/executor/create_chain_test.go | 10 +-- .../txs/executor/create_subnet_test.go | 2 +- vms/platformvm/txs/executor/export_test.go | 2 +- vms/platformvm/txs/executor/helpers_test.go | 65 +++++++++++++------ vms/platformvm/txs/executor/import_test.go | 2 +- .../txs/executor/proposal_tx_executor_test.go | 8 +-- .../txs/executor/reward_validator_test.go | 12 ++-- .../txs/executor/standard_tx_executor_test.go | 14 ++-- vms/platformvm/vm_test.go | 7 +- 16 files changed, 212 insertions(+), 97 deletions(-) diff --git a/vms/platformvm/block/builder/builder_test.go b/vms/platformvm/block/builder/builder_test.go index 56f189cb986..039bcc92b0c 100644 --- a/vms/platformvm/block/builder/builder_test.go +++ b/vms/platformvm/block/builder/builder_test.go @@ -33,7 +33,7 @@ import ( func TestBuildBlockBasic(t *testing.T) { require := require.New(t) - env := newEnvironment(t) + env := newEnvironment(t, durangoFork) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() @@ -75,7 +75,7 @@ func TestBuildBlockBasic(t *testing.T) { func TestBuildBlockDoesNotBuildWithEmptyMempool(t *testing.T) { require := require.New(t) - env := newEnvironment(t) + env := newEnvironment(t, durangoFork) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() @@ -92,7 +92,7 @@ func TestBuildBlockDoesNotBuildWithEmptyMempool(t *testing.T) { func TestBuildBlockShouldReward(t *testing.T) { require := require.New(t) - env := newEnvironment(t) + env := newEnvironment(t, durangoFork) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() @@ -193,7 +193,7 @@ func TestBuildBlockShouldReward(t *testing.T) { func TestBuildBlockAdvanceTime(t *testing.T) { require := require.New(t) - env := newEnvironment(t) + env := newEnvironment(t, durangoFork) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() @@ -226,7 +226,7 @@ func TestBuildBlockAdvanceTime(t *testing.T) { func TestBuildBlockForceAdvanceTime(t *testing.T) { require := require.New(t) - env := newEnvironment(t) + env := newEnvironment(t, durangoFork) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() @@ -280,7 +280,7 @@ func TestBuildBlockForceAdvanceTime(t *testing.T) { func TestBuildBlockDropExpiredStakerTxs(t *testing.T) { require := require.New(t) - env := newEnvironment(t) + env := newEnvironment(t, durangoFork) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() @@ -383,7 +383,7 @@ func TestBuildBlockDropExpiredStakerTxs(t *testing.T) { func TestBuildBlockInvalidStakingDurations(t *testing.T) { require := require.New(t) - env := newEnvironment(t) + env := newEnvironment(t, durangoFork) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() @@ -467,7 +467,7 @@ func TestBuildBlockInvalidStakingDurations(t *testing.T) { func TestPreviouslyDroppedTxsCannotBeReAddedToMempool(t *testing.T) { require := require.New(t) - env := newEnvironment(t) + env := newEnvironment(t, durangoFork) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() @@ -510,7 +510,7 @@ func TestPreviouslyDroppedTxsCannotBeReAddedToMempool(t *testing.T) { func TestNoErrorOnUnexpectedSetPreferenceDuringBootstrapping(t *testing.T) { require := require.New(t) - env := newEnvironment(t) + env := newEnvironment(t, durangoFork) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() diff --git a/vms/platformvm/block/builder/helpers_test.go b/vms/platformvm/block/builder/helpers_test.go index 92892df75ae..27b6573c05f 100644 --- a/vms/platformvm/block/builder/helpers_test.go +++ b/vms/platformvm/block/builder/helpers_test.go @@ -5,6 +5,7 @@ package builder import ( "context" + "fmt" "testing" "time" @@ -58,8 +59,17 @@ import ( const ( defaultWeight = 10000 trackChecksum = false + + apricotPhase3 activeFork = iota + apricotPhase5 + banffFork + cortinaFork + durangoFork + eUpgradeFork ) +type activeFork uint8 + var ( defaultMinStakingDuration = 24 * time.Hour defaultMaxStakingDuration = 365 * 24 * time.Hour @@ -111,12 +121,12 @@ type environment struct { backend txexecutor.Backend } -func newEnvironment(t *testing.T) *environment { +func newEnvironment(t *testing.T, fork activeFork) *environment { //nolint:unparam require := require.New(t) res := &environment{ isBootstrapped: &utils.Atomic[bool]{}, - config: defaultConfig(), + config: defaultConfig(t, fork), clk: defaultClock(), } res.isBootstrapped.Set(true) @@ -293,7 +303,38 @@ func defaultState( return state } -func defaultConfig() *config.Config { +func defaultConfig(t *testing.T, fork activeFork) *config.Config { + var ( + apricotPhase3Time = mockable.MaxTime + apricotPhase5Time = mockable.MaxTime + banffTime = mockable.MaxTime + cortinaTime = mockable.MaxTime + durangoTime = mockable.MaxTime + eUpgradeTime = mockable.MaxTime + ) + + switch fork { + case eUpgradeFork: + eUpgradeTime = time.Time{} // neglecting fork ordering this for package tests + fallthrough + case durangoFork: + durangoTime = time.Time{} // neglecting fork ordering this for package tests + fallthrough + case cortinaFork: + cortinaTime = time.Time{} // neglecting fork ordering this for package tests + fallthrough + case banffFork: + banffTime = time.Time{} // neglecting fork ordering this for package tests + fallthrough + case apricotPhase5: + apricotPhase5Time = defaultValidateEndTime + fallthrough + case apricotPhase3: + apricotPhase3Time = defaultValidateEndTime + default: + require.NoError(t, fmt.Errorf("unhandled fork %d", fork)) + } + return &config.Config{ Chains: chains.TestManager, UptimeLockedCalculator: uptime.NewLockedCalculator(), @@ -312,11 +353,12 @@ func defaultConfig() *config.Config { MintingPeriod: 365 * 24 * time.Hour, SupplyCap: 720 * units.MegaAvax, }, - ApricotPhase3Time: defaultValidateEndTime, - ApricotPhase5Time: defaultValidateEndTime, - BanffTime: time.Time{}, // neglecting fork ordering this for package tests - DurangoTime: time.Time{}, - EUpgradeTime: mockable.MaxTime, + ApricotPhase3Time: apricotPhase3Time, + ApricotPhase5Time: apricotPhase5Time, + BanffTime: banffTime, + CortinaTime: cortinaTime, + DurangoTime: durangoTime, + EUpgradeTime: eUpgradeTime, } } diff --git a/vms/platformvm/block/builder/standard_block_test.go b/vms/platformvm/block/builder/standard_block_test.go index 6064b215311..f286a9191ec 100644 --- a/vms/platformvm/block/builder/standard_block_test.go +++ b/vms/platformvm/block/builder/standard_block_test.go @@ -22,7 +22,7 @@ import ( func TestAtomicTxImports(t *testing.T) { require := require.New(t) - env := newEnvironment(t) + env := newEnvironment(t, durangoFork) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() diff --git a/vms/platformvm/block/executor/helpers_test.go b/vms/platformvm/block/executor/helpers_test.go index 9b98681c44c..26eb69ada86 100644 --- a/vms/platformvm/block/executor/helpers_test.go +++ b/vms/platformvm/block/executor/helpers_test.go @@ -61,8 +61,17 @@ const ( defaultWeight = 10000 trackChecksum = false + + apricotPhase3 activeFork = iota + apricotPhase5 + banffFork + cortinaFork + durangoFork + eUpgradeFork ) +type activeFork uint8 + var ( defaultMinStakingDuration = 24 * time.Hour defaultMaxStakingDuration = 365 * 24 * time.Hour @@ -126,10 +135,10 @@ type environment struct { backend *executor.Backend } -func newEnvironment(t *testing.T, ctrl *gomock.Controller) *environment { +func newEnvironment(t *testing.T, ctrl *gomock.Controller, fork activeFork) *environment { res := &environment{ isBootstrapped: &utils.Atomic[bool]{}, - config: defaultConfig(), + config: defaultConfig(t, fork), clk: defaultClock(), } res.isBootstrapped.Set(true) @@ -321,7 +330,38 @@ func defaultState( return state } -func defaultConfig() *config.Config { +func defaultConfig(t *testing.T, fork activeFork) *config.Config { + var ( + apricotPhase3Time = mockable.MaxTime + apricotPhase5Time = mockable.MaxTime + banffTime = mockable.MaxTime + cortinaTime = mockable.MaxTime + durangoTime = mockable.MaxTime + eUpgradeTime = mockable.MaxTime + ) + + switch fork { + case eUpgradeFork: + eUpgradeTime = time.Time{} // neglecting fork ordering this for package tests + fallthrough + case durangoFork: + durangoTime = time.Time{} // neglecting fork ordering this for package tests + fallthrough + case cortinaFork: + cortinaTime = time.Time{} // neglecting fork ordering this for package tests + fallthrough + case banffFork: + banffTime = time.Time{} // neglecting fork ordering this for package tests + fallthrough + case apricotPhase5: + apricotPhase5Time = defaultValidateEndTime + fallthrough + case apricotPhase3: + apricotPhase3Time = defaultValidateEndTime + default: + require.NoError(t, fmt.Errorf("unhandled fork %d", fork)) + } + return &config.Config{ Chains: chains.TestManager, UptimeLockedCalculator: uptime.NewLockedCalculator(), @@ -340,11 +380,12 @@ func defaultConfig() *config.Config { MintingPeriod: 365 * 24 * time.Hour, SupplyCap: 720 * units.MegaAvax, }, - ApricotPhase3Time: defaultValidateEndTime, - ApricotPhase5Time: defaultValidateEndTime, - BanffTime: mockable.MaxTime, - DurangoTime: mockable.MaxTime, - EUpgradeTime: mockable.MaxTime, + ApricotPhase3Time: apricotPhase3Time, + ApricotPhase5Time: apricotPhase5Time, + BanffTime: banffTime, + DurangoTime: durangoTime, + CortinaTime: cortinaTime, + EUpgradeTime: eUpgradeTime, } } diff --git a/vms/platformvm/block/executor/proposal_block_test.go b/vms/platformvm/block/executor/proposal_block_test.go index 33a3877fc24..7476c4f5772 100644 --- a/vms/platformvm/block/executor/proposal_block_test.go +++ b/vms/platformvm/block/executor/proposal_block_test.go @@ -36,7 +36,7 @@ func TestApricotProposalBlockTimeVerification(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) - env := newEnvironment(t, ctrl) + env := newEnvironment(t, ctrl, apricotPhase5) // create apricotParentBlk. It's a standard one for simplicity parentHeight := uint64(2022) @@ -139,7 +139,7 @@ func TestBanffProposalBlockTimeVerification(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) - env := newEnvironment(t, ctrl) + env := newEnvironment(t, ctrl, banffFork) env.clk.Set(defaultGenesisTime) env.config.BanffTime = time.Time{} // activate Banff env.config.DurangoTime = mockable.MaxTime // deactivate Durango @@ -550,7 +550,7 @@ func TestBanffProposalBlockUpdateStakers(t *testing.T) { for _, test := range tests { t.Run(test.description, func(t *testing.T) { require := require.New(t) - env := newEnvironment(t, nil) + env := newEnvironment(t, nil, banffFork) env.config.BanffTime = time.Time{} // activate Banff subnetID := testSubnet1.ID() @@ -700,7 +700,7 @@ func TestBanffProposalBlockUpdateStakers(t *testing.T) { func TestBanffProposalBlockRemoveSubnetValidator(t *testing.T) { require := require.New(t) - env := newEnvironment(t, nil) + env := newEnvironment(t, nil, banffFork) env.config.BanffTime = time.Time{} // activate Banff subnetID := testSubnet1.ID() @@ -840,7 +840,7 @@ func TestBanffProposalBlockTrackedSubnet(t *testing.T) { for _, tracked := range []bool{true, false} { t.Run(fmt.Sprintf("tracked %t", tracked), func(ts *testing.T) { require := require.New(t) - env := newEnvironment(t, nil) + env := newEnvironment(t, nil, banffFork) env.config.BanffTime = time.Time{} // activate Banff subnetID := testSubnet1.ID() @@ -943,7 +943,7 @@ func TestBanffProposalBlockTrackedSubnet(t *testing.T) { func TestBanffProposalBlockDelegatorStakerWeight(t *testing.T) { require := require.New(t) - env := newEnvironment(t, nil) + env := newEnvironment(t, nil, banffFork) env.config.BanffTime = time.Time{} // activate Banff // Case: Timestamp is after next validator start time @@ -1125,7 +1125,7 @@ func TestBanffProposalBlockDelegatorStakerWeight(t *testing.T) { func TestBanffProposalBlockDelegatorStakers(t *testing.T) { require := require.New(t) - env := newEnvironment(t, nil) + env := newEnvironment(t, nil, banffFork) env.config.BanffTime = time.Time{} // activate Banff // Case: Timestamp is after next validator start time @@ -1307,7 +1307,7 @@ func TestBanffProposalBlockDelegatorStakers(t *testing.T) { func TestAddValidatorProposalBlock(t *testing.T) { require := require.New(t) - env := newEnvironment(t, nil) + env := newEnvironment(t, nil, apricotPhase5) env.config.BanffTime = time.Time{} // activate Banff env.config.DurangoTime = time.Time{} // activate Durango diff --git a/vms/platformvm/block/executor/standard_block_test.go b/vms/platformvm/block/executor/standard_block_test.go index 3e0122c9123..54b45b0ab7c 100644 --- a/vms/platformvm/block/executor/standard_block_test.go +++ b/vms/platformvm/block/executor/standard_block_test.go @@ -30,7 +30,7 @@ func TestApricotStandardBlockTimeVerification(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) - env := newEnvironment(t, ctrl) + env := newEnvironment(t, ctrl, apricotPhase5) // setup and store parent block // it's a standard block for simplicity @@ -83,7 +83,7 @@ func TestBanffStandardBlockTimeVerification(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) - env := newEnvironment(t, ctrl) + env := newEnvironment(t, ctrl, banffFork) now := env.clk.Time() env.clk.Set(now) env.config.BanffTime = time.Time{} // activate Banff @@ -291,7 +291,7 @@ func TestBanffStandardBlockTimeVerification(t *testing.T) { func TestBanffStandardBlockUpdatePrimaryNetworkStakers(t *testing.T) { require := require.New(t) - env := newEnvironment(t, nil) + env := newEnvironment(t, nil, banffFork) env.config.BanffTime = time.Time{} // activate Banff // Case: Timestamp is after next validator start time @@ -493,7 +493,7 @@ func TestBanffStandardBlockUpdateStakers(t *testing.T) { for _, test := range tests { t.Run(test.description, func(t *testing.T) { require := require.New(t) - env := newEnvironment(t, nil) + env := newEnvironment(t, nil, banffFork) env.config.BanffTime = time.Time{} // activate Banff subnetID := testSubnet1.ID() @@ -592,7 +592,7 @@ func TestBanffStandardBlockUpdateStakers(t *testing.T) { // is after the new timestamp func TestBanffStandardBlockRemoveSubnetValidator(t *testing.T) { require := require.New(t) - env := newEnvironment(t, nil) + env := newEnvironment(t, nil, banffFork) env.config.BanffTime = time.Time{} // activate Banff subnetID := testSubnet1.ID() @@ -688,7 +688,7 @@ func TestBanffStandardBlockTrackedSubnet(t *testing.T) { for _, tracked := range []bool{true, false} { t.Run(fmt.Sprintf("tracked %t", tracked), func(t *testing.T) { require := require.New(t) - env := newEnvironment(t, nil) + env := newEnvironment(t, nil, banffFork) env.config.BanffTime = time.Time{} // activate Banff subnetID := testSubnet1.ID() @@ -748,7 +748,7 @@ func TestBanffStandardBlockTrackedSubnet(t *testing.T) { func TestBanffStandardBlockDelegatorStakerWeight(t *testing.T) { require := require.New(t) - env := newEnvironment(t, nil) + env := newEnvironment(t, nil, banffFork) env.config.BanffTime = time.Time{} // activate Banff // Case: Timestamp is after next validator start time diff --git a/vms/platformvm/txs/executor/advance_time_test.go b/vms/platformvm/txs/executor/advance_time_test.go index b7b636ad6db..eaab7ca0f04 100644 --- a/vms/platformvm/txs/executor/advance_time_test.go +++ b/vms/platformvm/txs/executor/advance_time_test.go @@ -34,7 +34,7 @@ func newAdvanceTimeTx(t testing.TB, timestamp time.Time) (*txs.Tx, error) { // for the primary network func TestAdvanceTimeTxUpdatePrimaryNetworkStakers(t *testing.T) { require := require.New(t) - env := newEnvironment(t, false /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, apricotPhase5) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() dummyHeight := uint64(1) @@ -97,7 +97,7 @@ func TestAdvanceTimeTxUpdatePrimaryNetworkStakers(t *testing.T) { // Ensure semantic verification fails when proposed timestamp is at or before current timestamp func TestAdvanceTimeTxTimestampTooEarly(t *testing.T) { require := require.New(t) - env := newEnvironment(t, false /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, apricotPhase5) tx, err := newAdvanceTimeTx(t, env.state.GetTimestamp()) require.NoError(err) @@ -121,7 +121,7 @@ func TestAdvanceTimeTxTimestampTooEarly(t *testing.T) { // Ensure semantic verification fails when proposed timestamp is after next validator set change time func TestAdvanceTimeTxTimestampTooLate(t *testing.T) { require := require.New(t) - env := newEnvironment(t, false /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, apricotPhase5) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() @@ -154,7 +154,7 @@ func TestAdvanceTimeTxTimestampTooLate(t *testing.T) { } // Case: Timestamp is after next validator end time - env = newEnvironment(t, false /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + env = newEnvironment(t, apricotPhase5) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() @@ -354,7 +354,7 @@ func TestAdvanceTimeTxUpdateStakers(t *testing.T) { for _, test := range tests { t.Run(test.description, func(t *testing.T) { require := require.New(t) - env := newEnvironment(t, false /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, apricotPhase5) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() @@ -457,7 +457,7 @@ func TestAdvanceTimeTxUpdateStakers(t *testing.T) { // is after the new timestamp func TestAdvanceTimeTxRemoveSubnetValidator(t *testing.T) { require := require.New(t) - env := newEnvironment(t, false /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, apricotPhase5) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() @@ -559,7 +559,7 @@ func TestTrackedSubnet(t *testing.T) { for _, tracked := range []bool{true, false} { t.Run(fmt.Sprintf("tracked %t", tracked), func(t *testing.T) { require := require.New(t) - env := newEnvironment(t, false /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, apricotPhase5) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() dummyHeight := uint64(1) @@ -627,7 +627,7 @@ func TestTrackedSubnet(t *testing.T) { func TestAdvanceTimeTxDelegatorStakerWeight(t *testing.T) { require := require.New(t) - env := newEnvironment(t, false /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, apricotPhase5) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() dummyHeight := uint64(1) @@ -732,7 +732,7 @@ func TestAdvanceTimeTxDelegatorStakerWeight(t *testing.T) { func TestAdvanceTimeTxDelegatorStakers(t *testing.T) { require := require.New(t) - env := newEnvironment(t, false /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, apricotPhase5) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() dummyHeight := uint64(1) @@ -826,7 +826,7 @@ func TestAdvanceTimeTxDelegatorStakers(t *testing.T) { func TestAdvanceTimeTxAfterBanff(t *testing.T) { require := require.New(t) - env := newEnvironment(t, false /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, apricotPhase5) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() env.clk.Set(defaultGenesisTime) // VM's clock reads the genesis time @@ -858,7 +858,7 @@ func TestAdvanceTimeTxAfterBanff(t *testing.T) { // Ensure marshaling/unmarshaling works func TestAdvanceTimeTxUnmarshal(t *testing.T) { require := require.New(t) - env := newEnvironment(t, false /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, apricotPhase5) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() diff --git a/vms/platformvm/txs/executor/create_chain_test.go b/vms/platformvm/txs/executor/create_chain_test.go index 0342c8dc1cf..bfb8097382d 100644 --- a/vms/platformvm/txs/executor/create_chain_test.go +++ b/vms/platformvm/txs/executor/create_chain_test.go @@ -25,7 +25,7 @@ import ( // Ensure Execute fails when there are not enough control sigs func TestCreateChainTxInsufficientControlSigs(t *testing.T) { require := require.New(t) - env := newEnvironment(t, true /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, banffFork) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() @@ -58,7 +58,7 @@ func TestCreateChainTxInsufficientControlSigs(t *testing.T) { // Ensure Execute fails when an incorrect control signature is given func TestCreateChainTxWrongControlSig(t *testing.T) { require := require.New(t) - env := newEnvironment(t, true /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, banffFork) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() @@ -98,7 +98,7 @@ func TestCreateChainTxWrongControlSig(t *testing.T) { // its validator set doesn't exist func TestCreateChainTxNoSuchSubnet(t *testing.T) { require := require.New(t) - env := newEnvironment(t, true /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, banffFork) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() @@ -130,7 +130,7 @@ func TestCreateChainTxNoSuchSubnet(t *testing.T) { // Ensure valid tx passes semanticVerify func TestCreateChainTxValid(t *testing.T) { require := require.New(t) - env := newEnvironment(t, true /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, banffFork) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() @@ -187,7 +187,7 @@ func TestCreateChainTxAP3FeeChange(t *testing.T) { t.Run(test.name, func(t *testing.T) { require := require.New(t) - env := newEnvironment(t, true /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, banffFork) env.config.ApricotPhase3Time = ap3Time ins, outs, _, signers, err := env.utxosHandler.Spend(env.state, preFundedKeys, 0, test.fee, ids.ShortEmpty) diff --git a/vms/platformvm/txs/executor/create_subnet_test.go b/vms/platformvm/txs/executor/create_subnet_test.go index 6d968daa4df..a2d59281cc6 100644 --- a/vms/platformvm/txs/executor/create_subnet_test.go +++ b/vms/platformvm/txs/executor/create_subnet_test.go @@ -49,7 +49,7 @@ func TestCreateSubnetTxAP3FeeChange(t *testing.T) { t.Run(test.name, func(t *testing.T) { require := require.New(t) - env := newEnvironment(t, false /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, apricotPhase5) env.config.ApricotPhase3Time = ap3Time env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() diff --git a/vms/platformvm/txs/executor/export_test.go b/vms/platformvm/txs/executor/export_test.go index d9e0ce07100..12aa12de33e 100644 --- a/vms/platformvm/txs/executor/export_test.go +++ b/vms/platformvm/txs/executor/export_test.go @@ -15,7 +15,7 @@ import ( ) func TestNewExportTx(t *testing.T) { - env := newEnvironment(t, true /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, banffFork) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() diff --git a/vms/platformvm/txs/executor/helpers_test.go b/vms/platformvm/txs/executor/helpers_test.go index 3d6683529cc..2975d4739f5 100644 --- a/vms/platformvm/txs/executor/helpers_test.go +++ b/vms/platformvm/txs/executor/helpers_test.go @@ -51,8 +51,17 @@ import ( const ( defaultWeight = 5 * units.MilliAvax trackChecksum = false + + apricotPhase3 activeFork = iota + apricotPhase5 + banffFork + cortinaFork + durangoFork + eUpgradeFork ) +type activeFork uint8 + var ( defaultMinStakingDuration = 24 * time.Hour defaultMaxStakingDuration = 365 * 24 * time.Hour @@ -112,12 +121,12 @@ func (e *environment) SetState(blkID ids.ID, chainState state.Chain) { e.states[blkID] = chainState } -func newEnvironment(t *testing.T, postBanff, postCortina, postDurango bool) *environment { +func newEnvironment(t *testing.T, fork activeFork) *environment { var isBootstrapped utils.Atomic[bool] isBootstrapped.Set(true) - config := defaultConfig(postBanff, postCortina, postDurango) - clk := defaultClock(postBanff || postCortina || postDurango) + config := defaultConfig(t, fork) + clk := defaultClock(fork) baseDB := versiondb.New(memdb.New()) ctx := snowtest.Context(t, snowtest.PChainID) @@ -271,18 +280,36 @@ func defaultState( return state } -func defaultConfig(postBanff, postCortina, postDurango bool) *config.Config { - banffTime := mockable.MaxTime - if postBanff { - banffTime = defaultValidateEndTime.Add(-2 * time.Second) - } - cortinaTime := mockable.MaxTime - if postCortina { - cortinaTime = defaultValidateStartTime.Add(-2 * time.Second) - } - durangoTime := mockable.MaxTime - if postDurango { +func defaultConfig(t *testing.T, fork activeFork) *config.Config { + var ( + apricotPhase3Time = mockable.MaxTime + apricotPhase5Time = mockable.MaxTime + banffTime = mockable.MaxTime + cortinaTime = mockable.MaxTime + durangoTime = mockable.MaxTime + eUpgradeTime = mockable.MaxTime + ) + + switch fork { + case eUpgradeFork: + eUpgradeTime = defaultValidateStartTime.Add(-2 * time.Second) + fallthrough + case durangoFork: durangoTime = defaultValidateStartTime.Add(-2 * time.Second) + fallthrough + case cortinaFork: + cortinaTime = defaultValidateStartTime.Add(-2 * time.Second) + fallthrough + case banffFork: + banffTime = defaultValidateStartTime.Add(-2 * time.Second) + fallthrough + case apricotPhase5: + apricotPhase5Time = defaultValidateEndTime + fallthrough + case apricotPhase3: + apricotPhase3Time = defaultValidateEndTime + default: + require.NoError(t, fmt.Errorf("unhandled fork %d", fork)) } return &config.Config{ @@ -303,18 +330,18 @@ func defaultConfig(postBanff, postCortina, postDurango bool) *config.Config { MintingPeriod: 365 * 24 * time.Hour, SupplyCap: 720 * units.MegaAvax, }, - ApricotPhase3Time: defaultValidateEndTime, - ApricotPhase5Time: defaultValidateEndTime, + ApricotPhase3Time: apricotPhase3Time, + ApricotPhase5Time: apricotPhase5Time, BanffTime: banffTime, CortinaTime: cortinaTime, DurangoTime: durangoTime, - EUpgradeTime: mockable.MaxTime, + EUpgradeTime: eUpgradeTime, } } -func defaultClock(postFork bool) *mockable.Clock { +func defaultClock(fork activeFork) *mockable.Clock { now := defaultGenesisTime - if postFork { + if fork == eUpgradeFork || fork == durangoFork || fork == cortinaFork || fork == banffFork { // 1 second after Banff fork now = defaultValidateEndTime.Add(-2 * time.Second) } diff --git a/vms/platformvm/txs/executor/import_test.go b/vms/platformvm/txs/executor/import_test.go index fed09bd882c..9f1c90dab50 100644 --- a/vms/platformvm/txs/executor/import_test.go +++ b/vms/platformvm/txs/executor/import_test.go @@ -22,7 +22,7 @@ import ( ) func TestNewImportTx(t *testing.T) { - env := newEnvironment(t, false /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, apricotPhase5) type test struct { description string diff --git a/vms/platformvm/txs/executor/proposal_tx_executor_test.go b/vms/platformvm/txs/executor/proposal_tx_executor_test.go index e01bd267a02..d16e072a3a1 100644 --- a/vms/platformvm/txs/executor/proposal_tx_executor_test.go +++ b/vms/platformvm/txs/executor/proposal_tx_executor_test.go @@ -91,7 +91,7 @@ func TestProposalTxExecuteAddDelegator(t *testing.T) { require.NoError(t, target.state.Commit()) } - dummyH := newEnvironment(t, false /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + dummyH := newEnvironment(t, apricotPhase5) currentTimestamp := dummyH.state.GetTimestamp() type test struct { @@ -245,7 +245,7 @@ func TestProposalTxExecuteAddDelegator(t *testing.T) { for _, tt := range tests { t.Run(tt.description, func(t *testing.T) { require := require.New(t) - freshTH := newEnvironment(t, false /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + freshTH := newEnvironment(t, apricotPhase5) freshTH.config.ApricotPhase3Time = tt.AP3Time tx, err := freshTH.txBuilder.NewAddDelegatorTx( @@ -283,7 +283,7 @@ func TestProposalTxExecuteAddDelegator(t *testing.T) { func TestProposalTxExecuteAddSubnetValidator(t *testing.T) { require := require.New(t) - env := newEnvironment(t, false /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, apricotPhase5) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() @@ -716,7 +716,7 @@ func TestProposalTxExecuteAddSubnetValidator(t *testing.T) { func TestProposalTxExecuteAddValidator(t *testing.T) { require := require.New(t) - env := newEnvironment(t, false /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, apricotPhase5) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() diff --git a/vms/platformvm/txs/executor/reward_validator_test.go b/vms/platformvm/txs/executor/reward_validator_test.go index 18ba653a4e7..c9aa34f207d 100644 --- a/vms/platformvm/txs/executor/reward_validator_test.go +++ b/vms/platformvm/txs/executor/reward_validator_test.go @@ -35,7 +35,7 @@ func newRewardValidatorTx(t testing.TB, txID ids.ID) (*txs.Tx, error) { func TestRewardValidatorTxExecuteOnCommit(t *testing.T) { require := require.New(t) - env := newEnvironment(t, false /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, apricotPhase5) dummyHeight := uint64(1) currentStakerIterator, err := env.state.GetCurrentStakerIterator() @@ -135,7 +135,7 @@ func TestRewardValidatorTxExecuteOnCommit(t *testing.T) { func TestRewardValidatorTxExecuteOnAbort(t *testing.T) { require := require.New(t) - env := newEnvironment(t, false /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, apricotPhase5) dummyHeight := uint64(1) currentStakerIterator, err := env.state.GetCurrentStakerIterator() @@ -229,7 +229,7 @@ func TestRewardValidatorTxExecuteOnAbort(t *testing.T) { func TestRewardDelegatorTxExecuteOnCommitPreDelegateeDeferral(t *testing.T) { require := require.New(t) - env := newEnvironment(t, false /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, apricotPhase5) dummyHeight := uint64(1) vdrRewardAddress := ids.GenerateTestShortID() @@ -350,7 +350,7 @@ func TestRewardDelegatorTxExecuteOnCommitPreDelegateeDeferral(t *testing.T) { func TestRewardDelegatorTxExecuteOnCommitPostDelegateeDeferral(t *testing.T) { require := require.New(t) - env := newEnvironment(t, true /*=postBanff*/, true /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, cortinaFork) dummyHeight := uint64(1) vdrRewardAddress := ids.GenerateTestShortID() @@ -566,7 +566,7 @@ func TestRewardDelegatorTxExecuteOnCommitPostDelegateeDeferral(t *testing.T) { func TestRewardDelegatorTxAndValidatorTxExecuteOnCommitPostDelegateeDeferral(t *testing.T) { require := require.New(t) - env := newEnvironment(t, true /*=postBanff*/, true /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, cortinaFork) dummyHeight := uint64(1) vdrRewardAddress := ids.GenerateTestShortID() @@ -725,7 +725,7 @@ func TestRewardDelegatorTxAndValidatorTxExecuteOnCommitPostDelegateeDeferral(t * func TestRewardDelegatorTxExecuteOnAbort(t *testing.T) { require := require.New(t) - env := newEnvironment(t, false /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, apricotPhase5) dummyHeight := uint64(1) initialSupply, err := env.state.GetCurrentSupply(constants.PrimaryNetworkID) diff --git a/vms/platformvm/txs/executor/standard_tx_executor_test.go b/vms/platformvm/txs/executor/standard_tx_executor_test.go index 6fd7fd0bc1f..211bc742409 100644 --- a/vms/platformvm/txs/executor/standard_tx_executor_test.go +++ b/vms/platformvm/txs/executor/standard_tx_executor_test.go @@ -46,7 +46,7 @@ var errTest = errors.New("non-nil error") func TestStandardTxExecutorAddValidatorTxEmptyID(t *testing.T) { require := require.New(t) - env := newEnvironment(t, false /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, apricotPhase5) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() @@ -168,7 +168,7 @@ func TestStandardTxExecutorAddDelegator(t *testing.T) { require.NoError(t, target.state.Commit()) } - dummyH := newEnvironment(t, false /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + dummyH := newEnvironment(t, apricotPhase5) currentTimestamp := dummyH.state.GetTimestamp() type test struct { @@ -322,7 +322,7 @@ func TestStandardTxExecutorAddDelegator(t *testing.T) { for _, tt := range tests { t.Run(tt.description, func(t *testing.T) { require := require.New(t) - freshTH := newEnvironment(t, false /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + freshTH := newEnvironment(t, apricotPhase5) freshTH.config.ApricotPhase3Time = tt.AP3Time tx, err := freshTH.txBuilder.NewAddDelegatorTx( @@ -358,7 +358,7 @@ func TestStandardTxExecutorAddDelegator(t *testing.T) { func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { require := require.New(t) - env := newEnvironment(t, false /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, apricotPhase5) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() @@ -785,7 +785,7 @@ func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { func TestBanffStandardTxExecutorAddValidator(t *testing.T) { require := require.New(t) - env := newEnvironment(t, true /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) + env := newEnvironment(t, banffFork) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() @@ -1068,7 +1068,7 @@ func TestDurangoDisabledTransactions(t *testing.T) { t.Run(tt.name, func(t *testing.T) { require := require.New(t) - env := newEnvironment(t, true /*=postBanff*/, true /*=postCortina*/, true /*=postDurango*/) + env := newEnvironment(t, durangoFork) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() @@ -1592,7 +1592,7 @@ func TestDurangoMemoField(t *testing.T) { t.Run(tt.name, func(t *testing.T) { require := require.New(t) - env := newEnvironment(t, true /*=postBanff*/, true /*=postCortina*/, true /*=postDurango*/) + env := newEnvironment(t, durangoFork) env.ctx.Lock.Lock() defer env.ctx.Lock.Unlock() diff --git a/vms/platformvm/vm_test.go b/vms/platformvm/vm_test.go index 94e158582cc..ea0e213d6ef 100644 --- a/vms/platformvm/vm_test.go +++ b/vms/platformvm/vm_test.go @@ -80,6 +80,7 @@ const ( banffFork cortinaFork durangoFork + eUpgradeFork latestFork activeFork = durangoFork @@ -210,12 +211,16 @@ func defaultVM(t *testing.T, fork activeFork) (*VM, database.Database, *mutableS banffTime = mockable.MaxTime cortinaTime = mockable.MaxTime durangoTime = mockable.MaxTime + eUpgradeTime = mockable.MaxTime ) // always reset latestForkTime (a package level variable) // to ensure test independence latestForkTime = defaultGenesisTime.Add(time.Second) switch fork { + case eUpgradeFork: + eUpgradeTime = latestForkTime + fallthrough case durangoFork: durangoTime = latestForkTime fallthrough @@ -254,7 +259,7 @@ func defaultVM(t *testing.T, fork activeFork) (*VM, database.Database, *mutableS BanffTime: banffTime, CortinaTime: cortinaTime, DurangoTime: durangoTime, - EUpgradeTime: mockable.MaxTime, + EUpgradeTime: eUpgradeTime, }} db := memdb.New() From ccb05f58d4095028000e036accc83074dba08f5b Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Tue, 13 Feb 2024 09:52:41 +0100 Subject: [PATCH 08/27] appease linter --- .../txs/executor/semantic_verifier_test.go | 50 +++++++++---------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/vms/avm/txs/executor/semantic_verifier_test.go b/vms/avm/txs/executor/semantic_verifier_test.go index 168ab593cc9..df60f656f9f 100644 --- a/vms/avm/txs/executor/semantic_verifier_test.go +++ b/vms/avm/txs/executor/semantic_verifier_test.go @@ -169,7 +169,7 @@ func TestSemanticVerifierBaseTx(t *testing.T) { }, { name: "invalid output", - stateFunc: func(ctrl *gomock.Controller) state.Chain { + stateFunc: func(*gomock.Controller) state.Chain { return nil }, txFunc: func(require *require.Assertions) *txs.Tx { @@ -197,7 +197,7 @@ func TestSemanticVerifierBaseTx(t *testing.T) { }, { name: "unsorted outputs", - stateFunc: func(ctrl *gomock.Controller) state.Chain { + stateFunc: func(*gomock.Controller) state.Chain { return nil }, txFunc: func(require *require.Assertions) *txs.Tx { @@ -236,7 +236,7 @@ func TestSemanticVerifierBaseTx(t *testing.T) { }, { name: "invalid input", - stateFunc: func(ctrl *gomock.Controller) state.Chain { + stateFunc: func(*gomock.Controller) state.Chain { return nil }, txFunc: func(require *require.Assertions) *txs.Tx { @@ -264,7 +264,7 @@ func TestSemanticVerifierBaseTx(t *testing.T) { }, { name: "duplicate inputs", - stateFunc: func(ctrl *gomock.Controller) state.Chain { + stateFunc: func(*gomock.Controller) state.Chain { return nil }, txFunc: func(require *require.Assertions) *txs.Tx { @@ -288,7 +288,7 @@ func TestSemanticVerifierBaseTx(t *testing.T) { }, { name: "input overflow", - stateFunc: func(ctrl *gomock.Controller) state.Chain { + stateFunc: func(*gomock.Controller) state.Chain { return nil }, txFunc: func(require *require.Assertions) *txs.Tx { @@ -325,7 +325,7 @@ func TestSemanticVerifierBaseTx(t *testing.T) { }, { name: "output overflow", - stateFunc: func(ctrl *gomock.Controller) state.Chain { + stateFunc: func(*gomock.Controller) state.Chain { return nil }, txFunc: func(require *require.Assertions) *txs.Tx { @@ -407,7 +407,7 @@ func TestSemanticVerifierBaseTx(t *testing.T) { }, { name: "insufficient funds", - stateFunc: func(ctrl *gomock.Controller) state.Chain { + stateFunc: func(*gomock.Controller) state.Chain { return nil }, txFunc: func(require *require.Assertions) *txs.Tx { @@ -435,7 +435,7 @@ func TestSemanticVerifierBaseTx(t *testing.T) { }, { name: "barely insufficient funds", - stateFunc: func(ctrl *gomock.Controller) state.Chain { + stateFunc: func(*gomock.Controller) state.Chain { return nil }, txFunc: func(require *require.Assertions) *txs.Tx { @@ -854,7 +854,7 @@ func TestSemanticVerifierExportTx(t *testing.T) { }, { name: "invalid output", - stateFunc: func(ctrl *gomock.Controller) state.Chain { + stateFunc: func(*gomock.Controller) state.Chain { return nil }, txFunc: func(require *require.Assertions) *txs.Tx { @@ -884,7 +884,7 @@ func TestSemanticVerifierExportTx(t *testing.T) { }, { name: "unsorted outputs", - stateFunc: func(ctrl *gomock.Controller) state.Chain { + stateFunc: func(*gomock.Controller) state.Chain { return nil }, txFunc: func(require *require.Assertions) *txs.Tx { @@ -925,7 +925,7 @@ func TestSemanticVerifierExportTx(t *testing.T) { }, { name: "unsorted exported outputs", - stateFunc: func(ctrl *gomock.Controller) state.Chain { + stateFunc: func(*gomock.Controller) state.Chain { return nil }, txFunc: func(require *require.Assertions) *txs.Tx { @@ -963,7 +963,7 @@ func TestSemanticVerifierExportTx(t *testing.T) { }, { name: "invalid input", - stateFunc: func(ctrl *gomock.Controller) state.Chain { + stateFunc: func(*gomock.Controller) state.Chain { return nil }, txFunc: func(require *require.Assertions) *txs.Tx { @@ -993,7 +993,7 @@ func TestSemanticVerifierExportTx(t *testing.T) { }, { name: "duplicate inputs", - stateFunc: func(ctrl *gomock.Controller) state.Chain { + stateFunc: func(*gomock.Controller) state.Chain { return nil }, txFunc: func(require *require.Assertions) *txs.Tx { @@ -1019,7 +1019,7 @@ func TestSemanticVerifierExportTx(t *testing.T) { }, { name: "input overflow", - stateFunc: func(ctrl *gomock.Controller) state.Chain { + stateFunc: func(*gomock.Controller) state.Chain { return nil }, txFunc: func(require *require.Assertions) *txs.Tx { @@ -1058,7 +1058,7 @@ func TestSemanticVerifierExportTx(t *testing.T) { }, { name: "output overflow", - stateFunc: func(ctrl *gomock.Controller) state.Chain { + stateFunc: func(*gomock.Controller) state.Chain { return nil }, txFunc: func(require *require.Assertions) *txs.Tx { @@ -1144,7 +1144,7 @@ func TestSemanticVerifierExportTx(t *testing.T) { }, { name: "insufficient funds", - stateFunc: func(ctrl *gomock.Controller) state.Chain { + stateFunc: func(*gomock.Controller) state.Chain { return nil }, txFunc: func(require *require.Assertions) *txs.Tx { @@ -1174,7 +1174,7 @@ func TestSemanticVerifierExportTx(t *testing.T) { }, { name: "barely insufficient funds", - stateFunc: func(ctrl *gomock.Controller) state.Chain { + stateFunc: func(*gomock.Controller) state.Chain { return nil }, txFunc: func(require *require.Assertions) *txs.Tx { @@ -1744,7 +1744,7 @@ func TestSemanticVerifierImportTx(t *testing.T) { }, { name: "invalid output", - stateFunc: func(c *gomock.Controller) state.Chain { + stateFunc: func(*gomock.Controller) state.Chain { return nil }, txFunc: func(require *require.Assertions) *txs.Tx { @@ -1772,7 +1772,7 @@ func TestSemanticVerifierImportTx(t *testing.T) { }, { name: "unsorted outputs", - stateFunc: func(c *gomock.Controller) state.Chain { + stateFunc: func(*gomock.Controller) state.Chain { return nil }, txFunc: func(require *require.Assertions) *txs.Tx { @@ -1810,7 +1810,7 @@ func TestSemanticVerifierImportTx(t *testing.T) { }, { name: "invalid input", - stateFunc: func(c *gomock.Controller) state.Chain { + stateFunc: func(*gomock.Controller) state.Chain { return nil }, txFunc: func(require *require.Assertions) *txs.Tx { @@ -1837,7 +1837,7 @@ func TestSemanticVerifierImportTx(t *testing.T) { }, { name: "duplicate inputs", - stateFunc: func(c *gomock.Controller) state.Chain { + stateFunc: func(*gomock.Controller) state.Chain { return nil }, txFunc: func(require *require.Assertions) *txs.Tx { @@ -1860,7 +1860,7 @@ func TestSemanticVerifierImportTx(t *testing.T) { }, { name: "duplicate imported inputs", - stateFunc: func(c *gomock.Controller) state.Chain { + stateFunc: func(*gomock.Controller) state.Chain { return nil }, txFunc: func(require *require.Assertions) *txs.Tx { @@ -1882,7 +1882,7 @@ func TestSemanticVerifierImportTx(t *testing.T) { }, { name: "input overflow", - stateFunc: func(c *gomock.Controller) state.Chain { + stateFunc: func(*gomock.Controller) state.Chain { return nil }, txFunc: func(require *require.Assertions) *txs.Tx { @@ -1918,7 +1918,7 @@ func TestSemanticVerifierImportTx(t *testing.T) { }, { name: "output overflow", - stateFunc: func(c *gomock.Controller) state.Chain { + stateFunc: func(*gomock.Controller) state.Chain { return nil }, txFunc: func(require *require.Assertions) *txs.Tx { @@ -1948,7 +1948,7 @@ func TestSemanticVerifierImportTx(t *testing.T) { }, { name: "insufficient funds", - stateFunc: func(c *gomock.Controller) state.Chain { + stateFunc: func(*gomock.Controller) state.Chain { return nil }, txFunc: func(require *require.Assertions) *txs.Tx { From a4b81e65e4757932d7add5bad19c5c275bff1fdf Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Tue, 20 Feb 2024 09:22:54 +0100 Subject: [PATCH 09/27] fork switch to the avm --- vms/avm/block/executor/block_test.go | 127 +++++------------- vms/avm/block/executor/manager_test.go | 27 +--- vms/avm/environment_test.go | 45 ++++++- vms/avm/index_test.go | 26 +--- vms/avm/service_test.go | 63 +++------ vms/avm/state_test.go | 3 + vms/avm/vm_benchmark_test.go | 3 +- vms/avm/vm_regression_test.go | 10 +- vms/avm/vm_test.go | 40 ++---- vms/avm/wallet_service_test.go | 1 + vms/platformvm/block/builder/helpers_test.go | 2 +- vms/platformvm/block/executor/helpers_test.go | 2 +- vms/platformvm/txs/executor/helpers_test.go | 2 +- vms/platformvm/vm_test.go | 2 +- 14 files changed, 122 insertions(+), 231 deletions(-) diff --git a/vms/avm/block/executor/block_test.go b/vms/avm/block/executor/block_test.go index 59200e5d88c..8b2e85a8378 100644 --- a/vms/avm/block/executor/block_test.go +++ b/vms/avm/block/executor/block_test.go @@ -30,6 +30,13 @@ import ( "github.com/ava-labs/avalanchego/vms/avm/txs/mempool" ) +var noFeesTestConfig = &config.Config{ + DurangoTime: time.Time{}, + EUpgradeTime: mockable.MaxTime, + TxFee: 0, + CreateAssetTxFee: 0, +} + func TestBlockVerify(t *testing.T) { type test struct { name string @@ -47,10 +54,7 @@ func TestBlockVerify(t *testing.T) { Block: mockBlock, manager: &manager{ backend: &executor.Backend{ - Config: &config.Config{ - DurangoTime: time.Time{}, - EUpgradeTime: mockable.MaxTime, - }, + Config: noFeesTestConfig, }, blkIDToState: map[ids.ID]*blockState{}, }, @@ -72,10 +76,7 @@ func TestBlockVerify(t *testing.T) { Block: mockBlock, manager: &manager{ backend: &executor.Backend{ - Config: &config.Config{ - DurangoTime: time.Time{}, - EUpgradeTime: mockable.MaxTime, - }, + Config: noFeesTestConfig, }, }, } @@ -97,10 +98,7 @@ func TestBlockVerify(t *testing.T) { Block: mockBlock, manager: &manager{ backend: &executor.Backend{ - Config: &config.Config{ - DurangoTime: time.Time{}, - EUpgradeTime: mockable.MaxTime, - }, + Config: noFeesTestConfig, }, clk: clk, }, @@ -120,10 +118,7 @@ func TestBlockVerify(t *testing.T) { Block: mockBlock, manager: &manager{ backend: &executor.Backend{ - Config: &config.Config{ - DurangoTime: time.Time{}, - EUpgradeTime: mockable.MaxTime, - }, + Config: noFeesTestConfig, }, blkIDToState: map[ids.ID]*blockState{}, clk: &mockable.Clock{}, @@ -152,10 +147,7 @@ func TestBlockVerify(t *testing.T) { Block: mockBlock, manager: &manager{ backend: &executor.Backend{ - Config: &config.Config{ - DurangoTime: time.Time{}, - EUpgradeTime: mockable.MaxTime, - }, + Config: noFeesTestConfig, }, mempool: mempool, metrics: metrics.NewMockMetrics(ctrl), @@ -190,10 +182,7 @@ func TestBlockVerify(t *testing.T) { Block: mockBlock, manager: &manager{ backend: &executor.Backend{ - Config: &config.Config{ - DurangoTime: time.Time{}, - EUpgradeTime: mockable.MaxTime, - }, + Config: noFeesTestConfig, }, state: mockState, blkIDToState: map[ids.ID]*blockState{}, @@ -232,10 +221,7 @@ func TestBlockVerify(t *testing.T) { Block: mockBlock, manager: &manager{ backend: &executor.Backend{ - Config: &config.Config{ - DurangoTime: time.Time{}, - EUpgradeTime: mockable.MaxTime, - }, + Config: noFeesTestConfig, }, state: mockState, blkIDToState: map[ids.ID]*blockState{}, @@ -277,10 +263,7 @@ func TestBlockVerify(t *testing.T) { Block: mockBlock, manager: &manager{ backend: &executor.Backend{ - Config: &config.Config{ - DurangoTime: time.Time{}, - EUpgradeTime: mockable.MaxTime, - }, + Config: noFeesTestConfig, }, blkIDToState: map[ids.ID]*blockState{ parentID: { @@ -330,10 +313,7 @@ func TestBlockVerify(t *testing.T) { Block: mockBlock, manager: &manager{ backend: &executor.Backend{ - Config: &config.Config{ - DurangoTime: time.Time{}, - EUpgradeTime: mockable.MaxTime, - }, + Config: noFeesTestConfig, }, mempool: mempool, metrics: metrics.NewMockMetrics(ctrl), @@ -388,10 +368,7 @@ func TestBlockVerify(t *testing.T) { mempool: mempool, metrics: metrics.NewMockMetrics(ctrl), backend: &executor.Backend{ - Config: &config.Config{ - DurangoTime: time.Time{}, - EUpgradeTime: mockable.MaxTime, - }, + Config: noFeesTestConfig, }, blkIDToState: map[ids.ID]*blockState{ parentID: { @@ -471,10 +448,7 @@ func TestBlockVerify(t *testing.T) { mempool: mempool, metrics: metrics.NewMockMetrics(ctrl), backend: &executor.Backend{ - Config: &config.Config{ - DurangoTime: time.Time{}, - EUpgradeTime: mockable.MaxTime, - }, + Config: noFeesTestConfig, }, blkIDToState: map[ids.ID]*blockState{ parentID: { @@ -534,10 +508,7 @@ func TestBlockVerify(t *testing.T) { Block: mockBlock, manager: &manager{ backend: &executor.Backend{ - Config: &config.Config{ - DurangoTime: time.Time{}, - EUpgradeTime: mockable.MaxTime, - }, + Config: noFeesTestConfig, }, blkIDToState: map[ids.ID]*blockState{ parentID: { @@ -591,10 +562,7 @@ func TestBlockVerify(t *testing.T) { mempool: mockMempool, metrics: metrics.NewMockMetrics(ctrl), backend: &executor.Backend{ - Config: &config.Config{ - DurangoTime: time.Time{}, - EUpgradeTime: mockable.MaxTime, - }, + Config: noFeesTestConfig, }, blkIDToState: map[ids.ID]*blockState{ parentID: { @@ -673,10 +641,7 @@ func TestBlockAccept(t *testing.T) { Ctx: &snow.Context{ Log: logging.NoLog{}, }, - Config: &config.Config{ - DurangoTime: time.Time{}, - EUpgradeTime: mockable.MaxTime, - }, + Config: noFeesTestConfig, }, blkIDToState: map[ids.ID]*blockState{}, }, @@ -711,10 +676,7 @@ func TestBlockAccept(t *testing.T) { Ctx: &snow.Context{ Log: logging.NoLog{}, }, - Config: &config.Config{ - DurangoTime: time.Time{}, - EUpgradeTime: mockable.MaxTime, - }, + Config: noFeesTestConfig, }, blkIDToState: map[ids.ID]*blockState{ blockID: { @@ -759,10 +721,7 @@ func TestBlockAccept(t *testing.T) { SharedMemory: mockSharedMemory, Log: logging.NoLog{}, }, - Config: &config.Config{ - DurangoTime: time.Time{}, - EUpgradeTime: mockable.MaxTime, - }, + Config: noFeesTestConfig, }, blkIDToState: map[ids.ID]*blockState{ blockID: { @@ -811,10 +770,7 @@ func TestBlockAccept(t *testing.T) { SharedMemory: mockSharedMemory, Log: logging.NoLog{}, }, - Config: &config.Config{ - DurangoTime: time.Time{}, - EUpgradeTime: mockable.MaxTime, - }, + Config: noFeesTestConfig, }, blkIDToState: map[ids.ID]*blockState{ blockID: { @@ -866,10 +822,7 @@ func TestBlockAccept(t *testing.T) { SharedMemory: mockSharedMemory, Log: logging.NoLog{}, }, - Config: &config.Config{ - DurangoTime: time.Time{}, - EUpgradeTime: mockable.MaxTime, - }, + Config: noFeesTestConfig, }, blkIDToState: map[ids.ID]*blockState{ blockID: { @@ -967,10 +920,7 @@ func TestBlockReject(t *testing.T) { metrics: metrics.NewMockMetrics(ctrl), backend: &executor.Backend{ Bootstrapped: true, - Config: &config.Config{ - DurangoTime: time.Time{}, - EUpgradeTime: mockable.MaxTime, - }, + Config: noFeesTestConfig, Ctx: &snow.Context{ Log: logging.NoLog{}, }, @@ -1032,10 +982,7 @@ func TestBlockReject(t *testing.T) { Ctx: &snow.Context{ Log: logging.NoLog{}, }, - Config: &config.Config{ - DurangoTime: time.Time{}, - EUpgradeTime: mockable.MaxTime, - }, + Config: noFeesTestConfig, }, state: mockState, blkIDToState: map[ids.ID]*blockState{ @@ -1086,10 +1033,7 @@ func TestBlockStatus(t *testing.T) { Block: mockBlock, manager: &manager{ backend: &executor.Backend{ - Config: &config.Config{ - DurangoTime: time.Time{}, - EUpgradeTime: mockable.MaxTime, - }, + Config: noFeesTestConfig, }, lastAccepted: blockID, }, @@ -1107,10 +1051,7 @@ func TestBlockStatus(t *testing.T) { Block: mockBlock, manager: &manager{ backend: &executor.Backend{ - Config: &config.Config{ - DurangoTime: time.Time{}, - EUpgradeTime: mockable.MaxTime, - }, + Config: noFeesTestConfig, }, blkIDToState: map[ids.ID]*blockState{ blockID: {}, @@ -1134,10 +1075,7 @@ func TestBlockStatus(t *testing.T) { Block: mockBlock, manager: &manager{ backend: &executor.Backend{ - Config: &config.Config{ - DurangoTime: time.Time{}, - EUpgradeTime: mockable.MaxTime, - }, + Config: noFeesTestConfig, }, blkIDToState: map[ids.ID]*blockState{}, state: mockState, @@ -1160,10 +1098,7 @@ func TestBlockStatus(t *testing.T) { Block: mockBlock, manager: &manager{ backend: &executor.Backend{ - Config: &config.Config{ - DurangoTime: time.Time{}, - EUpgradeTime: mockable.MaxTime, - }, + Config: noFeesTestConfig, }, blkIDToState: map[ids.ID]*blockState{}, state: mockState, diff --git a/vms/avm/block/executor/manager_test.go b/vms/avm/block/executor/manager_test.go index 517ced98eaf..adf1650cc78 100644 --- a/vms/avm/block/executor/manager_test.go +++ b/vms/avm/block/executor/manager_test.go @@ -13,9 +13,7 @@ import ( "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils/set" - "github.com/ava-labs/avalanchego/utils/timer/mockable" "github.com/ava-labs/avalanchego/vms/avm/block" - "github.com/ava-labs/avalanchego/vms/avm/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" @@ -126,10 +124,7 @@ func TestManagerVerifyTx(t *testing.T) { managerF: func(*gomock.Controller) *manager { return &manager{ backend: &executor.Backend{ - Config: &config.Config{ - DurangoTime: time.Time{}, - EUpgradeTime: mockable.MaxTime, - }, + Config: noFeesTestConfig, }, } }, @@ -148,10 +143,7 @@ func TestManagerVerifyTx(t *testing.T) { return &manager{ backend: &executor.Backend{ Bootstrapped: true, - Config: &config.Config{ - DurangoTime: time.Time{}, - EUpgradeTime: mockable.MaxTime, - }, + Config: noFeesTestConfig, }, } }, @@ -180,10 +172,7 @@ func TestManagerVerifyTx(t *testing.T) { return &manager{ backend: &executor.Backend{ Bootstrapped: true, - Config: &config.Config{ - DurangoTime: time.Time{}, - EUpgradeTime: mockable.MaxTime, - }, + Config: noFeesTestConfig, }, state: state, lastAccepted: lastAcceptedID, @@ -216,10 +205,7 @@ func TestManagerVerifyTx(t *testing.T) { return &manager{ backend: &executor.Backend{ Bootstrapped: true, - Config: &config.Config{ - DurangoTime: time.Time{}, - EUpgradeTime: mockable.MaxTime, - }, + Config: noFeesTestConfig, }, state: state, lastAccepted: lastAcceptedID, @@ -252,10 +238,7 @@ func TestManagerVerifyTx(t *testing.T) { return &manager{ backend: &executor.Backend{ Bootstrapped: true, - Config: &config.Config{ - DurangoTime: time.Time{}, - EUpgradeTime: mockable.MaxTime, - }, + Config: noFeesTestConfig, }, state: state, lastAccepted: lastAcceptedID, diff --git a/vms/avm/environment_test.go b/vms/avm/environment_test.go index b4f3e899a41..a013ec4e039 100644 --- a/vms/avm/environment_test.go +++ b/vms/avm/environment_test.go @@ -6,6 +6,7 @@ package avm import ( "context" "encoding/json" + "fmt" "math/rand" "testing" "time" @@ -40,7 +41,12 @@ import ( keystoreutils "github.com/ava-labs/avalanchego/vms/components/keystore" ) +type fork uint8 + const ( + durango fork = iota + eUpgrade + testTxFee uint64 = 1000 startBalance uint64 = 50000 @@ -70,6 +76,13 @@ var ( keys = secp256k1.TestKeys()[:3] // TODO: Remove [:3] addrs []ids.ShortID // addrs[i] corresponds to keys[i] + + noFeesTestConfig = &config.Config{ + DurangoTime: time.Time{}, + EUpgradeTime: mockable.MaxTime, + TxFee: 0, + CreateAssetTxFee: 0, + } ) func init() { @@ -86,6 +99,7 @@ type user struct { } type envConfig struct { + fork fork isCustomFeeAsset bool keystoreUsers []*user vmStaticConfig *config.Config @@ -146,12 +160,7 @@ func setup(tb testing.TB, c *envConfig) *environment { require.NoError(keystoreUser.Close()) } - vmStaticConfig := config.Config{ - TxFee: testTxFee, - CreateAssetTxFee: testTxFee, - DurangoTime: time.Time{}, - EUpgradeTime: mockable.MaxTime, - } + vmStaticConfig := staticConfig(tb, c.fork) if c.vmStaticConfig != nil { vmStaticConfig = *c.vmStaticConfig } @@ -224,6 +233,30 @@ func setup(tb testing.TB, c *envConfig) *environment { return env } +func staticConfig(tb testing.TB, f fork) config.Config { + var ( + durangoTime = mockable.MaxTime + eUpgradeTime = mockable.MaxTime + ) + + switch f { + case eUpgrade: + eUpgradeTime = time.Time{} + fallthrough + case durango: + durangoTime = time.Time{} + default: + require.FailNow(tb, fmt.Sprintf("unhandled fork %d", f)) + } + + return config.Config{ + TxFee: testTxFee, + CreateAssetTxFee: testTxFee, + DurangoTime: durangoTime, + EUpgradeTime: eUpgradeTime, + } +} + // Returns: // // 1. tx in genesis that creates asset diff --git a/vms/avm/index_test.go b/vms/avm/index_test.go index 8ed1887b693..ef8a357935a 100644 --- a/vms/avm/index_test.go +++ b/vms/avm/index_test.go @@ -6,7 +6,6 @@ package avm import ( "context" "testing" - "time" "github.com/prometheus/client_golang/prometheus" "github.com/stretchr/testify/require" @@ -20,8 +19,6 @@ 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" "github.com/ava-labs/avalanchego/vms/components/index" @@ -31,12 +28,7 @@ import ( func TestIndexTransaction_Ordered(t *testing.T) { require := require.New(t) - env := setup(t, &envConfig{ - vmStaticConfig: &config.Config{ - DurangoTime: time.Time{}, - EUpgradeTime: mockable.MaxTime, - }, - }) + env := setup(t, &envConfig{vmStaticConfig: noFeesTestConfig}) defer func() { require.NoError(env.vm.Shutdown(context.Background())) env.vm.ctx.Lock.Unlock() @@ -78,12 +70,7 @@ func TestIndexTransaction_Ordered(t *testing.T) { func TestIndexTransaction_MultipleTransactions(t *testing.T) { require := require.New(t) - env := setup(t, &envConfig{ - vmStaticConfig: &config.Config{ - DurangoTime: time.Time{}, - EUpgradeTime: mockable.MaxTime, - }, - }) + env := setup(t, &envConfig{vmStaticConfig: noFeesTestConfig}) defer func() { require.NoError(env.vm.Shutdown(context.Background())) env.vm.ctx.Lock.Unlock() @@ -129,12 +116,7 @@ func TestIndexTransaction_MultipleTransactions(t *testing.T) { func TestIndexTransaction_MultipleAddresses(t *testing.T) { require := require.New(t) - env := setup(t, &envConfig{ - vmStaticConfig: &config.Config{ - DurangoTime: time.Time{}, - EUpgradeTime: mockable.MaxTime, - }, - }) + env := setup(t, &envConfig{vmStaticConfig: noFeesTestConfig}) defer func() { require.NoError(env.vm.Shutdown(context.Background())) env.vm.ctx.Lock.Unlock() @@ -175,7 +157,7 @@ func TestIndexTransaction_MultipleAddresses(t *testing.T) { func TestIndexer_Read(t *testing.T) { require := require.New(t) - env := setup(t, &envConfig{}) + env := setup(t, &envConfig{vmStaticConfig: noFeesTestConfig}) defer func() { require.NoError(env.vm.Shutdown(context.Background())) env.vm.ctx.Lock.Unlock() diff --git a/vms/avm/service_test.go b/vms/avm/service_test.go index 00ec1c93e0c..c725658f839 100644 --- a/vms/avm/service_test.go +++ b/vms/avm/service_test.go @@ -28,10 +28,8 @@ import ( "github.com/ava-labs/avalanchego/utils/formatting" "github.com/ava-labs/avalanchego/utils/formatting/address" "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" "github.com/ava-labs/avalanchego/vms/avm/state" "github.com/ava-labs/avalanchego/vms/avm/txs" "github.com/ava-labs/avalanchego/vms/components/avax" @@ -47,7 +45,7 @@ import ( func TestServiceIssueTx(t *testing.T) { require := require.New(t) - env := setup(t, &envConfig{}) + env := setup(t, &envConfig{fork: durango}) env.vm.ctx.Lock.Unlock() defer func() { @@ -73,7 +71,7 @@ func TestServiceIssueTx(t *testing.T) { func TestServiceGetTxStatus(t *testing.T) { require := require.New(t) - env := setup(t, &envConfig{}) + env := setup(t, &envConfig{fork: durango}) env.vm.ctx.Lock.Unlock() defer func() { @@ -108,7 +106,7 @@ func TestServiceGetTxStatus(t *testing.T) { func TestServiceGetBalanceStrict(t *testing.T) { require := require.New(t) - env := setup(t, &envConfig{}) + env := setup(t, &envConfig{fork: durango}) defer func() { env.vm.ctx.Lock.Lock() require.NoError(env.vm.Shutdown(context.Background())) @@ -264,7 +262,7 @@ func TestServiceGetBalanceStrict(t *testing.T) { func TestServiceGetTxs(t *testing.T) { require := require.New(t) - env := setup(t, &envConfig{}) + env := setup(t, &envConfig{fork: durango}) var err error env.vm.addressTxsIndexer, err = index.NewIndexer(env.vm.db, env.vm.ctx.Log, "", prometheus.NewRegistry(), false) require.NoError(err) @@ -306,7 +304,7 @@ func TestServiceGetTxs(t *testing.T) { func TestServiceGetAllBalances(t *testing.T) { require := require.New(t) - env := setup(t, &envConfig{}) + env := setup(t, &envConfig{fork: durango}) defer func() { env.vm.ctx.Lock.Lock() require.NoError(env.vm.Shutdown(context.Background())) @@ -504,7 +502,7 @@ func TestServiceGetAllBalances(t *testing.T) { func TestServiceGetTx(t *testing.T) { require := require.New(t) - env := setup(t, &envConfig{}) + env := setup(t, &envConfig{fork: durango}) env.vm.ctx.Lock.Unlock() defer func() { @@ -532,7 +530,7 @@ func TestServiceGetTx(t *testing.T) { func TestServiceGetTxJSON_BaseTx(t *testing.T) { require := require.New(t) - env := setup(t, &envConfig{}) + env := setup(t, &envConfig{fork: durango}) env.vm.ctx.Lock.Unlock() defer func() { env.vm.ctx.Lock.Lock() @@ -615,7 +613,7 @@ func TestServiceGetTxJSON_BaseTx(t *testing.T) { func TestServiceGetTxJSON_ExportTx(t *testing.T) { require := require.New(t) - env := setup(t, &envConfig{}) + env := setup(t, &envConfig{fork: durango}) env.vm.ctx.Lock.Unlock() defer func() { env.vm.ctx.Lock.Lock() @@ -700,10 +698,7 @@ func TestServiceGetTxJSON_CreateAssetTx(t *testing.T) { require := require.New(t) env := setup(t, &envConfig{ - vmStaticConfig: &config.Config{ - DurangoTime: time.Time{}, - EUpgradeTime: mockable.MaxTime, - }, + vmStaticConfig: noFeesTestConfig, additionalFxs: []*common.Fx{{ ID: propertyfx.ID, Fx: &propertyfx.Fx{}, @@ -819,10 +814,7 @@ func TestServiceGetTxJSON_OperationTxWithNftxMintOp(t *testing.T) { require := require.New(t) env := setup(t, &envConfig{ - vmStaticConfig: &config.Config{ - DurangoTime: time.Time{}, - EUpgradeTime: mockable.MaxTime, - }, + vmStaticConfig: noFeesTestConfig, additionalFxs: []*common.Fx{{ ID: propertyfx.ID, Fx: &propertyfx.Fx{}, @@ -921,10 +913,7 @@ func TestServiceGetTxJSON_OperationTxWithMultipleNftxMintOp(t *testing.T) { require := require.New(t) env := setup(t, &envConfig{ - vmStaticConfig: &config.Config{ - DurangoTime: time.Time{}, - EUpgradeTime: mockable.MaxTime, - }, + vmStaticConfig: noFeesTestConfig, additionalFxs: []*common.Fx{{ ID: propertyfx.ID, Fx: &propertyfx.Fx{}, @@ -1062,10 +1051,7 @@ func TestServiceGetTxJSON_OperationTxWithSecpMintOp(t *testing.T) { require := require.New(t) env := setup(t, &envConfig{ - vmStaticConfig: &config.Config{ - DurangoTime: time.Time{}, - EUpgradeTime: mockable.MaxTime, - }, + vmStaticConfig: noFeesTestConfig, additionalFxs: []*common.Fx{{ ID: propertyfx.ID, Fx: &propertyfx.Fx{}, @@ -1168,10 +1154,7 @@ func TestServiceGetTxJSON_OperationTxWithMultipleSecpMintOp(t *testing.T) { require := require.New(t) env := setup(t, &envConfig{ - vmStaticConfig: &config.Config{ - DurangoTime: time.Time{}, - EUpgradeTime: mockable.MaxTime, - }, + vmStaticConfig: noFeesTestConfig, additionalFxs: []*common.Fx{{ ID: propertyfx.ID, Fx: &propertyfx.Fx{}, @@ -1317,10 +1300,7 @@ func TestServiceGetTxJSON_OperationTxWithPropertyFxMintOp(t *testing.T) { require := require.New(t) env := setup(t, &envConfig{ - vmStaticConfig: &config.Config{ - DurangoTime: time.Time{}, - EUpgradeTime: mockable.MaxTime, - }, + vmStaticConfig: noFeesTestConfig, additionalFxs: []*common.Fx{{ ID: propertyfx.ID, Fx: &propertyfx.Fx{}, @@ -1420,10 +1400,7 @@ func TestServiceGetTxJSON_OperationTxWithPropertyFxMintOpMultiple(t *testing.T) require := require.New(t) env := setup(t, &envConfig{ - vmStaticConfig: &config.Config{ - DurangoTime: time.Time{}, - EUpgradeTime: mockable.MaxTime, - }, + vmStaticConfig: noFeesTestConfig, additionalFxs: []*common.Fx{{ ID: propertyfx.ID, Fx: &propertyfx.Fx{}, @@ -1802,7 +1779,7 @@ func buildOperationTxWithOp(chainID ids.ID, op ...*txs.Operation) *txs.Tx { func TestServiceGetNilTx(t *testing.T) { require := require.New(t) - env := setup(t, &envConfig{}) + env := setup(t, &envConfig{fork: durango}) env.vm.ctx.Lock.Unlock() defer func() { @@ -1819,7 +1796,7 @@ func TestServiceGetNilTx(t *testing.T) { func TestServiceGetUnknownTx(t *testing.T) { require := require.New(t) - env := setup(t, &envConfig{}) + env := setup(t, &envConfig{fork: durango}) env.vm.ctx.Lock.Unlock() defer func() { @@ -1834,7 +1811,7 @@ func TestServiceGetUnknownTx(t *testing.T) { } func TestServiceGetUTXOs(t *testing.T) { - env := setup(t, &envConfig{}) + env := setup(t, &envConfig{fork: durango}) defer func() { env.vm.ctx.Lock.Lock() require.NoError(t, env.vm.Shutdown(context.Background())) @@ -2089,7 +2066,7 @@ func TestServiceGetUTXOs(t *testing.T) { func TestGetAssetDescription(t *testing.T) { require := require.New(t) - env := setup(t, &envConfig{}) + env := setup(t, &envConfig{fork: durango}) env.vm.ctx.Lock.Unlock() defer func() { @@ -2112,7 +2089,7 @@ func TestGetAssetDescription(t *testing.T) { func TestGetBalance(t *testing.T) { require := require.New(t) - env := setup(t, &envConfig{}) + env := setup(t, &envConfig{fork: durango}) env.vm.ctx.Lock.Unlock() defer func() { diff --git a/vms/avm/state_test.go b/vms/avm/state_test.go index b17604b2ba6..4496ed54d80 100644 --- a/vms/avm/state_test.go +++ b/vms/avm/state_test.go @@ -24,6 +24,7 @@ func TestSetsAndGets(t *testing.T) { require := require.New(t) env := setup(t, &envConfig{ + fork: durango, additionalFxs: []*common.Fx{{ ID: ids.GenerateTestID(), Fx: &FxTest{ @@ -86,6 +87,7 @@ func TestSetsAndGets(t *testing.T) { func TestFundingNoAddresses(t *testing.T) { env := setup(t, &envConfig{ + fork: durango, additionalFxs: []*common.Fx{{ ID: ids.GenerateTestID(), Fx: &FxTest{ @@ -118,6 +120,7 @@ func TestFundingAddresses(t *testing.T) { require := require.New(t) env := setup(t, &envConfig{ + fork: durango, additionalFxs: []*common.Fx{{ ID: ids.GenerateTestID(), Fx: &FxTest{ diff --git a/vms/avm/vm_benchmark_test.go b/vms/avm/vm_benchmark_test.go index 713f809f7f5..4ac65c86d7d 100644 --- a/vms/avm/vm_benchmark_test.go +++ b/vms/avm/vm_benchmark_test.go @@ -23,6 +23,7 @@ func BenchmarkLoadUser(b *testing.B) { require := require.New(b) env := setup(b, &envConfig{ + fork: durango, keystoreUsers: []*user{{ username: username, password: password, @@ -67,7 +68,7 @@ func BenchmarkLoadUser(b *testing.B) { func GetAllUTXOsBenchmark(b *testing.B, utxoCount int) { require := require.New(b) - env := setup(b, &envConfig{}) + env := setup(b, &envConfig{fork: durango}) defer func() { require.NoError(env.vm.Shutdown(context.Background())) env.vm.ctx.Lock.Unlock() diff --git a/vms/avm/vm_regression_test.go b/vms/avm/vm_regression_test.go index 2412c4e9a70..34d99dcc351 100644 --- a/vms/avm/vm_regression_test.go +++ b/vms/avm/vm_regression_test.go @@ -6,15 +6,12 @@ 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" "github.com/ava-labs/avalanchego/vms/components/verify" @@ -25,12 +22,7 @@ import ( func TestVerifyFxUsage(t *testing.T) { require := require.New(t) - env := setup(t, &envConfig{ - vmStaticConfig: &config.Config{ - DurangoTime: time.Time{}, - EUpgradeTime: mockable.MaxTime, - }, - }) + env := setup(t, &envConfig{vmStaticConfig: noFeesTestConfig}) env.vm.ctx.Lock.Unlock() defer func() { env.vm.ctx.Lock.Lock() diff --git a/vms/avm/vm_test.go b/vms/avm/vm_test.go index a01aefd349d..527c2e98efe 100644 --- a/vms/avm/vm_test.go +++ b/vms/avm/vm_test.go @@ -7,7 +7,6 @@ import ( "context" "math" "testing" - "time" "github.com/stretchr/testify/require" @@ -20,8 +19,6 @@ 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" "github.com/ava-labs/avalanchego/vms/components/avax" @@ -117,7 +114,7 @@ func TestFxInitializationFailure(t *testing.T) { func TestIssueTx(t *testing.T) { require := require.New(t) - env := setup(t, &envConfig{}) + env := setup(t, &envConfig{fork: durango}) env.vm.ctx.Lock.Unlock() defer func() { env.vm.ctx.Lock.Lock() @@ -133,12 +130,7 @@ func TestIssueTx(t *testing.T) { func TestIssueNFT(t *testing.T) { require := require.New(t) - env := setup(t, &envConfig{ - vmStaticConfig: &config.Config{ - DurangoTime: time.Time{}, - EUpgradeTime: mockable.MaxTime, - }, - }) + env := setup(t, &envConfig{vmStaticConfig: noFeesTestConfig}) env.vm.ctx.Lock.Unlock() defer func() { env.vm.ctx.Lock.Lock() @@ -238,10 +230,7 @@ func TestIssueProperty(t *testing.T) { require := require.New(t) env := setup(t, &envConfig{ - vmStaticConfig: &config.Config{ - DurangoTime: time.Time{}, - EUpgradeTime: mockable.MaxTime, - }, + vmStaticConfig: noFeesTestConfig, additionalFxs: []*common.Fx{{ ID: propertyfx.ID, Fx: &propertyfx.Fx{}, @@ -334,6 +323,7 @@ func TestIssueTxWithFeeAsset(t *testing.T) { require := require.New(t) env := setup(t, &envConfig{ + fork: durango, isCustomFeeAsset: true, }) env.vm.ctx.Lock.Unlock() @@ -352,6 +342,7 @@ func TestIssueTxWithAnotherAsset(t *testing.T) { require := require.New(t) env := setup(t, &envConfig{ + fork: durango, isCustomFeeAsset: true, }) env.vm.ctx.Lock.Unlock() @@ -411,7 +402,7 @@ func TestIssueTxWithAnotherAsset(t *testing.T) { } func TestVMFormat(t *testing.T) { - env := setup(t, &envConfig{}) + env := setup(t, &envConfig{fork: durango}) defer func() { require.NoError(t, env.vm.Shutdown(context.Background())) env.vm.ctx.Lock.Unlock() @@ -440,6 +431,7 @@ func TestTxAcceptAfterParseTx(t *testing.T) { require := require.New(t) env := setup(t, &envConfig{ + fork: durango, notLinearized: true, }) defer func() { @@ -527,12 +519,7 @@ func TestTxAcceptAfterParseTx(t *testing.T) { func TestIssueImportTx(t *testing.T) { require := require.New(t) - env := setup(t, &envConfig{ - vmStaticConfig: &config.Config{ - DurangoTime: time.Time{}, - EUpgradeTime: mockable.MaxTime, - }, - }) + env := setup(t, &envConfig{vmStaticConfig: noFeesTestConfig}) defer func() { require.NoError(env.vm.Shutdown(context.Background())) env.vm.ctx.Lock.Unlock() @@ -631,11 +618,8 @@ func TestForceAcceptImportTx(t *testing.T) { require := require.New(t) env := setup(t, &envConfig{ - vmStaticConfig: &config.Config{ - DurangoTime: time.Time{}, - EUpgradeTime: mockable.MaxTime, - }, - notLinearized: true, + vmStaticConfig: noFeesTestConfig, + notLinearized: true, }) defer func() { require.NoError(env.vm.Shutdown(context.Background())) @@ -711,7 +695,7 @@ func TestImportTxNotState(t *testing.T) { func TestIssueExportTx(t *testing.T) { require := require.New(t) - env := setup(t, &envConfig{}) + env := setup(t, &envConfig{fork: durango}) defer func() { require.NoError(env.vm.Shutdown(context.Background())) env.vm.ctx.Lock.Unlock() @@ -786,7 +770,7 @@ func TestIssueExportTx(t *testing.T) { func TestClearForceAcceptedExportTx(t *testing.T) { require := require.New(t) - env := setup(t, &envConfig{}) + env := setup(t, &envConfig{fork: durango}) defer func() { require.NoError(env.vm.Shutdown(context.Background())) env.vm.ctx.Lock.Unlock() diff --git a/vms/avm/wallet_service_test.go b/vms/avm/wallet_service_test.go index 7ffdccdaaa2..a71403fa385 100644 --- a/vms/avm/wallet_service_test.go +++ b/vms/avm/wallet_service_test.go @@ -18,6 +18,7 @@ func TestWalletService_SendMultiple(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { env := setup(t, &envConfig{ + fork: durango, isCustomFeeAsset: !tc.avaxAsset, keystoreUsers: []*user{{ username: username, diff --git a/vms/platformvm/block/builder/helpers_test.go b/vms/platformvm/block/builder/helpers_test.go index d75b5780e53..d07ab6140c0 100644 --- a/vms/platformvm/block/builder/helpers_test.go +++ b/vms/platformvm/block/builder/helpers_test.go @@ -334,7 +334,7 @@ func defaultConfig(t *testing.T, f fork) *config.Config { case apricotPhase3: apricotPhase3Time = defaultValidateEndTime default: - require.NoError(t, fmt.Errorf("unhandled fork %d", f)) + require.FailNow(t, fmt.Sprintf("unhandled fork %d", f)) } return &config.Config{ diff --git a/vms/platformvm/block/executor/helpers_test.go b/vms/platformvm/block/executor/helpers_test.go index a2cacb0f277..26cd8bd566a 100644 --- a/vms/platformvm/block/executor/helpers_test.go +++ b/vms/platformvm/block/executor/helpers_test.go @@ -358,7 +358,7 @@ func defaultConfig(t *testing.T, f fork) *config.Config { case apricotPhase3: apricotPhase3Time = defaultValidateEndTime default: - require.NoError(t, fmt.Errorf("unhandled fork %d", f)) + require.FailNow(t, fmt.Sprintf("unhandled fork %d", f)) } return &config.Config{ diff --git a/vms/platformvm/txs/executor/helpers_test.go b/vms/platformvm/txs/executor/helpers_test.go index ad8acaa859e..907829f901c 100644 --- a/vms/platformvm/txs/executor/helpers_test.go +++ b/vms/platformvm/txs/executor/helpers_test.go @@ -309,7 +309,7 @@ func defaultConfig(t *testing.T, f fork) *config.Config { case apricotPhase3: apricotPhase3Time = defaultValidateEndTime default: - require.NoError(t, fmt.Errorf("unhandled fork %d", f)) + require.FailNow(t, fmt.Sprintf("unhandled fork %d", f)) } return &config.Config{ diff --git a/vms/platformvm/vm_test.go b/vms/platformvm/vm_test.go index 7f097436576..b1d6a73b645 100644 --- a/vms/platformvm/vm_test.go +++ b/vms/platformvm/vm_test.go @@ -235,7 +235,7 @@ func defaultVM(t *testing.T, f fork) (*VM, database.Database, *mutableSharedMemo case apricotPhase3: apricotPhase3Time = latestForkTime default: - require.NoError(fmt.Errorf("unhandled fork %d", f)) + require.FailNow(fmt.Sprintf("unhandled fork %d", f)) } vm := &VM{Config: config.Config{ From 507636e6f192e1d9d9aa9aa0ae2e4b4d5ffcc8c6 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 29 Feb 2024 11:25:35 +0100 Subject: [PATCH 10/27] latestFork in avm --- vms/avm/environment_test.go | 2 ++ vms/avm/service_test.go | 26 +++++++++++++------------- vms/avm/state_test.go | 6 +++--- vms/avm/vm_benchmark_test.go | 4 ++-- vms/avm/vm_test.go | 14 +++++++------- vms/avm/wallet_service_test.go | 2 +- 6 files changed, 28 insertions(+), 26 deletions(-) diff --git a/vms/avm/environment_test.go b/vms/avm/environment_test.go index a6c8c3aed76..3500a9bc43f 100644 --- a/vms/avm/environment_test.go +++ b/vms/avm/environment_test.go @@ -47,6 +47,8 @@ const ( durango fork = iota eUpgrade + latest = durango + testTxFee uint64 = 1000 startBalance uint64 = 50000 diff --git a/vms/avm/service_test.go b/vms/avm/service_test.go index c725658f839..7fe845b21cb 100644 --- a/vms/avm/service_test.go +++ b/vms/avm/service_test.go @@ -45,7 +45,7 @@ import ( func TestServiceIssueTx(t *testing.T) { require := require.New(t) - env := setup(t, &envConfig{fork: durango}) + env := setup(t, &envConfig{fork: latest}) env.vm.ctx.Lock.Unlock() defer func() { @@ -71,7 +71,7 @@ func TestServiceIssueTx(t *testing.T) { func TestServiceGetTxStatus(t *testing.T) { require := require.New(t) - env := setup(t, &envConfig{fork: durango}) + env := setup(t, &envConfig{fork: latest}) env.vm.ctx.Lock.Unlock() defer func() { @@ -106,7 +106,7 @@ func TestServiceGetTxStatus(t *testing.T) { func TestServiceGetBalanceStrict(t *testing.T) { require := require.New(t) - env := setup(t, &envConfig{fork: durango}) + env := setup(t, &envConfig{fork: latest}) defer func() { env.vm.ctx.Lock.Lock() require.NoError(env.vm.Shutdown(context.Background())) @@ -262,7 +262,7 @@ func TestServiceGetBalanceStrict(t *testing.T) { func TestServiceGetTxs(t *testing.T) { require := require.New(t) - env := setup(t, &envConfig{fork: durango}) + env := setup(t, &envConfig{fork: latest}) var err error env.vm.addressTxsIndexer, err = index.NewIndexer(env.vm.db, env.vm.ctx.Log, "", prometheus.NewRegistry(), false) require.NoError(err) @@ -304,7 +304,7 @@ func TestServiceGetTxs(t *testing.T) { func TestServiceGetAllBalances(t *testing.T) { require := require.New(t) - env := setup(t, &envConfig{fork: durango}) + env := setup(t, &envConfig{fork: latest}) defer func() { env.vm.ctx.Lock.Lock() require.NoError(env.vm.Shutdown(context.Background())) @@ -502,7 +502,7 @@ func TestServiceGetAllBalances(t *testing.T) { func TestServiceGetTx(t *testing.T) { require := require.New(t) - env := setup(t, &envConfig{fork: durango}) + env := setup(t, &envConfig{fork: latest}) env.vm.ctx.Lock.Unlock() defer func() { @@ -530,7 +530,7 @@ func TestServiceGetTx(t *testing.T) { func TestServiceGetTxJSON_BaseTx(t *testing.T) { require := require.New(t) - env := setup(t, &envConfig{fork: durango}) + env := setup(t, &envConfig{fork: latest}) env.vm.ctx.Lock.Unlock() defer func() { env.vm.ctx.Lock.Lock() @@ -613,7 +613,7 @@ func TestServiceGetTxJSON_BaseTx(t *testing.T) { func TestServiceGetTxJSON_ExportTx(t *testing.T) { require := require.New(t) - env := setup(t, &envConfig{fork: durango}) + env := setup(t, &envConfig{fork: latest}) env.vm.ctx.Lock.Unlock() defer func() { env.vm.ctx.Lock.Lock() @@ -1779,7 +1779,7 @@ func buildOperationTxWithOp(chainID ids.ID, op ...*txs.Operation) *txs.Tx { func TestServiceGetNilTx(t *testing.T) { require := require.New(t) - env := setup(t, &envConfig{fork: durango}) + env := setup(t, &envConfig{fork: latest}) env.vm.ctx.Lock.Unlock() defer func() { @@ -1796,7 +1796,7 @@ func TestServiceGetNilTx(t *testing.T) { func TestServiceGetUnknownTx(t *testing.T) { require := require.New(t) - env := setup(t, &envConfig{fork: durango}) + env := setup(t, &envConfig{fork: latest}) env.vm.ctx.Lock.Unlock() defer func() { @@ -1811,7 +1811,7 @@ func TestServiceGetUnknownTx(t *testing.T) { } func TestServiceGetUTXOs(t *testing.T) { - env := setup(t, &envConfig{fork: durango}) + env := setup(t, &envConfig{fork: latest}) defer func() { env.vm.ctx.Lock.Lock() require.NoError(t, env.vm.Shutdown(context.Background())) @@ -2066,7 +2066,7 @@ func TestServiceGetUTXOs(t *testing.T) { func TestGetAssetDescription(t *testing.T) { require := require.New(t) - env := setup(t, &envConfig{fork: durango}) + env := setup(t, &envConfig{fork: latest}) env.vm.ctx.Lock.Unlock() defer func() { @@ -2089,7 +2089,7 @@ func TestGetAssetDescription(t *testing.T) { func TestGetBalance(t *testing.T) { require := require.New(t) - env := setup(t, &envConfig{fork: durango}) + env := setup(t, &envConfig{fork: latest}) env.vm.ctx.Lock.Unlock() defer func() { diff --git a/vms/avm/state_test.go b/vms/avm/state_test.go index 4496ed54d80..e71acf1251c 100644 --- a/vms/avm/state_test.go +++ b/vms/avm/state_test.go @@ -24,7 +24,7 @@ func TestSetsAndGets(t *testing.T) { require := require.New(t) env := setup(t, &envConfig{ - fork: durango, + fork: latest, additionalFxs: []*common.Fx{{ ID: ids.GenerateTestID(), Fx: &FxTest{ @@ -87,7 +87,7 @@ func TestSetsAndGets(t *testing.T) { func TestFundingNoAddresses(t *testing.T) { env := setup(t, &envConfig{ - fork: durango, + fork: latest, additionalFxs: []*common.Fx{{ ID: ids.GenerateTestID(), Fx: &FxTest{ @@ -120,7 +120,7 @@ func TestFundingAddresses(t *testing.T) { require := require.New(t) env := setup(t, &envConfig{ - fork: durango, + fork: latest, additionalFxs: []*common.Fx{{ ID: ids.GenerateTestID(), Fx: &FxTest{ diff --git a/vms/avm/vm_benchmark_test.go b/vms/avm/vm_benchmark_test.go index 4ac65c86d7d..5befa7062dd 100644 --- a/vms/avm/vm_benchmark_test.go +++ b/vms/avm/vm_benchmark_test.go @@ -23,7 +23,7 @@ func BenchmarkLoadUser(b *testing.B) { require := require.New(b) env := setup(b, &envConfig{ - fork: durango, + fork: latest, keystoreUsers: []*user{{ username: username, password: password, @@ -68,7 +68,7 @@ func BenchmarkLoadUser(b *testing.B) { func GetAllUTXOsBenchmark(b *testing.B, utxoCount int) { require := require.New(b) - env := setup(b, &envConfig{fork: durango}) + env := setup(b, &envConfig{fork: latest}) defer func() { require.NoError(env.vm.Shutdown(context.Background())) env.vm.ctx.Lock.Unlock() diff --git a/vms/avm/vm_test.go b/vms/avm/vm_test.go index 527c2e98efe..270ab6b36ed 100644 --- a/vms/avm/vm_test.go +++ b/vms/avm/vm_test.go @@ -114,7 +114,7 @@ func TestFxInitializationFailure(t *testing.T) { func TestIssueTx(t *testing.T) { require := require.New(t) - env := setup(t, &envConfig{fork: durango}) + env := setup(t, &envConfig{fork: latest}) env.vm.ctx.Lock.Unlock() defer func() { env.vm.ctx.Lock.Lock() @@ -323,7 +323,7 @@ func TestIssueTxWithFeeAsset(t *testing.T) { require := require.New(t) env := setup(t, &envConfig{ - fork: durango, + fork: latest, isCustomFeeAsset: true, }) env.vm.ctx.Lock.Unlock() @@ -342,7 +342,7 @@ func TestIssueTxWithAnotherAsset(t *testing.T) { require := require.New(t) env := setup(t, &envConfig{ - fork: durango, + fork: latest, isCustomFeeAsset: true, }) env.vm.ctx.Lock.Unlock() @@ -402,7 +402,7 @@ func TestIssueTxWithAnotherAsset(t *testing.T) { } func TestVMFormat(t *testing.T) { - env := setup(t, &envConfig{fork: durango}) + env := setup(t, &envConfig{fork: latest}) defer func() { require.NoError(t, env.vm.Shutdown(context.Background())) env.vm.ctx.Lock.Unlock() @@ -431,7 +431,7 @@ func TestTxAcceptAfterParseTx(t *testing.T) { require := require.New(t) env := setup(t, &envConfig{ - fork: durango, + fork: latest, notLinearized: true, }) defer func() { @@ -695,7 +695,7 @@ func TestImportTxNotState(t *testing.T) { func TestIssueExportTx(t *testing.T) { require := require.New(t) - env := setup(t, &envConfig{fork: durango}) + env := setup(t, &envConfig{fork: latest}) defer func() { require.NoError(env.vm.Shutdown(context.Background())) env.vm.ctx.Lock.Unlock() @@ -770,7 +770,7 @@ func TestIssueExportTx(t *testing.T) { func TestClearForceAcceptedExportTx(t *testing.T) { require := require.New(t) - env := setup(t, &envConfig{fork: durango}) + env := setup(t, &envConfig{fork: latest}) defer func() { require.NoError(env.vm.Shutdown(context.Background())) env.vm.ctx.Lock.Unlock() diff --git a/vms/avm/wallet_service_test.go b/vms/avm/wallet_service_test.go index a71403fa385..eeb214fba9b 100644 --- a/vms/avm/wallet_service_test.go +++ b/vms/avm/wallet_service_test.go @@ -18,7 +18,7 @@ func TestWalletService_SendMultiple(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { env := setup(t, &envConfig{ - fork: durango, + fork: latest, isCustomFeeAsset: !tc.avaxAsset, keystoreUsers: []*user{{ username: username, From 399dfc8afc16ad65c2719b6b47f031a00bae73be Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 29 Feb 2024 11:46:24 +0100 Subject: [PATCH 11/27] default test config for a few unit tests --- .../executor/staker_tx_verification_test.go | 92 +++++--------- .../txs/executor/standard_tx_executor_test.go | 115 ++++++------------ 2 files changed, 64 insertions(+), 143 deletions(-) diff --git a/vms/platformvm/txs/executor/staker_tx_verification_test.go b/vms/platformvm/txs/executor/staker_tx_verification_test.go index a5f426a665a..343b8932785 100644 --- a/vms/platformvm/txs/executor/staker_tx_verification_test.go +++ b/vms/platformvm/txs/executor/staker_tx_verification_test.go @@ -109,11 +109,8 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { name: "fail syntactic verification", backendF: func(*gomock.Controller) *Backend { return &Backend{ - Ctx: ctx, - Config: &config.Config{ - DurangoTime: activeForkTime, // activate latest fork - EUpgradeTime: mockable.MaxTime, - }, + Ctx: ctx, + Config: defaultTestConfig(activeForkTime), } }, stateF: func(*gomock.Controller) state.Chain { @@ -131,11 +128,8 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { name: "not bootstrapped", backendF: func(*gomock.Controller) *Backend { return &Backend{ - Ctx: ctx, - Config: &config.Config{ - DurangoTime: activeForkTime, // activate latest fork - EUpgradeTime: mockable.MaxTime, - }, + Ctx: ctx, + Config: defaultTestConfig(activeForkTime), Bootstrapped: &utils.Atomic[bool]{}, } }, @@ -186,11 +180,8 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { bootstrapped := &utils.Atomic[bool]{} bootstrapped.Set(true) return &Backend{ - Ctx: ctx, - Config: &config.Config{ - DurangoTime: activeForkTime, // activate latest fork - EUpgradeTime: mockable.MaxTime, - }, + Ctx: ctx, + Config: defaultTestConfig(activeForkTime), Bootstrapped: bootstrapped, } }, @@ -216,11 +207,8 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { bootstrapped := &utils.Atomic[bool]{} bootstrapped.Set(true) return &Backend{ - Ctx: ctx, - Config: &config.Config{ - DurangoTime: activeForkTime, // activate latest fork - EUpgradeTime: mockable.MaxTime, - }, + Ctx: ctx, + Config: defaultTestConfig(activeForkTime), Bootstrapped: bootstrapped, } }, @@ -246,11 +234,8 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { bootstrapped := &utils.Atomic[bool]{} bootstrapped.Set(true) return &Backend{ - Ctx: ctx, - Config: &config.Config{ - DurangoTime: activeForkTime, // activate latest fork - EUpgradeTime: mockable.MaxTime, - }, + Ctx: ctx, + Config: defaultTestConfig(activeForkTime), Bootstrapped: bootstrapped, } }, @@ -277,11 +262,8 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { bootstrapped := &utils.Atomic[bool]{} bootstrapped.Set(true) return &Backend{ - Ctx: ctx, - Config: &config.Config{ - DurangoTime: activeForkTime, // activate latest fork - EUpgradeTime: mockable.MaxTime, - }, + Ctx: ctx, + Config: defaultTestConfig(activeForkTime), Bootstrapped: bootstrapped, } }, @@ -311,11 +293,8 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { bootstrapped := &utils.Atomic[bool]{} bootstrapped.Set(true) return &Backend{ - Ctx: ctx, - Config: &config.Config{ - DurangoTime: activeForkTime, // activate latest fork - EUpgradeTime: mockable.MaxTime, - }, + Ctx: ctx, + Config: defaultTestConfig(activeForkTime), Bootstrapped: bootstrapped, } }, @@ -345,11 +324,8 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { bootstrapped := &utils.Atomic[bool]{} bootstrapped.Set(true) return &Backend{ - Ctx: ctx, - Config: &config.Config{ - DurangoTime: activeForkTime, // activate latest fork - EUpgradeTime: mockable.MaxTime, - }, + Ctx: ctx, + Config: defaultTestConfig(activeForkTime), Bootstrapped: bootstrapped, } }, @@ -381,11 +357,8 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { bootstrapped := &utils.Atomic[bool]{} bootstrapped.Set(true) return &Backend{ - Ctx: ctx, - Config: &config.Config{ - DurangoTime: activeForkTime, // activate latest fork - EUpgradeTime: mockable.MaxTime, - }, + Ctx: ctx, + Config: defaultTestConfig(activeForkTime), Bootstrapped: bootstrapped, } }, @@ -411,11 +384,8 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { bootstrapped := &utils.Atomic[bool]{} bootstrapped.Set(true) return &Backend{ - Ctx: ctx, - Config: &config.Config{ - DurangoTime: activeForkTime, // activate latest fork - EUpgradeTime: mockable.MaxTime, - }, + Ctx: ctx, + Config: defaultTestConfig(activeForkTime), Bootstrapped: bootstrapped, } }, @@ -456,13 +426,12 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { gomock.Any(), ).Return(ErrFlowCheckFailed) + cfg := defaultTestConfig(activeForkTime) + cfg.AddSubnetValidatorFee = 1 + return &Backend{ - FlowChecker: flowChecker, - Config: &config.Config{ - AddSubnetValidatorFee: 1, - DurangoTime: activeForkTime, // activate latest fork, - EUpgradeTime: mockable.MaxTime, - }, + FlowChecker: flowChecker, + Config: cfg, Ctx: ctx, Bootstrapped: bootstrapped, } @@ -556,13 +525,12 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { gomock.Any(), ).Return(nil) + cfg := defaultTestConfig(activeForkTime) + cfg.AddSubnetValidatorFee = 1 + return &Backend{ - FlowChecker: flowChecker, - Config: &config.Config{ - AddSubnetValidatorFee: 1, - DurangoTime: activeForkTime, // activate latest fork, - EUpgradeTime: mockable.MaxTime, - }, + FlowChecker: flowChecker, + Config: cfg, Ctx: ctx, Bootstrapped: bootstrapped, } diff --git a/vms/platformvm/txs/executor/standard_tx_executor_test.go b/vms/platformvm/txs/executor/standard_tx_executor_test.go index 55e6289f070..17553e2f801 100644 --- a/vms/platformvm/txs/executor/standard_tx_executor_test.go +++ b/vms/platformvm/txs/executor/standard_tx_executor_test.go @@ -1543,12 +1543,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { env.state.EXPECT().AddUTXO(gomock.Any()).Times(len(env.unsignedTx.Outs)) e := &StandardTxExecutor{ Backend: &Backend{ - Config: &config.Config{ - BanffTime: env.latestForkTime, - CortinaTime: env.latestForkTime, - DurangoTime: env.latestForkTime, - EUpgradeTime: mockable.MaxTime, - }, + Config: defaultTestConfig(env.latestForkTime), Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, @@ -1571,12 +1566,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { env.state = state.NewMockDiff(ctrl) e := &StandardTxExecutor{ Backend: &Backend{ - Config: &config.Config{ - BanffTime: env.latestForkTime, - CortinaTime: env.latestForkTime, - DurangoTime: env.latestForkTime, - EUpgradeTime: mockable.MaxTime, - }, + Config: defaultTestConfig(env.latestForkTime), Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, @@ -1600,12 +1590,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { env.state.EXPECT().GetPendingValidator(env.unsignedTx.Subnet, env.unsignedTx.NodeID).Return(nil, database.ErrNotFound) e := &StandardTxExecutor{ Backend: &Backend{ - Config: &config.Config{ - BanffTime: env.latestForkTime, - CortinaTime: env.latestForkTime, - DurangoTime: env.latestForkTime, - EUpgradeTime: mockable.MaxTime, - }, + Config: defaultTestConfig(env.latestForkTime), Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, @@ -1632,12 +1617,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { env.state.EXPECT().GetCurrentValidator(env.unsignedTx.Subnet, env.unsignedTx.NodeID).Return(&staker, nil).Times(1) e := &StandardTxExecutor{ Backend: &Backend{ - Config: &config.Config{ - BanffTime: env.latestForkTime, - CortinaTime: env.latestForkTime, - DurangoTime: env.latestForkTime, - EUpgradeTime: mockable.MaxTime, - }, + Config: defaultTestConfig(env.latestForkTime), Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, @@ -1662,12 +1642,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { env.state.EXPECT().GetCurrentValidator(env.unsignedTx.Subnet, env.unsignedTx.NodeID).Return(env.staker, nil) e := &StandardTxExecutor{ Backend: &Backend{ - Config: &config.Config{ - BanffTime: env.latestForkTime, - CortinaTime: env.latestForkTime, - DurangoTime: env.latestForkTime, - EUpgradeTime: mockable.MaxTime, - }, + Config: defaultTestConfig(env.latestForkTime), Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, @@ -1691,12 +1666,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { env.state.EXPECT().GetSubnetOwner(env.unsignedTx.Subnet).Return(nil, database.ErrNotFound) e := &StandardTxExecutor{ Backend: &Backend{ - Config: &config.Config{ - BanffTime: env.latestForkTime, - CortinaTime: env.latestForkTime, - DurangoTime: env.latestForkTime, - EUpgradeTime: mockable.MaxTime, - }, + Config: defaultTestConfig(env.latestForkTime), Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, @@ -1722,12 +1692,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { env.fx.EXPECT().VerifyPermission(gomock.Any(), env.unsignedTx.SubnetAuth, env.tx.Creds[len(env.tx.Creds)-1], subnetOwner).Return(errTest) e := &StandardTxExecutor{ Backend: &Backend{ - Config: &config.Config{ - BanffTime: env.latestForkTime, - CortinaTime: env.latestForkTime, - DurangoTime: env.latestForkTime, - EUpgradeTime: mockable.MaxTime, - }, + Config: defaultTestConfig(env.latestForkTime), Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, @@ -1756,12 +1721,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { ).Return(errTest) e := &StandardTxExecutor{ Backend: &Backend{ - Config: &config.Config{ - BanffTime: env.latestForkTime, - CortinaTime: env.latestForkTime, - DurangoTime: env.latestForkTime, - EUpgradeTime: mockable.MaxTime, - }, + Config: defaultTestConfig(env.latestForkTime), Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, @@ -1914,12 +1874,7 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { env.state = state.NewMockDiff(ctrl) e := &StandardTxExecutor{ Backend: &Backend{ - Config: &config.Config{ - BanffTime: env.latestForkTime, - CortinaTime: env.latestForkTime, - DurangoTime: env.latestForkTime, - EUpgradeTime: mockable.MaxTime, - }, + Config: defaultTestConfig(env.latestForkTime), Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, @@ -1942,12 +1897,7 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { env.state.EXPECT().GetTimestamp().Return(env.latestForkTime) e := &StandardTxExecutor{ Backend: &Backend{ - Config: &config.Config{ - BanffTime: env.latestForkTime, - CortinaTime: env.latestForkTime, - DurangoTime: env.latestForkTime, - EUpgradeTime: mockable.MaxTime, - }, + Config: defaultTestConfig(env.latestForkTime), Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, @@ -1969,15 +1919,13 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { env.tx.Creds = nil env.state = state.NewMockDiff(ctrl) env.state.EXPECT().GetTimestamp().Return(env.latestForkTime) + + cfg := defaultTestConfig(env.latestForkTime) + cfg.MaxStakeDuration = math.MaxInt64 + e := &StandardTxExecutor{ Backend: &Backend{ - Config: &config.Config{ - BanffTime: env.latestForkTime, - CortinaTime: env.latestForkTime, - DurangoTime: env.latestForkTime, - MaxStakeDuration: math.MaxInt64, - EUpgradeTime: mockable.MaxTime, - }, + Config: cfg, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, @@ -2004,15 +1952,13 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { env.flowChecker.EXPECT().VerifySpend( gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), ).Return(ErrFlowCheckFailed) + + cfg := defaultTestConfig(env.latestForkTime) + cfg.MaxStakeDuration = math.MaxInt64 + e := &StandardTxExecutor{ Backend: &Backend{ - Config: &config.Config{ - BanffTime: env.latestForkTime, - CortinaTime: env.latestForkTime, - DurangoTime: env.latestForkTime, - EUpgradeTime: mockable.MaxTime, - MaxStakeDuration: math.MaxInt64, - }, + Config: cfg, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, @@ -2044,15 +1990,13 @@ 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 := defaultTestConfig(env.latestForkTime) + cfg.MaxStakeDuration = math.MaxInt64 + e := &StandardTxExecutor{ Backend: &Backend{ - Config: &config.Config{ - BanffTime: env.latestForkTime, - CortinaTime: env.latestForkTime, - DurangoTime: env.latestForkTime, - EUpgradeTime: mockable.MaxTime, - MaxStakeDuration: math.MaxInt64, - }, + Config: cfg, Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, @@ -2078,3 +2022,12 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { }) } } + +func defaultTestConfig(latestForkTime time.Time) *config.Config { + return &config.Config{ + BanffTime: latestForkTime, + CortinaTime: latestForkTime, + DurangoTime: latestForkTime, + EUpgradeTime: mockable.MaxTime, + } +} From 089af5e04c3c5379e74ee6121c84d586b6bef7e1 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 29 Feb 2024 12:55:15 +0100 Subject: [PATCH 12/27] come more unit tests helpers --- vms/avm/block/executor/block_test.go | 155 +++++++------------------ vms/avm/block/executor/manager_test.go | 25 +--- 2 files changed, 50 insertions(+), 130 deletions(-) diff --git a/vms/avm/block/executor/block_test.go b/vms/avm/block/executor/block_test.go index 8b2e85a8378..e8b08ab0346 100644 --- a/vms/avm/block/executor/block_test.go +++ b/vms/avm/block/executor/block_test.go @@ -30,13 +30,6 @@ import ( "github.com/ava-labs/avalanchego/vms/avm/txs/mempool" ) -var noFeesTestConfig = &config.Config{ - DurangoTime: time.Time{}, - EUpgradeTime: mockable.MaxTime, - TxFee: 0, - CreateAssetTxFee: 0, -} - func TestBlockVerify(t *testing.T) { type test struct { name string @@ -53,9 +46,7 @@ func TestBlockVerify(t *testing.T) { b := &Block{ Block: mockBlock, manager: &manager{ - backend: &executor.Backend{ - Config: noFeesTestConfig, - }, + backend: defaultTestBackend(false, nil), blkIDToState: map[ids.ID]*blockState{}, }, } @@ -75,9 +66,7 @@ func TestBlockVerify(t *testing.T) { return &Block{ Block: mockBlock, manager: &manager{ - backend: &executor.Backend{ - Config: noFeesTestConfig, - }, + backend: defaultTestBackend(false, nil), }, } }, @@ -97,10 +86,8 @@ func TestBlockVerify(t *testing.T) { return &Block{ Block: mockBlock, manager: &manager{ - backend: &executor.Backend{ - Config: noFeesTestConfig, - }, - clk: clk, + backend: defaultTestBackend(false, nil), + clk: clk, }, } }, @@ -117,9 +104,7 @@ func TestBlockVerify(t *testing.T) { return &Block{ Block: mockBlock, manager: &manager{ - backend: &executor.Backend{ - Config: noFeesTestConfig, - }, + backend: defaultTestBackend(false, nil), blkIDToState: map[ids.ID]*blockState{}, clk: &mockable.Clock{}, }, @@ -146,9 +131,7 @@ func TestBlockVerify(t *testing.T) { return &Block{ Block: mockBlock, manager: &manager{ - backend: &executor.Backend{ - Config: noFeesTestConfig, - }, + backend: defaultTestBackend(false, nil), mempool: mempool, metrics: metrics.NewMockMetrics(ctrl), blkIDToState: map[ids.ID]*blockState{}, @@ -181,9 +164,7 @@ func TestBlockVerify(t *testing.T) { return &Block{ Block: mockBlock, manager: &manager{ - backend: &executor.Backend{ - Config: noFeesTestConfig, - }, + backend: defaultTestBackend(false, nil), state: mockState, blkIDToState: map[ids.ID]*blockState{}, clk: &mockable.Clock{}, @@ -220,9 +201,7 @@ func TestBlockVerify(t *testing.T) { return &Block{ Block: mockBlock, manager: &manager{ - backend: &executor.Backend{ - Config: noFeesTestConfig, - }, + backend: defaultTestBackend(false, nil), state: mockState, blkIDToState: map[ids.ID]*blockState{}, clk: &mockable.Clock{}, @@ -262,9 +241,7 @@ func TestBlockVerify(t *testing.T) { return &Block{ Block: mockBlock, manager: &manager{ - backend: &executor.Backend{ - Config: noFeesTestConfig, - }, + backend: defaultTestBackend(false, nil), blkIDToState: map[ids.ID]*blockState{ parentID: { onAcceptState: mockParentState, @@ -312,9 +289,7 @@ func TestBlockVerify(t *testing.T) { return &Block{ Block: mockBlock, manager: &manager{ - backend: &executor.Backend{ - Config: noFeesTestConfig, - }, + backend: defaultTestBackend(false, nil), mempool: mempool, metrics: metrics.NewMockMetrics(ctrl), blkIDToState: map[ids.ID]*blockState{ @@ -367,9 +342,7 @@ func TestBlockVerify(t *testing.T) { manager: &manager{ mempool: mempool, metrics: metrics.NewMockMetrics(ctrl), - backend: &executor.Backend{ - Config: noFeesTestConfig, - }, + backend: defaultTestBackend(false, nil), blkIDToState: map[ids.ID]*blockState{ parentID: { onAcceptState: mockParentState, @@ -447,9 +420,7 @@ func TestBlockVerify(t *testing.T) { manager: &manager{ mempool: mempool, metrics: metrics.NewMockMetrics(ctrl), - backend: &executor.Backend{ - Config: noFeesTestConfig, - }, + backend: defaultTestBackend(false, nil), blkIDToState: map[ids.ID]*blockState{ parentID: { onAcceptState: mockParentState, @@ -507,9 +478,7 @@ func TestBlockVerify(t *testing.T) { return &Block{ Block: mockBlock, manager: &manager{ - backend: &executor.Backend{ - Config: noFeesTestConfig, - }, + backend: defaultTestBackend(false, nil), blkIDToState: map[ids.ID]*blockState{ parentID: { onAcceptState: mockParentState, @@ -561,9 +530,7 @@ func TestBlockVerify(t *testing.T) { manager: &manager{ mempool: mockMempool, metrics: metrics.NewMockMetrics(ctrl), - backend: &executor.Backend{ - Config: noFeesTestConfig, - }, + backend: defaultTestBackend(false, nil), blkIDToState: map[ids.ID]*blockState{ parentID: { onAcceptState: mockParentState, @@ -635,14 +602,9 @@ func TestBlockAccept(t *testing.T) { return &Block{ Block: mockBlock, manager: &manager{ - mempool: mempool, - metrics: metrics.NewMockMetrics(ctrl), - backend: &executor.Backend{ - Ctx: &snow.Context{ - Log: logging.NoLog{}, - }, - Config: noFeesTestConfig, - }, + mempool: mempool, + metrics: metrics.NewMockMetrics(ctrl), + backend: defaultTestBackend(false, nil), blkIDToState: map[ids.ID]*blockState{}, }, } @@ -672,12 +634,7 @@ func TestBlockAccept(t *testing.T) { manager: &manager{ state: mockManagerState, mempool: mempool, - backend: &executor.Backend{ - Ctx: &snow.Context{ - Log: logging.NoLog{}, - }, - Config: noFeesTestConfig, - }, + backend: defaultTestBackend(false, nil), blkIDToState: map[ids.ID]*blockState{ blockID: { onAcceptState: mockOnAcceptState, @@ -716,13 +673,7 @@ func TestBlockAccept(t *testing.T) { manager: &manager{ state: mockManagerState, mempool: mempool, - backend: &executor.Backend{ - Ctx: &snow.Context{ - SharedMemory: mockSharedMemory, - Log: logging.NoLog{}, - }, - Config: noFeesTestConfig, - }, + backend: defaultTestBackend(false, mockSharedMemory), blkIDToState: map[ids.ID]*blockState{ blockID: { onAcceptState: mockOnAcceptState, @@ -765,13 +716,7 @@ func TestBlockAccept(t *testing.T) { state: mockManagerState, mempool: mempool, metrics: metrics, - backend: &executor.Backend{ - Ctx: &snow.Context{ - SharedMemory: mockSharedMemory, - Log: logging.NoLog{}, - }, - Config: noFeesTestConfig, - }, + backend: defaultTestBackend(false, mockSharedMemory), blkIDToState: map[ids.ID]*blockState{ blockID: { onAcceptState: mockOnAcceptState, @@ -817,13 +762,7 @@ func TestBlockAccept(t *testing.T) { state: mockManagerState, mempool: mempool, metrics: metrics, - backend: &executor.Backend{ - Ctx: &snow.Context{ - SharedMemory: mockSharedMemory, - Log: logging.NoLog{}, - }, - Config: noFeesTestConfig, - }, + backend: defaultTestBackend(false, mockSharedMemory), blkIDToState: map[ids.ID]*blockState{ blockID: { onAcceptState: mockOnAcceptState, @@ -918,14 +857,8 @@ func TestBlockReject(t *testing.T) { lastAccepted: lastAcceptedID, mempool: mempool, metrics: metrics.NewMockMetrics(ctrl), - backend: &executor.Backend{ - Bootstrapped: true, - Config: noFeesTestConfig, - Ctx: &snow.Context{ - Log: logging.NoLog{}, - }, - }, - state: mockState, + backend: defaultTestBackend(true, nil), + state: mockState, blkIDToState: map[ids.ID]*blockState{ blockID: {}, }, @@ -977,14 +910,8 @@ func TestBlockReject(t *testing.T) { lastAccepted: lastAcceptedID, mempool: mempool, metrics: metrics.NewMockMetrics(ctrl), - backend: &executor.Backend{ - Bootstrapped: true, - Ctx: &snow.Context{ - Log: logging.NoLog{}, - }, - Config: noFeesTestConfig, - }, - state: mockState, + backend: defaultTestBackend(true, nil), + state: mockState, blkIDToState: map[ids.ID]*blockState{ blockID: {}, }, @@ -1032,9 +959,7 @@ func TestBlockStatus(t *testing.T) { return &Block{ Block: mockBlock, manager: &manager{ - backend: &executor.Backend{ - Config: noFeesTestConfig, - }, + backend: defaultTestBackend(false, nil), lastAccepted: blockID, }, } @@ -1050,9 +975,7 @@ func TestBlockStatus(t *testing.T) { return &Block{ Block: mockBlock, manager: &manager{ - backend: &executor.Backend{ - Config: noFeesTestConfig, - }, + backend: defaultTestBackend(false, nil), blkIDToState: map[ids.ID]*blockState{ blockID: {}, }, @@ -1074,9 +997,7 @@ func TestBlockStatus(t *testing.T) { return &Block{ Block: mockBlock, manager: &manager{ - backend: &executor.Backend{ - Config: noFeesTestConfig, - }, + backend: defaultTestBackend(false, nil), blkIDToState: map[ids.ID]*blockState{}, state: mockState, }, @@ -1097,9 +1018,7 @@ func TestBlockStatus(t *testing.T) { return &Block{ Block: mockBlock, manager: &manager{ - backend: &executor.Backend{ - Config: noFeesTestConfig, - }, + backend: defaultTestBackend(false, nil), blkIDToState: map[ids.ID]*blockState{}, state: mockState, }, @@ -1118,3 +1037,19 @@ func TestBlockStatus(t *testing.T) { }) } } + +func defaultTestBackend(bootstrapped bool, sharedMemory atomic.SharedMemory) *executor.Backend { + return &executor.Backend{ + Bootstrapped: bootstrapped, + Ctx: &snow.Context{ + SharedMemory: sharedMemory, + Log: logging.NoLog{}, + }, + Config: &config.Config{ + DurangoTime: time.Time{}, + EUpgradeTime: mockable.MaxTime, + TxFee: 0, + CreateAssetTxFee: 0, + }, + } +} diff --git a/vms/avm/block/executor/manager_test.go b/vms/avm/block/executor/manager_test.go index adf1650cc78..14484fcbb55 100644 --- a/vms/avm/block/executor/manager_test.go +++ b/vms/avm/block/executor/manager_test.go @@ -16,7 +16,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" - "github.com/ava-labs/avalanchego/vms/avm/txs/executor" ) var ( @@ -123,9 +122,7 @@ func TestManagerVerifyTx(t *testing.T) { }, managerF: func(*gomock.Controller) *manager { return &manager{ - backend: &executor.Backend{ - Config: noFeesTestConfig, - }, + backend: defaultTestBackend(false, nil), } }, expectedErr: ErrChainNotSynced, @@ -141,10 +138,7 @@ func TestManagerVerifyTx(t *testing.T) { }, managerF: func(*gomock.Controller) *manager { return &manager{ - backend: &executor.Backend{ - Bootstrapped: true, - Config: noFeesTestConfig, - }, + backend: defaultTestBackend(true, nil), } }, expectedErr: errTestSyntacticVerifyFail, @@ -170,10 +164,7 @@ func TestManagerVerifyTx(t *testing.T) { state.EXPECT().GetTimestamp().Return(time.Time{}) return &manager{ - backend: &executor.Backend{ - Bootstrapped: true, - Config: noFeesTestConfig, - }, + backend: defaultTestBackend(true, nil), state: state, lastAccepted: lastAcceptedID, } @@ -203,10 +194,7 @@ func TestManagerVerifyTx(t *testing.T) { state.EXPECT().GetTimestamp().Return(time.Time{}) return &manager{ - backend: &executor.Backend{ - Bootstrapped: true, - Config: noFeesTestConfig, - }, + backend: defaultTestBackend(true, nil), state: state, lastAccepted: lastAcceptedID, } @@ -236,10 +224,7 @@ func TestManagerVerifyTx(t *testing.T) { state.EXPECT().GetTimestamp().Return(time.Time{}) return &manager{ - backend: &executor.Backend{ - Bootstrapped: true, - Config: noFeesTestConfig, - }, + backend: defaultTestBackend(true, nil), state: state, lastAccepted: lastAcceptedID, } From dca34a5297c904c4859ed563c5863b1496676bc1 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 11 Mar 2024 10:56:25 +0100 Subject: [PATCH 13/27] fixed merge --- codec/reflectcodec/type_codec.go | 4 ---- codec/test_codec.go | 3 ++- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/codec/reflectcodec/type_codec.go b/codec/reflectcodec/type_codec.go index c3da55c22a8..486ab006f3f 100644 --- a/codec/reflectcodec/type_codec.go +++ b/codec/reflectcodec/type_codec.go @@ -157,10 +157,6 @@ func (c *genericCodec) size( return 0, false, err } - if size == 0 { - return 0, false, fmt.Errorf("can't marshal slice of zero length values: %w", codec.ErrMarshalZeroLength) - } - // For fixed-size types we manually calculate lengths rather than // processing each element separately to improve performance. if constSize { diff --git a/codec/test_codec.go b/codec/test_codec.go index 809cd84f21c..37127f0de9b 100644 --- a/codec/test_codec.go +++ b/codec/test_codec.go @@ -864,8 +864,9 @@ func TestSliceWithEmptySerializationError(codec GeneralCodec, t testing.TB) { _, err := manager.Marshal(0, val) require.ErrorIs(err, ErrMarshalZeroLength) + // we cannot marshal/unmarshal an empty slice, but we can ask its size _, err = manager.Size(0, val) - require.ErrorIs(err, ErrMarshalZeroLength) + require.NoError(err) b := []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x01} // codec version (0x00, 0x00) then (0x00, 0x00, 0x00, 0x01) for numElts From cd989f37d630472cb2b5fd98b8c1125c35598685 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 11 Mar 2024 15:18:37 +0100 Subject: [PATCH 14/27] nits from code reviews --- vms/avm/config/config.go | 2 +- vms/platformvm/config/config.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/vms/avm/config/config.go b/vms/avm/config/config.go index 42e37b678a0..fb376fb77a3 100644 --- a/vms/avm/config/config.go +++ b/vms/avm/config/config.go @@ -20,6 +20,6 @@ type Config struct { EUpgradeTime time.Time } -func (c *Config) IsEUpgradeActivated(timestamp time.Time) bool { +func (c *Config) IsEUActivated(timestamp time.Time) bool { return !timestamp.Before(c.EUpgradeTime) } diff --git a/vms/platformvm/config/config.go b/vms/platformvm/config/config.go index 0ac37f81f08..0c5fcf15a47 100644 --- a/vms/platformvm/config/config.go +++ b/vms/platformvm/config/config.go @@ -140,7 +140,7 @@ func (c *Config) IsDurangoActivated(timestamp time.Time) bool { return !timestamp.Before(c.DurangoTime) } -func (c *Config) IsEForkActivated(timestamp time.Time) bool { +func (c *Config) IsEActivated(timestamp time.Time) bool { return !timestamp.Before(c.EUpgradeTime) } From 32da156991d9c6fd5320cb697a2fa81b1b25c7ec Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 11 Mar 2024 15:34:13 +0100 Subject: [PATCH 15/27] some more nits from code reviews --- .../executor/staker_tx_verification_test.go | 24 +++---- .../txs/executor/standard_tx_executor_test.go | 70 ++++++++++++++----- 2 files changed, 64 insertions(+), 30 deletions(-) diff --git a/vms/platformvm/txs/executor/staker_tx_verification_test.go b/vms/platformvm/txs/executor/staker_tx_verification_test.go index a4c65395ba0..f9081fdf5de 100644 --- a/vms/platformvm/txs/executor/staker_tx_verification_test.go +++ b/vms/platformvm/txs/executor/staker_tx_verification_test.go @@ -110,7 +110,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { backendF: func(*gomock.Controller) *Backend { return &Backend{ Ctx: ctx, - Config: defaultTestConfig(activeForkTime), + Config: defaultTestConfig(t, durango, activeForkTime), } }, stateF: func(*gomock.Controller) state.Chain { @@ -129,7 +129,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { backendF: func(*gomock.Controller) *Backend { return &Backend{ Ctx: ctx, - Config: defaultTestConfig(activeForkTime), + Config: defaultTestConfig(t, durango, activeForkTime), Bootstrapped: &utils.Atomic[bool]{}, } }, @@ -181,7 +181,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { bootstrapped.Set(true) return &Backend{ Ctx: ctx, - Config: defaultTestConfig(activeForkTime), + Config: defaultTestConfig(t, durango, activeForkTime), Bootstrapped: bootstrapped, } }, @@ -208,7 +208,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { bootstrapped.Set(true) return &Backend{ Ctx: ctx, - Config: defaultTestConfig(activeForkTime), + Config: defaultTestConfig(t, durango, activeForkTime), Bootstrapped: bootstrapped, } }, @@ -235,7 +235,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { bootstrapped.Set(true) return &Backend{ Ctx: ctx, - Config: defaultTestConfig(activeForkTime), + Config: defaultTestConfig(t, durango, activeForkTime), Bootstrapped: bootstrapped, } }, @@ -263,7 +263,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { bootstrapped.Set(true) return &Backend{ Ctx: ctx, - Config: defaultTestConfig(activeForkTime), + Config: defaultTestConfig(t, durango, activeForkTime), Bootstrapped: bootstrapped, } }, @@ -294,7 +294,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { bootstrapped.Set(true) return &Backend{ Ctx: ctx, - Config: defaultTestConfig(activeForkTime), + Config: defaultTestConfig(t, durango, activeForkTime), Bootstrapped: bootstrapped, } }, @@ -325,7 +325,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { bootstrapped.Set(true) return &Backend{ Ctx: ctx, - Config: defaultTestConfig(activeForkTime), + Config: defaultTestConfig(t, durango, activeForkTime), Bootstrapped: bootstrapped, } }, @@ -358,7 +358,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { bootstrapped.Set(true) return &Backend{ Ctx: ctx, - Config: defaultTestConfig(activeForkTime), + Config: defaultTestConfig(t, durango, activeForkTime), Bootstrapped: bootstrapped, } }, @@ -385,7 +385,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { bootstrapped.Set(true) return &Backend{ Ctx: ctx, - Config: defaultTestConfig(activeForkTime), + Config: defaultTestConfig(t, durango, activeForkTime), Bootstrapped: bootstrapped, } }, @@ -426,7 +426,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { gomock.Any(), ).Return(ErrFlowCheckFailed) - cfg := defaultTestConfig(activeForkTime) + cfg := defaultTestConfig(t, durango, activeForkTime) cfg.AddSubnetValidatorFee = 1 return &Backend{ @@ -472,7 +472,7 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { gomock.Any(), ).Return(nil) - cfg := defaultTestConfig(activeForkTime) + cfg := defaultTestConfig(t, durango, activeForkTime) cfg.AddSubnetValidatorFee = 1 return &Backend{ diff --git a/vms/platformvm/txs/executor/standard_tx_executor_test.go b/vms/platformvm/txs/executor/standard_tx_executor_test.go index 9fca25a9a28..6e58a4bcfda 100644 --- a/vms/platformvm/txs/executor/standard_tx_executor_test.go +++ b/vms/platformvm/txs/executor/standard_tx_executor_test.go @@ -5,6 +5,7 @@ package executor import ( "errors" + "fmt" "math" "testing" "time" @@ -1503,7 +1504,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { env.state.EXPECT().AddUTXO(gomock.Any()).Times(len(env.unsignedTx.Outs)) e := &StandardTxExecutor{ Backend: &Backend{ - Config: defaultTestConfig(env.latestForkTime), + Config: defaultTestConfig(t, durango, env.latestForkTime), Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, @@ -1526,7 +1527,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { env.state = state.NewMockDiff(ctrl) e := &StandardTxExecutor{ Backend: &Backend{ - Config: defaultTestConfig(env.latestForkTime), + Config: defaultTestConfig(t, durango, env.latestForkTime), Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, @@ -1550,7 +1551,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { env.state.EXPECT().GetPendingValidator(env.unsignedTx.Subnet, env.unsignedTx.NodeID).Return(nil, database.ErrNotFound) e := &StandardTxExecutor{ Backend: &Backend{ - Config: defaultTestConfig(env.latestForkTime), + Config: defaultTestConfig(t, durango, env.latestForkTime), Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, @@ -1577,7 +1578,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { env.state.EXPECT().GetCurrentValidator(env.unsignedTx.Subnet, env.unsignedTx.NodeID).Return(&staker, nil).Times(1) e := &StandardTxExecutor{ Backend: &Backend{ - Config: defaultTestConfig(env.latestForkTime), + Config: defaultTestConfig(t, durango, env.latestForkTime), Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, @@ -1602,7 +1603,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { env.state.EXPECT().GetCurrentValidator(env.unsignedTx.Subnet, env.unsignedTx.NodeID).Return(env.staker, nil) e := &StandardTxExecutor{ Backend: &Backend{ - Config: defaultTestConfig(env.latestForkTime), + Config: defaultTestConfig(t, durango, env.latestForkTime), Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, @@ -1626,7 +1627,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { env.state.EXPECT().GetSubnetOwner(env.unsignedTx.Subnet).Return(nil, database.ErrNotFound) e := &StandardTxExecutor{ Backend: &Backend{ - Config: defaultTestConfig(env.latestForkTime), + Config: defaultTestConfig(t, durango, env.latestForkTime), Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, @@ -1652,7 +1653,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { env.fx.EXPECT().VerifyPermission(gomock.Any(), env.unsignedTx.SubnetAuth, env.tx.Creds[len(env.tx.Creds)-1], subnetOwner).Return(errTest) e := &StandardTxExecutor{ Backend: &Backend{ - Config: defaultTestConfig(env.latestForkTime), + Config: defaultTestConfig(t, durango, env.latestForkTime), Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, @@ -1681,7 +1682,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { ).Return(errTest) e := &StandardTxExecutor{ Backend: &Backend{ - Config: defaultTestConfig(env.latestForkTime), + Config: defaultTestConfig(t, durango, env.latestForkTime), Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, @@ -1834,7 +1835,7 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { env.state = state.NewMockDiff(ctrl) e := &StandardTxExecutor{ Backend: &Backend{ - Config: defaultTestConfig(env.latestForkTime), + Config: defaultTestConfig(t, durango, env.latestForkTime), Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, @@ -1857,7 +1858,7 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { env.state.EXPECT().GetTimestamp().Return(env.latestForkTime) e := &StandardTxExecutor{ Backend: &Backend{ - Config: defaultTestConfig(env.latestForkTime), + Config: defaultTestConfig(t, durango, env.latestForkTime), Bootstrapped: &utils.Atomic[bool]{}, Fx: env.fx, FlowChecker: env.flowChecker, @@ -1880,7 +1881,7 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { env.state = state.NewMockDiff(ctrl) env.state.EXPECT().GetTimestamp().Return(env.latestForkTime) - cfg := defaultTestConfig(env.latestForkTime) + cfg := defaultTestConfig(t, durango, env.latestForkTime) cfg.MaxStakeDuration = math.MaxInt64 e := &StandardTxExecutor{ @@ -1913,7 +1914,7 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), ).Return(ErrFlowCheckFailed) - cfg := defaultTestConfig(env.latestForkTime) + cfg := defaultTestConfig(t, durango, env.latestForkTime) cfg.MaxStakeDuration = math.MaxInt64 e := &StandardTxExecutor{ @@ -1951,7 +1952,7 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { env.state.EXPECT().DeleteUTXO(gomock.Any()).Times(len(env.unsignedTx.Ins)) env.state.EXPECT().AddUTXO(gomock.Any()).Times(len(env.unsignedTx.Outs)) - cfg := defaultTestConfig(env.latestForkTime) + cfg := defaultTestConfig(t, durango, env.latestForkTime) cfg.MaxStakeDuration = math.MaxInt64 e := &StandardTxExecutor{ @@ -1983,11 +1984,44 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { } } -func defaultTestConfig(latestForkTime time.Time) *config.Config { +func defaultTestConfig(t *testing.T, f fork, tm time.Time) *config.Config { //nolint: unparam + var ( + apricotPhase3Time = mockable.MaxTime + apricotPhase5Time = mockable.MaxTime + banffTime = mockable.MaxTime + cortinaTime = mockable.MaxTime + durangoTime = mockable.MaxTime + eUpgradeTime = mockable.MaxTime + ) + + switch f { + case eUpgrade: + eUpgradeTime = tm + fallthrough + case durango: + durangoTime = tm + fallthrough + case cortina: + cortinaTime = tm + fallthrough + case banff: + banffTime = tm + fallthrough + case apricotPhase5: + apricotPhase5Time = tm + fallthrough + case apricotPhase3: + apricotPhase3Time = tm + default: + require.FailNow(t, fmt.Sprintf("unhandled fork %d", f)) + } + return &config.Config{ - BanffTime: latestForkTime, - CortinaTime: latestForkTime, - DurangoTime: latestForkTime, - EUpgradeTime: mockable.MaxTime, + EUpgradeTime: eUpgradeTime, + DurangoTime: durangoTime, + CortinaTime: cortinaTime, + BanffTime: banffTime, + ApricotPhase5Time: apricotPhase5Time, + ApricotPhase3Time: apricotPhase3Time, } } From d2525d5d2160a11984cb60e86cfe67afd1ba0f4c Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Mon, 11 Mar 2024 16:06:17 +0100 Subject: [PATCH 16/27] fixed merge --- codec/test_codec.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/codec/test_codec.go b/codec/test_codec.go index 910e72da917..2712d2ada9f 100644 --- a/codec/test_codec.go +++ b/codec/test_codec.go @@ -8,6 +8,8 @@ import ( "testing" "github.com/stretchr/testify/require" + + "github.com/ava-labs/avalanchego/utils/wrappers" ) var ( From 7a17a9bfe5fffbacc023ae91e978c6682364bf7f Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Wed, 13 Mar 2024 17:43:54 +0100 Subject: [PATCH 17/27] drop DurangoTime from avm config --- vms/avm/block/executor/block_test.go | 1 - vms/avm/config/config.go | 5 +---- vms/avm/environment_test.go | 10 ++-------- vms/avm/txs/executor/syntactic_verifier_test.go | 2 -- 4 files changed, 3 insertions(+), 15 deletions(-) diff --git a/vms/avm/block/executor/block_test.go b/vms/avm/block/executor/block_test.go index e8b08ab0346..8e72f4c21eb 100644 --- a/vms/avm/block/executor/block_test.go +++ b/vms/avm/block/executor/block_test.go @@ -1046,7 +1046,6 @@ func defaultTestBackend(bootstrapped bool, sharedMemory atomic.SharedMemory) *ex Log: logging.NoLog{}, }, Config: &config.Config{ - DurangoTime: time.Time{}, EUpgradeTime: mockable.MaxTime, TxFee: 0, CreateAssetTxFee: 0, diff --git a/vms/avm/config/config.go b/vms/avm/config/config.go index fb376fb77a3..0d026eb05db 100644 --- a/vms/avm/config/config.go +++ b/vms/avm/config/config.go @@ -13,13 +13,10 @@ type Config struct { // Fee that must be burned by every asset creating transaction CreateAssetTxFee uint64 - // Time of the Durango network upgrade - DurangoTime time.Time - // Time of the E network upgrade EUpgradeTime time.Time } -func (c *Config) IsEUActivated(timestamp time.Time) bool { +func (c *Config) IsEActivated(timestamp time.Time) bool { return !timestamp.Before(c.EUpgradeTime) } diff --git a/vms/avm/environment_test.go b/vms/avm/environment_test.go index 35db1462b94..1ab7cf068d7 100644 --- a/vms/avm/environment_test.go +++ b/vms/avm/environment_test.go @@ -80,7 +80,6 @@ var ( addrs []ids.ShortID // addrs[i] corresponds to keys[i] noFeesTestConfig = &config.Config{ - DurangoTime: time.Time{}, EUpgradeTime: mockable.MaxTime, TxFee: 0, CreateAssetTxFee: 0, @@ -236,17 +235,13 @@ func setup(tb testing.TB, c *envConfig) *environment { } func staticConfig(tb testing.TB, f fork) config.Config { - var ( - durangoTime = mockable.MaxTime - eUpgradeTime = mockable.MaxTime - ) + var eUpgradeTime time.Time switch f { case eUpgrade: eUpgradeTime = time.Time{} - fallthrough case durango: - durangoTime = time.Time{} + eUpgradeTime = mockable.MaxTime default: require.FailNow(tb, fmt.Sprintf("unhandled fork %d", f)) } @@ -254,7 +249,6 @@ func staticConfig(tb testing.TB, f fork) config.Config { return config.Config{ TxFee: testTxFee, CreateAssetTxFee: testTxFee, - DurangoTime: durangoTime, EUpgradeTime: eUpgradeTime, } } diff --git a/vms/avm/txs/executor/syntactic_verifier_test.go b/vms/avm/txs/executor/syntactic_verifier_test.go index a95df8354c0..c5762a81c74 100644 --- a/vms/avm/txs/executor/syntactic_verifier_test.go +++ b/vms/avm/txs/executor/syntactic_verifier_test.go @@ -7,7 +7,6 @@ import ( "math" "strings" "testing" - "time" "github.com/stretchr/testify/require" @@ -31,7 +30,6 @@ var ( feeConfig = config.Config{ TxFee: 2, CreateAssetTxFee: 3, - DurangoTime: time.Time{}, EUpgradeTime: mockable.MaxTime, } ) From 29067561e1dbb7d9965b652c96644c19153af21e Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Wed, 13 Mar 2024 17:48:53 +0100 Subject: [PATCH 18/27] nit --- .../txs/executor/standard_tx_executor_test.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/vms/platformvm/txs/executor/standard_tx_executor_test.go b/vms/platformvm/txs/executor/standard_tx_executor_test.go index 6e58a4bcfda..eef52f4b46d 100644 --- a/vms/platformvm/txs/executor/standard_tx_executor_test.go +++ b/vms/platformvm/txs/executor/standard_tx_executor_test.go @@ -2017,11 +2017,11 @@ func defaultTestConfig(t *testing.T, f fork, tm time.Time) *config.Config { //no } return &config.Config{ - EUpgradeTime: eUpgradeTime, - DurangoTime: durangoTime, - CortinaTime: cortinaTime, - BanffTime: banffTime, - ApricotPhase5Time: apricotPhase5Time, ApricotPhase3Time: apricotPhase3Time, + ApricotPhase5Time: apricotPhase5Time, + BanffTime: banffTime, + CortinaTime: cortinaTime, + DurangoTime: durangoTime, + EUpgradeTime: eUpgradeTime, } } From d3edbaae5618518da96d55b712f9bb46dd06140a Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Wed, 13 Mar 2024 17:52:11 +0100 Subject: [PATCH 19/27] nit --- .../txs/executor/staker_tx_verification_test.go | 8 ++------ vms/platformvm/txs/executor/standard_tx_executor_test.go | 2 +- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/vms/platformvm/txs/executor/staker_tx_verification_test.go b/vms/platformvm/txs/executor/staker_tx_verification_test.go index f9081fdf5de..24e1df2a0db 100644 --- a/vms/platformvm/txs/executor/staker_tx_verification_test.go +++ b/vms/platformvm/txs/executor/staker_tx_verification_test.go @@ -152,12 +152,8 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { bootstrapped := &utils.Atomic[bool]{} bootstrapped.Set(true) return &Backend{ - Ctx: ctx, - Config: &config.Config{ - CortinaTime: activeForkTime, - DurangoTime: mockable.MaxTime, - EUpgradeTime: mockable.MaxTime, - }, + Ctx: ctx, + Config: defaultTestConfig(t, cortina, activeForkTime), Bootstrapped: bootstrapped, } }, diff --git a/vms/platformvm/txs/executor/standard_tx_executor_test.go b/vms/platformvm/txs/executor/standard_tx_executor_test.go index eef52f4b46d..f8d5a76811c 100644 --- a/vms/platformvm/txs/executor/standard_tx_executor_test.go +++ b/vms/platformvm/txs/executor/standard_tx_executor_test.go @@ -1984,7 +1984,7 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { } } -func defaultTestConfig(t *testing.T, f fork, tm time.Time) *config.Config { //nolint: unparam +func defaultTestConfig(t *testing.T, f fork, tm time.Time) *config.Config { var ( apricotPhase3Time = mockable.MaxTime apricotPhase5Time = mockable.MaxTime From bd2311e437425e7f5279410e2fc5bb3629c51349 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Wed, 27 Mar 2024 09:41:34 +0100 Subject: [PATCH 20/27] reverted unnecessary changes --- codec/manager.go | 4 +- codec/reflectcodec/type_codec.go | 10 ++- codec/test_codec.go | 86 +--------------------- vms/platformvm/state/metadata_validator.go | 2 +- 4 files changed, 11 insertions(+), 91 deletions(-) diff --git a/codec/manager.go b/codec/manager.go index bf1ad3af72b..27e5e392260 100644 --- a/codec/manager.go +++ b/codec/manager.go @@ -13,7 +13,7 @@ import ( ) const ( - CodecVersionSize = wrappers.ShortLen + VersionSize = wrappers.ShortLen // default max size, in bytes, of something being marshalled by Marshal() defaultMaxSize = 256 * units.KiB @@ -105,7 +105,7 @@ func (m *manager) Size(version uint16, value interface{}) (int, error) { res, err := c.Size(value) // Add [CodecVersionSize] for the codec version - return CodecVersionSize + res, err + return VersionSize + res, err } // To marshal an interface, [value] must be a pointer to the interface. diff --git a/codec/reflectcodec/type_codec.go b/codec/reflectcodec/type_codec.go index bfec299a3e5..45818a74181 100644 --- a/codec/reflectcodec/type_codec.go +++ b/codec/reflectcodec/type_codec.go @@ -82,7 +82,7 @@ func New(typer TypeCodec, tagNames []string) codec.Codec { func (c *genericCodec) Size(value interface{}) (int, error) { if value == nil { - return 0, nil // can't marshal nil, we return zero size + return 0, codec.ErrMarshalNil // can't marshal nil, we return zero size } size, _, err := c.size(reflect.ValueOf(value), nil /*=typeStack*/) @@ -118,14 +118,14 @@ func (c *genericCodec) size( return wrappers.StringLen(value.String()), false, nil case reflect.Ptr: if value.IsNil() { - return 0, false, nil // can't marshal nil, we return zero size + return 0, false, codec.ErrMarshalNil // can't marshal nil, we return zero size } return c.size(value.Elem(), typeStack) case reflect.Interface: if value.IsNil() { - return 0, false, nil // can't marshal nil, we return zero size + return 0, false, codec.ErrMarshalNil // can't marshal nil, we return zero size } underlyingValue := value.Interface() @@ -152,6 +152,10 @@ func (c *genericCodec) size( return 0, false, err } + if size == 0 { + return 0, false, fmt.Errorf("can't marshal slice of zero length values: %w", codec.ErrMarshalZeroLength) + } + // For fixed-size types we manually calculate lengths rather than // processing each element separately to improve performance. if constSize { diff --git a/codec/test_codec.go b/codec/test_codec.go index 2712d2ada9f..2dc8b3e2add 100644 --- a/codec/test_codec.go +++ b/codec/test_codec.go @@ -8,15 +8,11 @@ import ( "testing" "github.com/stretchr/testify/require" - - "github.com/ava-labs/avalanchego/utils/wrappers" ) var ( Tests = []func(c GeneralCodec, t testing.TB){ TestStruct, - TestPartiallyFilledStruct, - TestSliceWithEmptyElements, TestRegisterStructTwice, TestUInt32, TestUIntPtr, @@ -245,85 +241,6 @@ func TestStruct(codec GeneralCodec, t testing.TB) { require.Equal(myStructInstance, *myStructUnmarshaled) } -func TestPartiallyFilledStruct(codec GeneralCodec, t testing.TB) { - require := require.New(t) - - manager := NewDefaultManager() - require.NoError(manager.RegisterCodec(0, codec)) - - // a nil pointer cannot be marshalled but we can get its size - var nilStruct *myStruct - _, err := manager.Marshal(0, nilStruct) - require.ErrorIs(err, ErrMarshalNil) - - bytesLen, err := manager.Size(0, nilStruct) - require.NoError(err) - require.Equal(CodecVersionSize, bytesLen) - - // an empty struct cannot be marshalled but we can get its size - emptyStruct := &myStruct{} - _, err = manager.Marshal(0, nilStruct) - require.ErrorIs(err, ErrMarshalNil) - - emptyStructLen := CodecVersionSize + 117 - bytesLen, err = manager.Size(0, emptyStruct) - require.NoError(err) - require.Equal(emptyStructLen, bytesLen) - - // an partially filled struct cannot be marshalled but we can get its size - elem := &MyInnerStruct{ - Str: "a", - } - elemLen := CodecVersionSize + wrappers.StringLen(elem.Str) - - partialStruct := &myStruct{ - InnerStruct2: elem, - } - partialStructLen := emptyStructLen + elemLen - CodecVersionSize - bytesLen, err = manager.Size(0, partialStruct) - require.NoError(err) - require.Equal(partialStructLen, bytesLen) -} - -func TestSliceWithEmptyElements(codec GeneralCodec, t testing.TB) { - require := require.New(t) - - manager := NewDefaultManager() - require.NoError(manager.RegisterCodec(0, codec)) - - // a non-empty slice with nil pointers cannot be marshalled but we can get its size - slice := make([]*MyInnerStruct, 10) - - _, err := manager.Marshal(0, slice) - require.ErrorIs(err, ErrMarshalNil) - - emptySliceLen := CodecVersionSize + wrappers.IntLen // Codec version + slice size. Slice elements have zero size - bytesLen, err := manager.Size(0, slice) - require.NoError(err) - require.Equal(emptySliceLen, bytesLen) - - elem := &MyInnerStruct{ - Str: "aaa", - } - elemLen := CodecVersionSize + wrappers.StringLen(elem.Str) - bytesLen, err = manager.Size(0, elem) - require.NoError(err) - require.Equal(elemLen, bytesLen) - - // we can fill some elements and leave other empty. Size will be sub-additive - slice[1] = elem - sliceLen := emptySliceLen + elemLen - CodecVersionSize // codec version is marshelled only once - bytesLen, err = manager.Size(0, slice) - require.NoError(err) - require.Equal(sliceLen, bytesLen) - - slice[5] = elem - sliceLen += elemLen - CodecVersionSize // codec version is marshelled only once - bytesLen, err = manager.Size(0, slice) - require.NoError(err) - require.Equal(sliceLen, bytesLen) -} - func TestRegisterStructTwice(codec GeneralCodec, t testing.TB) { require := require.New(t) @@ -856,9 +773,8 @@ func TestSliceWithEmptySerializationError(codec GeneralCodec, t testing.TB) { _, err := manager.Marshal(0, val) require.ErrorIs(err, ErrMarshalZeroLength) - // we cannot marshal/unmarshal an empty slice, but we can ask its size _, err = manager.Size(0, val) - require.NoError(err) + require.ErrorIs(err, ErrMarshalZeroLength) b := []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x01} // codec version (0x00, 0x00) then (0x00, 0x00, 0x00, 0x01) for numElts diff --git a/vms/platformvm/state/metadata_validator.go b/vms/platformvm/state/metadata_validator.go index 74242150d37..340c7205350 100644 --- a/vms/platformvm/state/metadata_validator.go +++ b/vms/platformvm/state/metadata_validator.go @@ -18,7 +18,7 @@ import ( // [preDelegateeRewardMetadata]. // // CodecVersionLen + UpDurationLen + LastUpdatedLen + PotentialRewardLen -const preDelegateeRewardSize = codec.CodecVersionSize + 3*wrappers.LongLen +const preDelegateeRewardSize = codec.VersionSize + 3*wrappers.LongLen var _ validatorState = (*metadata)(nil) From d637d8b6872278a6cefba6b618b0800315e41d8c Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 28 Mar 2024 22:05:45 +0100 Subject: [PATCH 21/27] unlocked UT --- .../txs/executor/semantic_verifier_test.go | 451 ++++++++++++++++++ .../txs/executor/syntactic_verifier_test.go | 204 -------- 2 files changed, 451 insertions(+), 204 deletions(-) diff --git a/vms/avm/txs/executor/semantic_verifier_test.go b/vms/avm/txs/executor/semantic_verifier_test.go index f1e856dc0ca..7f67c771072 100644 --- a/vms/avm/txs/executor/semantic_verifier_test.go +++ b/vms/avm/txs/executor/semantic_verifier_test.go @@ -22,11 +22,14 @@ import ( "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/utils/units" "github.com/ava-labs/avalanchego/vms/avm/fxs" "github.com/ava-labs/avalanchego/vms/avm/state" "github.com/ava-labs/avalanchego/vms/avm/txs" "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/components/verify" + "github.com/ava-labs/avalanchego/vms/nftfx" + "github.com/ava-labs/avalanchego/vms/propertyfx" "github.com/ava-labs/avalanchego/vms/secp256k1fx" safemath "github.com/ava-labs/avalanchego/utils/math" @@ -2085,3 +2088,451 @@ func TestSemanticVerifierImportTx(t *testing.T) { }) } } + +func TestSemanticVerifierOperationTx(t *testing.T) { + ctx := snowtest.Context(t, snowtest.XChainID) + + var ( + secpFx = &secp256k1fx.Fx{} + nftFx = &nftfx.Fx{} + propertyFx = &propertyfx.Fx{} + ) + + typeToFxIndex := make(map[reflect.Type]int) + parser, err := txs.NewCustomParser( + typeToFxIndex, + new(mockable.Clock), + logging.NoWarn{}, + []fxs.Fx{ + secpFx, + nftFx, + propertyFx, + }, + ) + + require.NoError(t, err) + codec := parser.Codec() + + feeAssetID := ids.GenerateTestID() + feeAsset := avax.Asset{ + ID: feeAssetID, + } + + outputOwners := secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{ + keys[0].Address(), + }, + } + + utxoAmount := 20 * units.KiloAvax + utxoID := avax.UTXOID{ + TxID: ids.GenerateTestID(), + OutputIndex: 1, + } + utxo := &avax.UTXO{ + UTXOID: utxoID, + Asset: feeAsset, + Out: &secp256k1fx.TransferOutput{ + Amt: 20 * units.KiloAvax, + OutputOwners: outputOwners, + }, + } + + opUTXOID := avax.UTXOID{ + TxID: ids.GenerateTestID(), + OutputIndex: 1, + } + opUTXO := &avax.UTXO{ + UTXOID: opUTXOID, + Asset: avax.Asset{ID: assetID}, + Out: &secp256k1fx.MintOutput{ + OutputOwners: outputOwners, + }, + } + + unsignedCreateAssetTx := txs.CreateAssetTx{ + States: []*txs.InitialState{{ + FxIndex: 0, + }}, + } + createAssetTx := &txs.Tx{ + Unsigned: &unsignedCreateAssetTx, + } + + opTxInSigner := secp256k1fx.Input{ + SigIndices: []uint32{ + 0, + }, + } + opTxIn := avax.TransferableInput{ + UTXOID: utxoID, + Asset: feeAsset, + In: &secp256k1fx.TransferInput{ + Amt: utxoAmount, + Input: opTxInSigner, + }, + } + opTxOut := avax.TransferableOutput{ + Asset: avax.Asset{ID: feeAssetID}, + Out: &secp256k1fx.TransferOutput{ + Amt: units.NanoAvax, + OutputOwners: outputOwners, + }, + } + unsignedOperationTx := txs.OperationTx{ + BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ + NetworkID: constants.UnitTestID, + BlockchainID: chainID, + Ins: []*avax.TransferableInput{&opTxIn}, + Outs: []*avax.TransferableOutput{&opTxOut}, + }}, + Ops: []*txs.Operation{{ + Asset: avax.Asset{ID: assetID}, + UTXOIDs: []*avax.UTXOID{ + &opUTXOID, + }, + Op: &secp256k1fx.MintOperation{ + MintInput: secp256k1fx.Input{ + SigIndices: []uint32{0}, + }, + MintOutput: secp256k1fx.MintOutput{ + OutputOwners: outputOwners, + }, + TransferOutput: secp256k1fx.TransferOutput{ + Amt: 1, + OutputOwners: outputOwners, + }, + }, + }}, + } + + operationTx := txs.Tx{Unsigned: &unsignedOperationTx} + require.NoError(t, operationTx.SignSECP256K1Fx( + codec, + [][]*secp256k1.PrivateKey{ + {keys[0]}, + {keys[0]}, + }, + )) + + backend := &Backend{ + Ctx: ctx, + Config: &feeConfig, + Fxs: []*fxs.ParsedFx{ + { + ID: secp256k1fx.ID, + Fx: secpFx, + }, + { + ID: nftfx.ID, + Fx: nftFx, + }, + { + ID: propertyfx.ID, + Fx: propertyFx, + }, + }, + Codec: codec, + TypeToFxIndex: typeToFxIndex, + FeeAssetID: feeAssetID, + } + require.NoError(t, secpFx.Bootstrapped()) + require.NoError(t, nftFx.Bootstrapped()) + require.NoError(t, propertyFx.Bootstrapped()) + + tests := []struct { + name string + stateFunc func(*gomock.Controller) state.Chain + txFunc func(*require.Assertions) *txs.Tx + expectedErr error + }{ + { + name: "valid", + stateFunc: func(ctrl *gomock.Controller) state.Chain { + state := state.NewMockChain(ctrl) + state.EXPECT().GetUTXO(utxoID.InputID()).Return(utxo, nil).AnyTimes() + state.EXPECT().GetUTXO(opUTXO.InputID()).Return(opUTXO, nil).AnyTimes() + state.EXPECT().GetTx(feeAssetID).Return(createAssetTx, nil).AnyTimes() + return state + }, + txFunc: func(*require.Assertions) *txs.Tx { + return &operationTx + }, + expectedErr: nil, + }, + { + name: "invalid output", + stateFunc: func(ctrl *gomock.Controller) state.Chain { + state := state.NewMockChain(ctrl) + return state + }, + txFunc: func(*require.Assertions) *txs.Tx { + output := opTxOut + output.Out = &secp256k1fx.TransferOutput{ + Amt: 0, + OutputOwners: outputOwners, + } + + unsignedTx := unsignedOperationTx + unsignedTx.Outs = []*avax.TransferableOutput{ + &output, + } + return &txs.Tx{ + Unsigned: &unsignedTx, + Creds: operationTx.Creds, + } + }, + expectedErr: secp256k1fx.ErrNoValueOutput, + }, + { + name: "unsorted outputs", + stateFunc: func(ctrl *gomock.Controller) state.Chain { + state := state.NewMockChain(ctrl) + return state + }, + txFunc: func(*require.Assertions) *txs.Tx { + output0 := opTxOut + output0.Out = &secp256k1fx.TransferOutput{ + Amt: 1, + OutputOwners: outputOwners, + } + + output1 := opTxOut + output1.Out = &secp256k1fx.TransferOutput{ + Amt: 2, + OutputOwners: outputOwners, + } + + outputs := []*avax.TransferableOutput{ + &output0, + &output1, + } + avax.SortTransferableOutputs(outputs, codec) + outputs[0], outputs[1] = outputs[1], outputs[0] + + unsignedTx := unsignedOperationTx + unsignedTx.Outs = outputs + return &txs.Tx{ + Unsigned: &unsignedTx, + Creds: operationTx.Creds, + } + }, + expectedErr: avax.ErrOutputsNotSorted, + }, + { + name: "invalid input", + stateFunc: func(ctrl *gomock.Controller) state.Chain { + state := state.NewMockChain(ctrl) + return state + }, + txFunc: func(*require.Assertions) *txs.Tx { + input := opTxIn + input.In = &secp256k1fx.TransferInput{ + Amt: 0, + Input: opTxInSigner, + } + + tx := unsignedOperationTx + tx.Ins = []*avax.TransferableInput{ + &input, + } + return &txs.Tx{ + Unsigned: &tx, + Creds: operationTx.Creds, + } + }, + expectedErr: secp256k1fx.ErrNoValueInput, + }, + { + name: "duplicate inputs", + stateFunc: func(ctrl *gomock.Controller) state.Chain { + state := state.NewMockChain(ctrl) + return state + }, + txFunc: func(*require.Assertions) *txs.Tx { + unsignedTx := unsignedOperationTx + unsignedTx.Ins = []*avax.TransferableInput{ + &opTxIn, + &opTxIn, + } + + tx := &txs.Tx{Unsigned: &unsignedTx} + require.NoError(t, tx.SignSECP256K1Fx( + codec, + [][]*secp256k1.PrivateKey{ + {keys[0]}, + {keys[0]}, + })) + + return tx + }, + expectedErr: avax.ErrInputsNotSortedUnique, + }, + { + name: "input overflow", + stateFunc: func(ctrl *gomock.Controller) state.Chain { + state := state.NewMockChain(ctrl) + return state + }, + txFunc: func(*require.Assertions) *txs.Tx { + input0 := opTxIn + input0.In = &secp256k1fx.TransferInput{ + Amt: 1, + Input: opTxInSigner, + } + + input1 := opTxIn + input1.UTXOID.OutputIndex++ + input1.In = &secp256k1fx.TransferInput{ + Amt: math.MaxUint64, + Input: opTxInSigner, + } + + unsignedTx := unsignedOperationTx + unsignedTx.Ins = []*avax.TransferableInput{ + &input0, + &input1, + } + avax.SortTransferableInputsWithSigners(unsignedTx.Ins, make([][]*secp256k1.PrivateKey, 2)) + + tx := &txs.Tx{Unsigned: &unsignedTx} + require.NoError(t, tx.SignSECP256K1Fx( + codec, + [][]*secp256k1.PrivateKey{ + {keys[0]}, + {keys[0]}, + })) + return tx + }, + expectedErr: safemath.ErrOverflow, + }, + { + name: "output overflow", + stateFunc: func(ctrl *gomock.Controller) state.Chain { + state := state.NewMockChain(ctrl) + return state + }, + txFunc: func(*require.Assertions) *txs.Tx { + output := opTxOut + output.Out = &secp256k1fx.TransferOutput{ + Amt: math.MaxUint64, + OutputOwners: outputOwners, + } + + outputs := []*avax.TransferableOutput{ + &output, + } + avax.SortTransferableOutputs(outputs, codec) + + unsignedTx := unsignedOperationTx + unsignedTx.Outs = outputs + return &txs.Tx{ + Unsigned: &unsignedTx, + Creds: operationTx.Creds, + } + }, + expectedErr: safemath.ErrOverflow, + }, + { + name: "insufficient funds", + stateFunc: func(ctrl *gomock.Controller) state.Chain { + state := state.NewMockChain(ctrl) + return state + }, + txFunc: func(*require.Assertions) *txs.Tx { + input := opTxIn + input.In = &secp256k1fx.TransferInput{ + Amt: 1, + Input: opTxInSigner, + } + + unsignedTx := unsignedOperationTx + unsignedTx.Ins = []*avax.TransferableInput{ + &input, + } + return &txs.Tx{ + Unsigned: &unsignedTx, + Creds: operationTx.Creds, + } + }, + expectedErr: avax.ErrInsufficientFunds, + }, + { + name: "barely sufficient funds", + stateFunc: func(ctrl *gomock.Controller) state.Chain { + state := state.NewMockChain(ctrl) + + barelySufficientUtxo := &avax.UTXO{ + UTXOID: utxoID, + Asset: feeAsset, + Out: &secp256k1fx.TransferOutput{ + Amt: units.NanoAvax + feeConfig.TxFee, + OutputOwners: outputOwners, + }, + } + + state.EXPECT().GetUTXO(utxoID.InputID()).Return(barelySufficientUtxo, nil).AnyTimes() + state.EXPECT().GetUTXO(opUTXO.InputID()).Return(opUTXO, nil).AnyTimes() + state.EXPECT().GetTx(feeAssetID).Return(createAssetTx, nil).AnyTimes() + return state + }, + txFunc: func(*require.Assertions) *txs.Tx { + input := opTxIn + input.In = &secp256k1fx.TransferInput{ + Amt: units.NanoAvax + feeConfig.TxFee, + Input: opTxInSigner, + } + + unsignedTx := unsignedOperationTx + unsignedTx.Ins = []*avax.TransferableInput{ + &input, + } + return &txs.Tx{ + Unsigned: &unsignedTx, + Creds: operationTx.Creds, + } + }, + expectedErr: nil, + }, + { + name: "barely insufficient funds", + stateFunc: func(ctrl *gomock.Controller) state.Chain { + state := state.NewMockChain(ctrl) + return state + }, + txFunc: func(*require.Assertions) *txs.Tx { + input := opTxIn + input.In = &secp256k1fx.TransferInput{ + Amt: feeConfig.TxFee, + Input: opTxInSigner, + } + + unsignedTx := unsignedOperationTx + unsignedTx.Ins = []*avax.TransferableInput{ + &input, + } + return &txs.Tx{ + Unsigned: &unsignedTx, + Creds: operationTx.Creds, + } + }, + expectedErr: avax.ErrInsufficientFunds, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + require := require.New(t) + ctrl := gomock.NewController(t) + + state := test.stateFunc(ctrl) + tx := test.txFunc(require) + err := tx.Unsigned.Visit(&SemanticVerifier{ + Backend: backend, + State: state, + Tx: tx, + }) + require.ErrorIs(err, test.expectedErr) + }) + } +} diff --git a/vms/avm/txs/executor/syntactic_verifier_test.go b/vms/avm/txs/executor/syntactic_verifier_test.go index d769913edee..ff566c69c03 100644 --- a/vms/avm/txs/executor/syntactic_verifier_test.go +++ b/vms/avm/txs/executor/syntactic_verifier_test.go @@ -751,170 +751,6 @@ func TestSyntacticVerifierOperationTx(t *testing.T) { }, err: avax.ErrMemoTooLarge, }, - // { - // name: "invalid output", - // txFunc: func() *txs.Tx { - // output := output - // output.Out = &secp256k1fx.TransferOutput{ - // Amt: 0, - // OutputOwners: outputOwners, - // } - - // tx := tx - // tx.Outs = []*avax.TransferableOutput{ - // &output, - // } - // return &txs.Tx{ - // Unsigned: &tx, - // Creds: creds, - // } - // }, - // err: secp256k1fx.ErrNoValueOutput, - // }, - // { - // name: "unsorted outputs", - // txFunc: func() *txs.Tx { - // output0 := output - // output0.Out = &secp256k1fx.TransferOutput{ - // Amt: 1, - // OutputOwners: outputOwners, - // } - - // output1 := output - // output1.Out = &secp256k1fx.TransferOutput{ - // Amt: 2, - // OutputOwners: outputOwners, - // } - - // outputs := []*avax.TransferableOutput{ - // &output0, - // &output1, - // } - // avax.SortTransferableOutputs(outputs, codec) - // outputs[0], outputs[1] = outputs[1], outputs[0] - - // tx := tx - // tx.Outs = outputs - // return &txs.Tx{ - // Unsigned: &tx, - // Creds: creds, - // } - // }, - // err: avax.ErrOutputsNotSorted, - // }, - // { - // name: "invalid input", - // txFunc: func() *txs.Tx { - // input := input - // input.In = &secp256k1fx.TransferInput{ - // Amt: 0, - // Input: inputSigners, - // } - - // tx := tx - // tx.Ins = []*avax.TransferableInput{ - // &input, - // } - // return &txs.Tx{ - // Unsigned: &tx, - // Creds: creds, - // } - // }, - // err: secp256k1fx.ErrNoValueInput, - // }, - // { - // name: "duplicate inputs", - // txFunc: func() *txs.Tx { - // tx := tx - // tx.Ins = []*avax.TransferableInput{ - // &input, - // &input, - // } - // return &txs.Tx{ - // Unsigned: &tx, - // Creds: []*fxs.FxCredential{ - // &cred, - // &cred, - // }, - // } - // }, - // err: avax.ErrInputsNotSortedUnique, - // }, - // { - // name: "input overflow", - // txFunc: func() *txs.Tx { - // input0 := input - // input0.In = &secp256k1fx.TransferInput{ - // Amt: 1, - // Input: inputSigners, - // } - - // input1 := input - // input1.UTXOID.OutputIndex++ - // input1.In = &secp256k1fx.TransferInput{ - // Amt: math.MaxUint64, - // Input: inputSigners, - // } - - // tx := tx - // tx.Ins = []*avax.TransferableInput{ - // &input0, - // &input1, - // } - // avax.SortTransferableInputsWithSigners(tx.Ins, make([][]*secp256k1.PrivateKey, 2)) - // return &txs.Tx{ - // Unsigned: &tx, - // Creds: []*fxs.FxCredential{ - // &cred, - // &cred, - // }, - // } - // }, - // err: safemath.ErrOverflow, - // }, - // { - // name: "output overflow", - // txFunc: func() *txs.Tx { - // output := output - // output.Out = &secp256k1fx.TransferOutput{ - // Amt: math.MaxUint64, - // OutputOwners: outputOwners, - // } - - // outputs := []*avax.TransferableOutput{ - // &output, - // } - // avax.SortTransferableOutputs(outputs, codec) - - // tx := tx - // tx.Outs = outputs - // return &txs.Tx{ - // Unsigned: &tx, - // Creds: creds, - // } - // }, - // err: safemath.ErrOverflow, - // }, - // { - // name: "insufficient funds", - // txFunc: func() *txs.Tx { - // input := input - // input.In = &secp256k1fx.TransferInput{ - // Amt: 1, - // Input: inputSigners, - // } - - // tx := tx - // tx.Ins = []*avax.TransferableInput{ - // &input, - // } - // return &txs.Tx{ - // Unsigned: &tx, - // Creds: creds, - // } - // }, - // err: avax.ErrInsufficientFunds, - // }, { name: "invalid nil op", txFunc: func() *txs.Tx { @@ -1025,46 +861,6 @@ func TestSyntacticVerifierOperationTx(t *testing.T) { }, err: errWrongNumberOfCredentials, }, - // { - // name: "barely sufficient funds", - // txFunc: func() *txs.Tx { - // input := input - // input.In = &secp256k1fx.TransferInput{ - // Amt: fxOutput.Amt + feeConfig.TxFee, - // Input: inputSigners, - // } - - // tx := tx - // tx.Ins = []*avax.TransferableInput{ - // &input, - // } - // return &txs.Tx{ - // Unsigned: &tx, - // Creds: creds, - // } - // }, - // err: nil, - // }, - // { - // name: "barely insufficient funds", - // txFunc: func() *txs.Tx { - // input := input - // input.In = &secp256k1fx.TransferInput{ - // Amt: fxOutput.Amt + feeConfig.TxFee - 1, - // Input: inputSigners, - // } - - // tx := tx - // tx.Ins = []*avax.TransferableInput{ - // &input, - // } - // return &txs.Tx{ - // Unsigned: &tx, - // Creds: creds, - // } - // }, - // err: avax.ErrInsufficientFunds, - // }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { From 3af2422b5aad2a3239ef56a9dee45a5c82f0ea5f Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Tue, 2 Apr 2024 17:24:03 +0200 Subject: [PATCH 22/27] introduced fee calculator constructor --- vms/avm/txs/executor/semantic_verifier.go | 6 ++---- vms/avm/txs/fees/calculator.go | 20 +++++++++++++------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/vms/avm/txs/executor/semantic_verifier.go b/vms/avm/txs/executor/semantic_verifier.go index d8d95d6313a..97692ee8c1b 100644 --- a/vms/avm/txs/executor/semantic_verifier.go +++ b/vms/avm/txs/executor/semantic_verifier.go @@ -131,10 +131,8 @@ func (v *SemanticVerifier) verifyBaseTx( importedIns []*avax.TransferableInput, exportedOuts []*avax.TransferableOutput, ) error { - feeCalculator := fees.Calculator{ - Config: v.Config, - } - if err := tx.Visit(&feeCalculator); err != nil { + feeCalculator := fees.NewStaticCalculator(v.Config) + 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 5bcf9d77099..d5339d72998 100644 --- a/vms/avm/txs/fees/calculator.go +++ b/vms/avm/txs/fees/calculator.go @@ -11,34 +11,40 @@ import ( var _ txs.Visitor = (*Calculator)(nil) type Calculator struct { - // Pre E-fork inputs - Config *config.Config + // Pre E update inputs + config *config.Config // outputs of visitor execution Fee uint64 } +func NewStaticCalculator(cfg *config.Config) *Calculator { + return &Calculator{ + config: cfg, + } +} + func (fc *Calculator) BaseTx(*txs.BaseTx) error { - fc.Fee = fc.Config.TxFee + fc.Fee = fc.config.TxFee return nil } func (fc *Calculator) CreateAssetTx(*txs.CreateAssetTx) error { - fc.Fee = fc.Config.CreateAssetTxFee + fc.Fee = fc.config.CreateAssetTxFee return nil } func (fc *Calculator) OperationTx(*txs.OperationTx) error { - fc.Fee = fc.Config.TxFee + fc.Fee = fc.config.TxFee return nil } func (fc *Calculator) ImportTx(*txs.ImportTx) error { - fc.Fee = fc.Config.TxFee + fc.Fee = fc.config.TxFee return nil } func (fc *Calculator) ExportTx(*txs.ExportTx) error { - fc.Fee = fc.Config.TxFee + fc.Fee = fc.config.TxFee return nil } From 8e0d84f32f1051da41009945f33441e590ca8362 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Fri, 12 Jul 2024 11:21:08 +0200 Subject: [PATCH 23/27] restructured calculator API --- vms/avm/txs/executor/semantic_verifier.go | 9 ++-- vms/avm/txs/fees/calculator.go | 47 ++----------------- vms/avm/txs/fees/static_calculator.go | 57 +++++++++++++++++++++++ 3 files changed, 66 insertions(+), 47 deletions(-) create mode 100644 vms/avm/txs/fees/static_calculator.go diff --git a/vms/avm/txs/executor/semantic_verifier.go b/vms/avm/txs/executor/semantic_verifier.go index 97692ee8c1b..b5451e35b19 100644 --- a/vms/avm/txs/executor/semantic_verifier.go +++ b/vms/avm/txs/executor/semantic_verifier.go @@ -131,13 +131,14 @@ func (v *SemanticVerifier) verifyBaseTx( importedIns []*avax.TransferableInput, exportedOuts []*avax.TransferableOutput, ) error { - feeCalculator := fees.NewStaticCalculator(v.Config) - if err := tx.Visit(feeCalculator); err != nil { + feeCalculator := fees.NewStaticCalculator(v.Backend.Config) + fee, err := feeCalculator.CalculateFee(&txs.Tx{Unsigned: tx}) + if err != nil { return err } - err := avax.VerifyTx( - feeCalculator.Fee, + err = avax.VerifyTx( + fee, v.FeeAssetID, [][]*avax.TransferableInput{tx.Ins, importedIns}, [][]*avax.TransferableOutput{tx.Outs, exportedOuts}, diff --git a/vms/avm/txs/fees/calculator.go b/vms/avm/txs/fees/calculator.go index d5339d72998..334f0d492d2 100644 --- a/vms/avm/txs/fees/calculator.go +++ b/vms/avm/txs/fees/calculator.go @@ -3,48 +3,9 @@ package fees -import ( - "github.com/ava-labs/avalanchego/vms/avm/config" - "github.com/ava-labs/avalanchego/vms/avm/txs" -) +import "github.com/ava-labs/avalanchego/vms/avm/txs" -var _ txs.Visitor = (*Calculator)(nil) - -type Calculator struct { - // Pre E update inputs - config *config.Config - - // outputs of visitor execution - Fee uint64 -} - -func NewStaticCalculator(cfg *config.Config) *Calculator { - return &Calculator{ - config: cfg, - } -} - -func (fc *Calculator) BaseTx(*txs.BaseTx) error { - fc.Fee = fc.config.TxFee - return nil -} - -func (fc *Calculator) CreateAssetTx(*txs.CreateAssetTx) error { - fc.Fee = fc.config.CreateAssetTxFee - return nil -} - -func (fc *Calculator) OperationTx(*txs.OperationTx) error { - fc.Fee = fc.config.TxFee - return nil -} - -func (fc *Calculator) ImportTx(*txs.ImportTx) error { - fc.Fee = fc.config.TxFee - return nil -} - -func (fc *Calculator) ExportTx(*txs.ExportTx) error { - fc.Fee = fc.config.TxFee - return nil +// Calculator is the interfaces that any fee Calculator must implement +type Calculator interface { + CalculateFee(tx *txs.Tx) (uint64, error) } diff --git a/vms/avm/txs/fees/static_calculator.go b/vms/avm/txs/fees/static_calculator.go new file mode 100644 index 00000000000..fe707131838 --- /dev/null +++ b/vms/avm/txs/fees/static_calculator.go @@ -0,0 +1,57 @@ +// 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/vms/avm/config" + "github.com/ava-labs/avalanchego/vms/avm/txs" +) + +var ( + _ Calculator = (*staticCalculator)(nil) + _ txs.Visitor = (*staticCalculator)(nil) +) + +func NewStaticCalculator(c *config.Config) Calculator { + return &staticCalculator{staticCfg: c} +} + +func (c *staticCalculator) CalculateFee(tx *txs.Tx) (uint64, error) { + c.fee = 0 // zero fee among different calculateFee invocations (unlike gas which gets cumulated) + err := tx.Unsigned.Visit(c) + return c.fee, err +} + +type staticCalculator struct { + // inputs + staticCfg *config.Config + + // outputs of visitor execution + fee uint64 +} + +func (c *staticCalculator) BaseTx(*txs.BaseTx) error { + c.fee = c.staticCfg.TxFee + return nil +} + +func (c *staticCalculator) CreateAssetTx(*txs.CreateAssetTx) error { + c.fee = c.staticCfg.CreateAssetTxFee + return nil +} + +func (c *staticCalculator) OperationTx(*txs.OperationTx) error { + c.fee = c.staticCfg.TxFee + return nil +} + +func (c *staticCalculator) ImportTx(*txs.ImportTx) error { + c.fee = c.staticCfg.TxFee + return nil +} + +func (c *staticCalculator) ExportTx(*txs.ExportTx) error { + c.fee = c.staticCfg.TxFee + return nil +} From c2d6e869d8d806c7a44a9a82506eb5187f79f79b Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Fri, 12 Jul 2024 11:36:54 +0200 Subject: [PATCH 24/27] repackaged avm static fee config --- node/node.go | 9 ++++++--- vms/avm/block/executor/block_test.go | 9 ++++++--- vms/avm/config/config.go | 12 ++++++------ vms/avm/environment_test.go | 9 ++++++--- vms/avm/txs/executor/semantic_verifier.go | 2 +- vms/avm/txs/executor/syntactic_verifier_test.go | 9 ++++++--- vms/avm/txs/fees/static_calculator.go | 9 +++------ vms/avm/txs/fees/static_config.go | 12 ++++++++++++ 8 files changed, 46 insertions(+), 25 deletions(-) create mode 100644 vms/avm/txs/fees/static_config.go diff --git a/node/node.go b/node/node.go index fe574b17ea5..9562bd8f98b 100644 --- a/node/node.go +++ b/node/node.go @@ -75,6 +75,7 @@ import ( "github.com/ava-labs/avalanchego/version" "github.com/ava-labs/avalanchego/vms" "github.com/ava-labs/avalanchego/vms/avm" + "github.com/ava-labs/avalanchego/vms/avm/txs/fees" "github.com/ava-labs/avalanchego/vms/platformvm" "github.com/ava-labs/avalanchego/vms/platformvm/signer" "github.com/ava-labs/avalanchego/vms/platformvm/upgrade" @@ -1249,9 +1250,11 @@ func (n *Node) initVMs() error { }), n.VMManager.RegisterFactory(context.TODO(), constants.AVMID, &avm.Factory{ Config: avmconfig.Config{ - TxFee: n.Config.TxFee, - CreateAssetTxFee: n.Config.CreateAssetTxFee, - EUpgradeTime: eUpgradeTime, + StaticConfig: fees.StaticConfig{ + TxFee: n.Config.TxFee, + CreateAssetTxFee: n.Config.CreateAssetTxFee, + }, + EUpgradeTime: eUpgradeTime, }, }), n.VMManager.RegisterFactory(context.TODO(), constants.EVMID, &coreth.Factory{}), diff --git a/vms/avm/block/executor/block_test.go b/vms/avm/block/executor/block_test.go index 8e72f4c21eb..23b5c761204 100644 --- a/vms/avm/block/executor/block_test.go +++ b/vms/avm/block/executor/block_test.go @@ -27,6 +27,7 @@ import ( "github.com/ava-labs/avalanchego/vms/avm/state" "github.com/ava-labs/avalanchego/vms/avm/txs" "github.com/ava-labs/avalanchego/vms/avm/txs/executor" + "github.com/ava-labs/avalanchego/vms/avm/txs/fees" "github.com/ava-labs/avalanchego/vms/avm/txs/mempool" ) @@ -1046,9 +1047,11 @@ func defaultTestBackend(bootstrapped bool, sharedMemory atomic.SharedMemory) *ex Log: logging.NoLog{}, }, Config: &config.Config{ - EUpgradeTime: mockable.MaxTime, - TxFee: 0, - CreateAssetTxFee: 0, + StaticConfig: fees.StaticConfig{ + TxFee: 0, + CreateAssetTxFee: 0, + }, + EUpgradeTime: mockable.MaxTime, }, } } diff --git a/vms/avm/config/config.go b/vms/avm/config/config.go index 0d026eb05db..357cbfaf560 100644 --- a/vms/avm/config/config.go +++ b/vms/avm/config/config.go @@ -3,15 +3,15 @@ package config -import "time" +import ( + "time" + + "github.com/ava-labs/avalanchego/vms/avm/txs/fees" +) // Struct collecting all the foundational parameters of the AVM type Config struct { - // Fee that is burned by every non-asset creating transaction - TxFee uint64 - - // Fee that must be burned by every asset creating transaction - CreateAssetTxFee uint64 + fees.StaticConfig // Time of the E network upgrade EUpgradeTime time.Time diff --git a/vms/avm/environment_test.go b/vms/avm/environment_test.go index d4375aa092d..18457b4216e 100644 --- a/vms/avm/environment_test.go +++ b/vms/avm/environment_test.go @@ -31,6 +31,7 @@ import ( "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/avm/txs/fees" "github.com/ava-labs/avalanchego/vms/avm/txs/txstest" "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/nftfx" @@ -230,9 +231,11 @@ func setup(tb testing.TB, c *envConfig) *environment { func staticConfig(tb testing.TB, f fork) config.Config { c := config.Config{ - TxFee: testTxFee, - CreateAssetTxFee: testTxFee, - EUpgradeTime: mockable.MaxTime, + StaticConfig: fees.StaticConfig{ + TxFee: testTxFee, + CreateAssetTxFee: testTxFee, + }, + EUpgradeTime: mockable.MaxTime, } switch f { diff --git a/vms/avm/txs/executor/semantic_verifier.go b/vms/avm/txs/executor/semantic_verifier.go index b5451e35b19..eebcd001237 100644 --- a/vms/avm/txs/executor/semantic_verifier.go +++ b/vms/avm/txs/executor/semantic_verifier.go @@ -131,7 +131,7 @@ func (v *SemanticVerifier) verifyBaseTx( importedIns []*avax.TransferableInput, exportedOuts []*avax.TransferableOutput, ) error { - feeCalculator := fees.NewStaticCalculator(v.Backend.Config) + feeCalculator := fees.NewStaticCalculator(v.Backend.Config.StaticConfig) fee, err := feeCalculator.CalculateFee(&txs.Tx{Unsigned: tx}) if err != nil { return err diff --git a/vms/avm/txs/executor/syntactic_verifier_test.go b/vms/avm/txs/executor/syntactic_verifier_test.go index ff566c69c03..74f182ad1f5 100644 --- a/vms/avm/txs/executor/syntactic_verifier_test.go +++ b/vms/avm/txs/executor/syntactic_verifier_test.go @@ -17,6 +17,7 @@ import ( "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/avm/txs/fees" "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/components/verify" "github.com/ava-labs/avalanchego/vms/secp256k1fx" @@ -25,9 +26,11 @@ import ( var ( keys = secp256k1.TestKeys() feeConfig = config.Config{ - TxFee: 2, - CreateAssetTxFee: 3, - EUpgradeTime: mockable.MaxTime, + StaticConfig: fees.StaticConfig{ + TxFee: 2, + CreateAssetTxFee: 3, + }, + EUpgradeTime: mockable.MaxTime, } ) diff --git a/vms/avm/txs/fees/static_calculator.go b/vms/avm/txs/fees/static_calculator.go index fe707131838..2f1b8d4828b 100644 --- a/vms/avm/txs/fees/static_calculator.go +++ b/vms/avm/txs/fees/static_calculator.go @@ -3,17 +3,14 @@ package fees -import ( - "github.com/ava-labs/avalanchego/vms/avm/config" - "github.com/ava-labs/avalanchego/vms/avm/txs" -) +import "github.com/ava-labs/avalanchego/vms/avm/txs" var ( _ Calculator = (*staticCalculator)(nil) _ txs.Visitor = (*staticCalculator)(nil) ) -func NewStaticCalculator(c *config.Config) Calculator { +func NewStaticCalculator(c StaticConfig) Calculator { return &staticCalculator{staticCfg: c} } @@ -25,7 +22,7 @@ func (c *staticCalculator) CalculateFee(tx *txs.Tx) (uint64, error) { type staticCalculator struct { // inputs - staticCfg *config.Config + staticCfg StaticConfig // outputs of visitor execution fee uint64 diff --git a/vms/avm/txs/fees/static_config.go b/vms/avm/txs/fees/static_config.go new file mode 100644 index 00000000000..f5b8da04335 --- /dev/null +++ b/vms/avm/txs/fees/static_config.go @@ -0,0 +1,12 @@ +// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package fees + +type StaticConfig struct { + // Fee that is burned by every non-asset creating transaction + TxFee uint64 + + // Fee that must be burned by every asset creating transaction + CreateAssetTxFee uint64 +} From 018988ebcd8447764fdd49db0152d63743551f23 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Fri, 12 Jul 2024 11:46:03 +0200 Subject: [PATCH 25/27] renamed fees package to fee --- node/node.go | 4 ++-- vms/avm/block/executor/block_test.go | 4 ++-- vms/avm/config/config.go | 4 ++-- vms/avm/environment_test.go | 4 ++-- vms/avm/txs/executor/semantic_verifier.go | 4 ++-- vms/avm/txs/executor/syntactic_verifier_test.go | 4 ++-- vms/avm/txs/{fees => fee}/calculator.go | 2 +- vms/avm/txs/{fees => fee}/static_calculator.go | 2 +- vms/avm/txs/{fees => fee}/static_config.go | 2 +- 9 files changed, 15 insertions(+), 15 deletions(-) rename vms/avm/txs/{fees => fee}/calculator.go (95%) rename vms/avm/txs/{fees => fee}/static_calculator.go (98%) rename vms/avm/txs/{fees => fee}/static_config.go (95%) diff --git a/node/node.go b/node/node.go index 9562bd8f98b..b4d513dba19 100644 --- a/node/node.go +++ b/node/node.go @@ -75,7 +75,7 @@ import ( "github.com/ava-labs/avalanchego/version" "github.com/ava-labs/avalanchego/vms" "github.com/ava-labs/avalanchego/vms/avm" - "github.com/ava-labs/avalanchego/vms/avm/txs/fees" + "github.com/ava-labs/avalanchego/vms/avm/txs/fee" "github.com/ava-labs/avalanchego/vms/platformvm" "github.com/ava-labs/avalanchego/vms/platformvm/signer" "github.com/ava-labs/avalanchego/vms/platformvm/upgrade" @@ -1250,7 +1250,7 @@ func (n *Node) initVMs() error { }), n.VMManager.RegisterFactory(context.TODO(), constants.AVMID, &avm.Factory{ Config: avmconfig.Config{ - StaticConfig: fees.StaticConfig{ + StaticConfig: fee.StaticConfig{ TxFee: n.Config.TxFee, CreateAssetTxFee: n.Config.CreateAssetTxFee, }, diff --git a/vms/avm/block/executor/block_test.go b/vms/avm/block/executor/block_test.go index 23b5c761204..f835123e60e 100644 --- a/vms/avm/block/executor/block_test.go +++ b/vms/avm/block/executor/block_test.go @@ -27,7 +27,7 @@ import ( "github.com/ava-labs/avalanchego/vms/avm/state" "github.com/ava-labs/avalanchego/vms/avm/txs" "github.com/ava-labs/avalanchego/vms/avm/txs/executor" - "github.com/ava-labs/avalanchego/vms/avm/txs/fees" + "github.com/ava-labs/avalanchego/vms/avm/txs/fee" "github.com/ava-labs/avalanchego/vms/avm/txs/mempool" ) @@ -1047,7 +1047,7 @@ func defaultTestBackend(bootstrapped bool, sharedMemory atomic.SharedMemory) *ex Log: logging.NoLog{}, }, Config: &config.Config{ - StaticConfig: fees.StaticConfig{ + StaticConfig: fee.StaticConfig{ TxFee: 0, CreateAssetTxFee: 0, }, diff --git a/vms/avm/config/config.go b/vms/avm/config/config.go index 357cbfaf560..cb8267204c8 100644 --- a/vms/avm/config/config.go +++ b/vms/avm/config/config.go @@ -6,12 +6,12 @@ package config import ( "time" - "github.com/ava-labs/avalanchego/vms/avm/txs/fees" + "github.com/ava-labs/avalanchego/vms/avm/txs/fee" ) // Struct collecting all the foundational parameters of the AVM type Config struct { - fees.StaticConfig + fee.StaticConfig // Time of the E network upgrade EUpgradeTime time.Time diff --git a/vms/avm/environment_test.go b/vms/avm/environment_test.go index 18457b4216e..05f6967423c 100644 --- a/vms/avm/environment_test.go +++ b/vms/avm/environment_test.go @@ -31,7 +31,7 @@ import ( "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/avm/txs/fees" + "github.com/ava-labs/avalanchego/vms/avm/txs/fee" "github.com/ava-labs/avalanchego/vms/avm/txs/txstest" "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/nftfx" @@ -231,7 +231,7 @@ func setup(tb testing.TB, c *envConfig) *environment { func staticConfig(tb testing.TB, f fork) config.Config { c := config.Config{ - StaticConfig: fees.StaticConfig{ + StaticConfig: fee.StaticConfig{ TxFee: testTxFee, CreateAssetTxFee: testTxFee, }, diff --git a/vms/avm/txs/executor/semantic_verifier.go b/vms/avm/txs/executor/semantic_verifier.go index eebcd001237..68a1b9ab4ab 100644 --- a/vms/avm/txs/executor/semantic_verifier.go +++ b/vms/avm/txs/executor/semantic_verifier.go @@ -11,7 +11,7 @@ import ( "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/vms/avm/state" "github.com/ava-labs/avalanchego/vms/avm/txs" - "github.com/ava-labs/avalanchego/vms/avm/txs/fees" + "github.com/ava-labs/avalanchego/vms/avm/txs/fee" "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/components/verify" ) @@ -131,7 +131,7 @@ func (v *SemanticVerifier) verifyBaseTx( importedIns []*avax.TransferableInput, exportedOuts []*avax.TransferableOutput, ) error { - feeCalculator := fees.NewStaticCalculator(v.Backend.Config.StaticConfig) + feeCalculator := fee.NewStaticCalculator(v.Backend.Config.StaticConfig) fee, err := feeCalculator.CalculateFee(&txs.Tx{Unsigned: tx}) if err != nil { return err diff --git a/vms/avm/txs/executor/syntactic_verifier_test.go b/vms/avm/txs/executor/syntactic_verifier_test.go index 74f182ad1f5..b473b4515e9 100644 --- a/vms/avm/txs/executor/syntactic_verifier_test.go +++ b/vms/avm/txs/executor/syntactic_verifier_test.go @@ -17,7 +17,7 @@ import ( "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/avm/txs/fees" + "github.com/ava-labs/avalanchego/vms/avm/txs/fee" "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/components/verify" "github.com/ava-labs/avalanchego/vms/secp256k1fx" @@ -26,7 +26,7 @@ import ( var ( keys = secp256k1.TestKeys() feeConfig = config.Config{ - StaticConfig: fees.StaticConfig{ + StaticConfig: fee.StaticConfig{ TxFee: 2, CreateAssetTxFee: 3, }, diff --git a/vms/avm/txs/fees/calculator.go b/vms/avm/txs/fee/calculator.go similarity index 95% rename from vms/avm/txs/fees/calculator.go rename to vms/avm/txs/fee/calculator.go index 334f0d492d2..5acc94b05f6 100644 --- a/vms/avm/txs/fees/calculator.go +++ b/vms/avm/txs/fee/calculator.go @@ -1,7 +1,7 @@ // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. // See the file LICENSE for licensing terms. -package fees +package fee import "github.com/ava-labs/avalanchego/vms/avm/txs" diff --git a/vms/avm/txs/fees/static_calculator.go b/vms/avm/txs/fee/static_calculator.go similarity index 98% rename from vms/avm/txs/fees/static_calculator.go rename to vms/avm/txs/fee/static_calculator.go index 2f1b8d4828b..fe46a0caaf8 100644 --- a/vms/avm/txs/fees/static_calculator.go +++ b/vms/avm/txs/fee/static_calculator.go @@ -1,7 +1,7 @@ // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. // See the file LICENSE for licensing terms. -package fees +package fee import "github.com/ava-labs/avalanchego/vms/avm/txs" diff --git a/vms/avm/txs/fees/static_config.go b/vms/avm/txs/fee/static_config.go similarity index 95% rename from vms/avm/txs/fees/static_config.go rename to vms/avm/txs/fee/static_config.go index f5b8da04335..a25fea8e95b 100644 --- a/vms/avm/txs/fees/static_config.go +++ b/vms/avm/txs/fee/static_config.go @@ -1,7 +1,7 @@ // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. // See the file LICENSE for licensing terms. -package fees +package fee type StaticConfig struct { // Fee that is burned by every non-asset creating transaction From d890cbc7b65a85ff2538d552d33021256b216677 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Fri, 12 Jul 2024 12:15:40 +0200 Subject: [PATCH 26/27] added tx fees uts --- vms/avm/txs/fee/calculator_test.go | 93 ++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 vms/avm/txs/fee/calculator_test.go diff --git a/vms/avm/txs/fee/calculator_test.go b/vms/avm/txs/fee/calculator_test.go new file mode 100644 index 00000000000..59e4a291c19 --- /dev/null +++ b/vms/avm/txs/fee/calculator_test.go @@ -0,0 +1,93 @@ +// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package fee + +import ( + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/ava-labs/avalanchego/utils/units" + "github.com/ava-labs/avalanchego/vms/avm/txs" +) + +func TestTxFees(t *testing.T) { + feeTestsDefaultCfg := StaticConfig{ + TxFee: 1 * units.Avax, + CreateAssetTxFee: 2 * units.Avax, + } + + // chain times needed to have specific upgrades active + eUpgradeTime := time.Unix(1713945427, 0) + preEUpgradeTime := eUpgradeTime.Add(-1 * time.Second) + + tests := []struct { + name string + chainTime time.Time + unsignedTx func() txs.UnsignedTx + expected uint64 + }{ + { + name: "BaseTx pre EUpgrade", + chainTime: preEUpgradeTime, + unsignedTx: baseTx, + expected: feeTestsDefaultCfg.TxFee, + }, + { + name: "CreateAssetTx pre EUpgrade", + chainTime: preEUpgradeTime, + unsignedTx: createAssetTx, + expected: feeTestsDefaultCfg.CreateAssetTxFee, + }, + { + name: "OperationTx pre EUpgrade", + chainTime: preEUpgradeTime, + unsignedTx: operationTx, + expected: feeTestsDefaultCfg.TxFee, + }, + { + name: "ImportTx pre EUpgrade", + chainTime: preEUpgradeTime, + unsignedTx: importTx, + expected: feeTestsDefaultCfg.TxFee, + }, + { + name: "ExportTx pre EUpgrade", + chainTime: preEUpgradeTime, + unsignedTx: exportTx, + expected: feeTestsDefaultCfg.TxFee, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + uTx := tt.unsignedTx() + fc := NewStaticCalculator(feeTestsDefaultCfg) + haveFee, err := fc.CalculateFee(&txs.Tx{Unsigned: uTx}) + require.NoError(t, err) + require.Equal(t, tt.expected, haveFee) + }) + } +} + +func baseTx() txs.UnsignedTx { + return &txs.BaseTx{} +} + +func createAssetTx() txs.UnsignedTx { + return &txs.CreateAssetTx{} +} + +func operationTx() txs.UnsignedTx { + return &txs.OperationTx{} +} + +func importTx() txs.UnsignedTx { + return &txs.ImportTx{} +} + +func exportTx() txs.UnsignedTx { + return &txs.ExportTx{} +} From 7f79fd15275945d3bc6039c82398022bca203849 Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Fri, 12 Jul 2024 16:01:25 +0200 Subject: [PATCH 27/27] reverted fee checks to synctactic verifier --- vms/avm/txs/executor/semantic_verifier.go | 78 +- .../txs/executor/semantic_verifier_test.go | 2022 +++-------------- vms/avm/txs/executor/syntactic_verifier.go | 36 +- .../txs/executor/syntactic_verifier_test.go | 1125 ++++++++- 4 files changed, 1466 insertions(+), 1795 deletions(-) diff --git a/vms/avm/txs/executor/semantic_verifier.go b/vms/avm/txs/executor/semantic_verifier.go index 68a1b9ab4ab..946346bc064 100644 --- a/vms/avm/txs/executor/semantic_verifier.go +++ b/vms/avm/txs/executor/semantic_verifier.go @@ -11,7 +11,6 @@ import ( "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/vms/avm/state" "github.com/ava-labs/avalanchego/vms/avm/txs" - "github.com/ava-labs/avalanchego/vms/avm/txs/fee" "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/components/verify" ) @@ -32,15 +31,36 @@ type SemanticVerifier struct { } func (v *SemanticVerifier) BaseTx(tx *txs.BaseTx) error { - return v.verifyBaseTx(tx, nil, nil) + for i, in := range tx.Ins { + // Note: Verification of the length of [t.tx.Creds] happens during + // syntactic verification, which happens before semantic verification. + cred := v.Tx.Creds[i].Credential + if err := v.verifyTransfer(tx, in, cred); err != nil { + return err + } + } + + for _, out := range tx.Outs { + fxIndex, err := v.getFx(out.Out) + if err != nil { + return err + } + + assetID := out.AssetID() + if err := v.verifyFxUsage(fxIndex, assetID); err != nil { + return err + } + } + + return nil } func (v *SemanticVerifier) CreateAssetTx(tx *txs.CreateAssetTx) error { - return v.verifyBaseTx(&tx.BaseTx, nil, nil) + return v.BaseTx(&tx.BaseTx) } func (v *SemanticVerifier) OperationTx(tx *txs.OperationTx) error { - if err := v.verifyBaseTx(&tx.BaseTx, nil, nil); err != nil { + if err := v.BaseTx(&tx.BaseTx); err != nil { return err } @@ -61,7 +81,7 @@ func (v *SemanticVerifier) OperationTx(tx *txs.OperationTx) error { } func (v *SemanticVerifier) ImportTx(tx *txs.ImportTx) error { - if err := v.verifyBaseTx(&tx.BaseTx, tx.ImportedIns, nil); err != nil { + if err := v.BaseTx(&tx.BaseTx); err != nil { return err } @@ -102,7 +122,7 @@ func (v *SemanticVerifier) ImportTx(tx *txs.ImportTx) error { } func (v *SemanticVerifier) ExportTx(tx *txs.ExportTx) error { - if err := v.verifyBaseTx(&tx.BaseTx, nil, tx.ExportedOuts); err != nil { + if err := v.BaseTx(&tx.BaseTx); err != nil { return err } @@ -126,52 +146,6 @@ func (v *SemanticVerifier) ExportTx(tx *txs.ExportTx) error { return nil } -func (v *SemanticVerifier) verifyBaseTx( - tx *txs.BaseTx, - importedIns []*avax.TransferableInput, - exportedOuts []*avax.TransferableOutput, -) error { - feeCalculator := fee.NewStaticCalculator(v.Backend.Config.StaticConfig) - fee, err := feeCalculator.CalculateFee(&txs.Tx{Unsigned: tx}) - if err != nil { - return err - } - - err = avax.VerifyTx( - fee, - v.FeeAssetID, - [][]*avax.TransferableInput{tx.Ins, importedIns}, - [][]*avax.TransferableOutput{tx.Outs, exportedOuts}, - v.Codec, - ) - if err != nil { - return err - } - - for i, in := range tx.Ins { - // Note: Verification of the length of [t.tx.Creds] happens during - // syntactic verification, which happens before semantic verification. - cred := v.Tx.Creds[i].Credential - if err := v.verifyTransfer(tx, in, cred); err != nil { - return err - } - } - - for _, out := range tx.Outs { - fxIndex, err := v.getFx(out.Out) - if err != nil { - return err - } - - assetID := out.AssetID() - if err := v.verifyFxUsage(fxIndex, assetID); err != nil { - return err - } - } - - return nil -} - func (v *SemanticVerifier) verifyTransfer( tx txs.UnsignedTx, in *avax.TransferableInput, diff --git a/vms/avm/txs/executor/semantic_verifier_test.go b/vms/avm/txs/executor/semantic_verifier_test.go index 7f67c771072..db89e1e5a5e 100644 --- a/vms/avm/txs/executor/semantic_verifier_test.go +++ b/vms/avm/txs/executor/semantic_verifier_test.go @@ -4,7 +4,6 @@ package executor import ( - "math" "reflect" "testing" @@ -22,95 +21,60 @@ import ( "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/utils/units" "github.com/ava-labs/avalanchego/vms/avm/fxs" "github.com/ava-labs/avalanchego/vms/avm/state" "github.com/ava-labs/avalanchego/vms/avm/txs" "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/components/verify" - "github.com/ava-labs/avalanchego/vms/nftfx" - "github.com/ava-labs/avalanchego/vms/propertyfx" "github.com/ava-labs/avalanchego/vms/secp256k1fx" - - safemath "github.com/ava-labs/avalanchego/utils/math" ) func TestSemanticVerifierBaseTx(t *testing.T) { ctx := snowtest.Context(t, snowtest.XChainID) - // UTXO to be spent - inputTxID := ids.GenerateTestID() + typeToFxIndex := make(map[reflect.Type]int) + secpFx := &secp256k1fx.Fx{} + parser, err := txs.NewCustomParser( + typeToFxIndex, + new(mockable.Clock), + logging.NoWarn{}, + []fxs.Fx{ + secpFx, + }, + ) + require.NoError(t, err) + + codec := parser.Codec() + txID := ids.GenerateTestID() utxoID := avax.UTXOID{ - TxID: inputTxID, - OutputIndex: 0, + TxID: txID, + OutputIndex: 2, } - - feeAssetID := ids.GenerateTestID() asset := avax.Asset{ - ID: feeAssetID, - } - outputOwners := secp256k1fx.OutputOwners{ - Threshold: 1, - Addrs: []ids.ShortID{keys[0].PublicKey().Address()}, - } - utxoAmount := 100 + feeConfig.TxFee + 50 - utxoOut := secp256k1fx.TransferOutput{ - Amt: utxoAmount, - OutputOwners: outputOwners, - } - utxo := avax.UTXO{ - UTXOID: utxoID, - Asset: asset, - Out: &utxoOut, + ID: ids.GenerateTestID(), } - - // Input spending the UTXO - inputSigners := secp256k1fx.Input{ - SigIndices: []uint32{0}, + inputSigner := secp256k1fx.Input{ + SigIndices: []uint32{ + 0, + }, } fxInput := secp256k1fx.TransferInput{ - Amt: utxoAmount, - Input: inputSigners, + Amt: 12345, + Input: inputSigner, } input := avax.TransferableInput{ UTXOID: utxoID, Asset: asset, In: &fxInput, } - - // Output produced by BaseTx - fxOutput := secp256k1fx.TransferOutput{ - Amt: 100, - OutputOwners: outputOwners, - } - output := avax.TransferableOutput{ - Asset: asset, - Out: &fxOutput, - } - - // BaseTx - baseTx := avax.BaseTx{ - Outs: []*avax.TransferableOutput{ - &output, - }, - Ins: []*avax.TransferableInput{ - &input, + baseTx := txs.BaseTx{ + BaseTx: avax.BaseTx{ + Ins: []*avax.TransferableInput{ + &input, + }, }, } - // Backend - typeToFxIndex := make(map[reflect.Type]int) - secpFx := &secp256k1fx.Fx{} - parser, err := txs.NewCustomParser( - typeToFxIndex, - new(mockable.Clock), - logging.NoWarn{}, - []fxs.Fx{ - secpFx, - }, - ) - require.NoError(t, err) - codec := parser.Codec() backend := &Backend{ Ctx: ctx, Config: &feeConfig, @@ -122,11 +86,26 @@ func TestSemanticVerifierBaseTx(t *testing.T) { }, TypeToFxIndex: typeToFxIndex, Codec: codec, - FeeAssetID: feeAssetID, + FeeAssetID: ids.GenerateTestID(), Bootstrapped: true, } require.NoError(t, secpFx.Bootstrapped()) + outputOwners := secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{ + keys[0].Address(), + }, + } + output := secp256k1fx.TransferOutput{ + Amt: 12345, + OutputOwners: outputOwners, + } + utxo := avax.UTXO{ + UTXOID: utxoID, + Asset: asset, + Out: &output, + } unsignedCreateAssetTx := txs.CreateAssetTx{ States: []*txs.InitialState{{ FxIndex: 0, @@ -148,15 +127,13 @@ func TestSemanticVerifierBaseTx(t *testing.T) { state := state.NewMockChain(ctrl) state.EXPECT().GetUTXO(utxoID.InputID()).Return(&utxo, nil) - state.EXPECT().GetTx(asset.ID).Return(&createAssetTx, nil).Times(2) + state.EXPECT().GetTx(asset.ID).Return(&createAssetTx, nil) return state }, txFunc: func(require *require.Assertions) *txs.Tx { tx := &txs.Tx{ - Unsigned: &txs.BaseTx{ - BaseTx: baseTx, - }, + Unsigned: &baseTx, } require.NoError(tx.SignSECP256K1Fx( codec, @@ -169,90 +146,21 @@ func TestSemanticVerifierBaseTx(t *testing.T) { err: nil, }, { - name: "invalid output", - stateFunc: func(*gomock.Controller) state.Chain { - return nil - }, - txFunc: func(require *require.Assertions) *txs.Tx { - output := output - output.Out = &secp256k1fx.TransferOutput{ - Amt: 0, - OutputOwners: outputOwners, - } - - baseTx := baseTx - baseTx.Outs = []*avax.TransferableOutput{ - &output, - } - - tx := &txs.Tx{Unsigned: &txs.BaseTx{BaseTx: baseTx}} - require.NoError(tx.SignSECP256K1Fx( - codec, - [][]*secp256k1.PrivateKey{ - {keys[0]}, - }, - )) - return tx - }, - err: secp256k1fx.ErrNoValueOutput, - }, - { - name: "unsorted outputs", - stateFunc: func(*gomock.Controller) state.Chain { - return nil - }, - txFunc: func(require *require.Assertions) *txs.Tx { - output0 := output - output0.Out = &secp256k1fx.TransferOutput{ - Amt: 1, - OutputOwners: outputOwners, - } - - output1 := output - output1.Out = &secp256k1fx.TransferOutput{ - Amt: 2, - OutputOwners: outputOwners, - } + name: "assetID mismatch", + stateFunc: func(ctrl *gomock.Controller) state.Chain { + state := state.NewMockChain(ctrl) - outputs := []*avax.TransferableOutput{ - &output0, - &output1, - } - avax.SortTransferableOutputs(outputs, codec) - outputs[0], outputs[1] = outputs[1], outputs[0] + utxo := utxo + utxo.Asset.ID = ids.GenerateTestID() - baseTx := baseTx - baseTx.Outs = outputs + state.EXPECT().GetUTXO(utxoID.InputID()).Return(&utxo, nil) - tx := &txs.Tx{Unsigned: &txs.BaseTx{BaseTx: baseTx}} - require.NoError(tx.SignSECP256K1Fx( - codec, - [][]*secp256k1.PrivateKey{ - {keys[0]}, - }, - )) - return tx - }, - err: avax.ErrOutputsNotSorted, - }, - { - name: "invalid input", - stateFunc: func(*gomock.Controller) state.Chain { - return nil + return state }, txFunc: func(require *require.Assertions) *txs.Tx { - input := input - input.In = &secp256k1fx.TransferInput{ - Amt: 0, - Input: inputSigners, - } - - baseTx := baseTx - baseTx.Ins = []*avax.TransferableInput{ - &input, + tx := &txs.Tx{ + Unsigned: &baseTx, } - - tx := &txs.Tx{Unsigned: &txs.BaseTx{BaseTx: baseTx}} require.NoError(tx.SignSECP256K1Fx( codec, [][]*secp256k1.PrivateKey{ @@ -261,97 +169,29 @@ func TestSemanticVerifierBaseTx(t *testing.T) { )) return tx }, - err: secp256k1fx.ErrNoValueInput, + err: errAssetIDMismatch, }, { - name: "duplicate inputs", - stateFunc: func(*gomock.Controller) state.Chain { - return nil - }, - txFunc: func(require *require.Assertions) *txs.Tx { - baseTx := baseTx - baseTx.Ins = []*avax.TransferableInput{ - &input, - &input, - } + name: "not allowed input feature extension", + stateFunc: func(ctrl *gomock.Controller) state.Chain { + state := state.NewMockChain(ctrl) - tx := &txs.Tx{Unsigned: &txs.BaseTx{BaseTx: baseTx}} - require.NoError(tx.SignSECP256K1Fx( - codec, - [][]*secp256k1.PrivateKey{ - {keys[0]}, - {keys[0]}, - }, - )) - return tx - }, - err: avax.ErrInputsNotSortedUnique, - }, - { - name: "input overflow", - stateFunc: func(*gomock.Controller) state.Chain { - return nil - }, - txFunc: func(require *require.Assertions) *txs.Tx { - input0 := input - input0.In = &secp256k1fx.TransferInput{ - Amt: 1, - Input: inputSigners, - } + unsignedCreateAssetTx := unsignedCreateAssetTx + unsignedCreateAssetTx.States = nil - input1 := input - input1.UTXOID.OutputIndex++ - input1.In = &secp256k1fx.TransferInput{ - Amt: math.MaxUint64, - Input: inputSigners, + createAssetTx := txs.Tx{ + Unsigned: &unsignedCreateAssetTx, } - baseTx := baseTx - baseTx.Ins = []*avax.TransferableInput{ - &input0, - &input1, - } - avax.SortTransferableInputsWithSigners(baseTx.Ins, make([][]*secp256k1.PrivateKey, 2)) + state.EXPECT().GetUTXO(utxoID.InputID()).Return(&utxo, nil) + state.EXPECT().GetTx(asset.ID).Return(&createAssetTx, nil) - tx := &txs.Tx{Unsigned: &txs.BaseTx{BaseTx: baseTx}} - require.NoError(tx.SignSECP256K1Fx( - codec, - [][]*secp256k1.PrivateKey{ - {keys[0]}, - }, - )) - return tx - }, - err: safemath.ErrOverflow, - }, - { - name: "output overflow", - stateFunc: func(*gomock.Controller) state.Chain { - return nil + return state }, txFunc: func(require *require.Assertions) *txs.Tx { - output0 := output - output0.Out = &secp256k1fx.TransferOutput{ - Amt: 1, - OutputOwners: outputOwners, - } - - output1 := output - output1.Out = &secp256k1fx.TransferOutput{ - Amt: math.MaxUint64, - OutputOwners: outputOwners, - } - - outputs := []*avax.TransferableOutput{ - &output0, - &output1, + tx := &txs.Tx{ + Unsigned: &baseTx, } - avax.SortTransferableOutputs(outputs, codec) - - baseTx := baseTx - baseTx.Outs = outputs - - tx := &txs.Tx{Unsigned: &txs.BaseTx{BaseTx: baseTx}} require.NoError(tx.SignSECP256K1Fx( codec, [][]*secp256k1.PrivateKey{ @@ -360,98 +200,45 @@ func TestSemanticVerifierBaseTx(t *testing.T) { )) return tx }, - err: safemath.ErrOverflow, + err: errIncompatibleFx, }, { - name: "barely sufficient funds", + name: "invalid signature", stateFunc: func(ctrl *gomock.Controller) state.Chain { state := state.NewMockChain(ctrl) - utxoAmount := 100 + feeConfig.TxFee - utxoOut := secp256k1fx.TransferOutput{ - Amt: utxoAmount, - OutputOwners: outputOwners, - } - utxo := avax.UTXO{ - UTXOID: utxoID, - Asset: asset, - Out: &utxoOut, - } - state.EXPECT().GetUTXO(utxoID.InputID()).Return(&utxo, nil) - state.EXPECT().GetTx(asset.ID).Return(&createAssetTx, nil).Times(2) + state.EXPECT().GetTx(asset.ID).Return(&createAssetTx, nil) return state }, txFunc: func(require *require.Assertions) *txs.Tx { - input := input - input.In = &secp256k1fx.TransferInput{ - Amt: fxOutput.Amt + feeConfig.TxFee, - Input: inputSigners, - } - - baseTx := baseTx - baseTx.Ins = []*avax.TransferableInput{ - &input, + tx := &txs.Tx{ + Unsigned: &baseTx, } - - tx := &txs.Tx{Unsigned: &txs.BaseTx{BaseTx: baseTx}} require.NoError(tx.SignSECP256K1Fx( codec, [][]*secp256k1.PrivateKey{ - {keys[0]}, + {keys[1]}, }, )) return tx }, - err: nil, + err: secp256k1fx.ErrWrongSig, }, { - name: "insufficient funds", - stateFunc: func(*gomock.Controller) state.Chain { - return nil - }, - txFunc: func(require *require.Assertions) *txs.Tx { - input := input - input.In = &secp256k1fx.TransferInput{ - Amt: 1, - Input: inputSigners, - } + name: "missing UTXO", + stateFunc: func(ctrl *gomock.Controller) state.Chain { + state := state.NewMockChain(ctrl) - baseTx := baseTx - baseTx.Ins = []*avax.TransferableInput{ - &input, - } + state.EXPECT().GetUTXO(utxoID.InputID()).Return(nil, database.ErrNotFound) - tx := &txs.Tx{Unsigned: &txs.BaseTx{BaseTx: baseTx}} - require.NoError(tx.SignSECP256K1Fx( - codec, - [][]*secp256k1.PrivateKey{ - {keys[0]}, - }, - )) - return tx - }, - err: avax.ErrInsufficientFunds, - }, - { - name: "barely insufficient funds", - stateFunc: func(*gomock.Controller) state.Chain { - return nil + return state }, txFunc: func(require *require.Assertions) *txs.Tx { - input := input - input.In = &secp256k1fx.TransferInput{ - Amt: fxOutput.Amt + feeConfig.TxFee - 1, - Input: inputSigners, - } - - baseTx := baseTx - baseTx.Ins = []*avax.TransferableInput{ - &input, + tx := &txs.Tx{ + Unsigned: &baseTx, } - - tx := &txs.Tx{Unsigned: &txs.BaseTx{BaseTx: baseTx}} require.NoError(tx.SignSECP256K1Fx( codec, [][]*secp256k1.PrivateKey{ @@ -460,25 +247,27 @@ func TestSemanticVerifierBaseTx(t *testing.T) { )) return tx }, - err: avax.ErrInsufficientFunds, + err: database.ErrNotFound, }, { - name: "assetID mismatch", + name: "invalid UTXO amount", stateFunc: func(ctrl *gomock.Controller) state.Chain { state := state.NewMockChain(ctrl) + output := output + output.Amt-- + utxo := utxo - utxo.Asset.ID = ids.GenerateTestID() + utxo.Out = &output state.EXPECT().GetUTXO(utxoID.InputID()).Return(&utxo, nil) + state.EXPECT().GetTx(asset.ID).Return(&createAssetTx, nil) return state }, txFunc: func(require *require.Assertions) *txs.Tx { tx := &txs.Tx{ - Unsigned: &txs.BaseTx{ - BaseTx: baseTx, - }, + Unsigned: &baseTx, } require.NoError(tx.SignSECP256K1Fx( codec, @@ -488,10 +277,10 @@ func TestSemanticVerifierBaseTx(t *testing.T) { )) return tx }, - err: errAssetIDMismatch, + err: secp256k1fx.ErrMismatchedAmounts, }, { - name: "not allowed input feature extension", + name: "not allowed output feature extension", stateFunc: func(ctrl *gomock.Controller) state.Chain { state := state.NewMockChain(ctrl) @@ -502,67 +291,71 @@ func TestSemanticVerifierBaseTx(t *testing.T) { Unsigned: &unsignedCreateAssetTx, } - state.EXPECT().GetUTXO(utxoID.InputID()).Return(&utxo, nil) state.EXPECT().GetTx(asset.ID).Return(&createAssetTx, nil) return state }, txFunc: func(require *require.Assertions) *txs.Tx { - tx := &txs.Tx{ - Unsigned: &txs.BaseTx{ - BaseTx: baseTx, + baseTx := baseTx + baseTx.Ins = nil + baseTx.Outs = []*avax.TransferableOutput{ + { + Asset: asset, + Out: &output, }, } + tx := &txs.Tx{ + Unsigned: &baseTx, + } require.NoError(tx.SignSECP256K1Fx( codec, - [][]*secp256k1.PrivateKey{ - {keys[0]}, - }, + [][]*secp256k1.PrivateKey{}, )) return tx }, err: errIncompatibleFx, }, { - name: "invalid signature", + name: "unknown asset", stateFunc: func(ctrl *gomock.Controller) state.Chain { state := state.NewMockChain(ctrl) state.EXPECT().GetUTXO(utxoID.InputID()).Return(&utxo, nil) - state.EXPECT().GetTx(asset.ID).Return(&createAssetTx, nil) + state.EXPECT().GetTx(asset.ID).Return(nil, database.ErrNotFound) return state }, txFunc: func(require *require.Assertions) *txs.Tx { tx := &txs.Tx{ - Unsigned: &txs.BaseTx{ - BaseTx: baseTx, - }, + Unsigned: &baseTx, } require.NoError(tx.SignSECP256K1Fx( codec, [][]*secp256k1.PrivateKey{ - {keys[1]}, + {keys[0]}, }, )) return tx }, - err: secp256k1fx.ErrWrongSig, + err: database.ErrNotFound, }, { - name: "missing UTXO", + name: "not an asset", stateFunc: func(ctrl *gomock.Controller) state.Chain { state := state.NewMockChain(ctrl) - state.EXPECT().GetUTXO(utxoID.InputID()).Return(nil, database.ErrNotFound) + tx := txs.Tx{ + Unsigned: &baseTx, + } + + state.EXPECT().GetUTXO(utxoID.InputID()).Return(&utxo, nil) + state.EXPECT().GetTx(asset.ID).Return(&tx, nil) return state }, txFunc: func(require *require.Assertions) *txs.Tx { tx := &txs.Tx{ - Unsigned: &txs.BaseTx{ - BaseTx: baseTx, - }, + Unsigned: &baseTx, } require.NoError(tx.SignSECP256K1Fx( codec, @@ -572,130 +365,7 @@ func TestSemanticVerifierBaseTx(t *testing.T) { )) return tx }, - err: database.ErrNotFound, - }, - { - name: "invalid UTXO amount", - stateFunc: func(ctrl *gomock.Controller) state.Chain { - state := state.NewMockChain(ctrl) - - utxoOut := utxoOut - utxoOut.Amt-- - - utxo := utxo - utxo.Out = &utxoOut - - state.EXPECT().GetUTXO(utxoID.InputID()).Return(&utxo, nil) - state.EXPECT().GetTx(asset.ID).Return(&createAssetTx, nil) - - return state - }, - txFunc: func(require *require.Assertions) *txs.Tx { - tx := &txs.Tx{ - Unsigned: &txs.BaseTx{ - BaseTx: baseTx, - }, - } - require.NoError(tx.SignSECP256K1Fx( - codec, - [][]*secp256k1.PrivateKey{ - {keys[0]}, - }, - )) - return tx - }, - err: secp256k1fx.ErrMismatchedAmounts, - }, - { - name: "not allowed output feature extension", - stateFunc: func(ctrl *gomock.Controller) state.Chain { - state := state.NewMockChain(ctrl) - - unsignedCreateAssetTx := unsignedCreateAssetTx - unsignedCreateAssetTx.States = nil - - createAssetTx := txs.Tx{ - Unsigned: &unsignedCreateAssetTx, - } - - state.EXPECT().GetTx(asset.ID).Return(&createAssetTx, nil) - state.EXPECT().GetUTXO(utxoID.InputID()).Return(&utxo, nil) - - return state - }, - txFunc: func(require *require.Assertions) *txs.Tx { - tx := &txs.Tx{ - Unsigned: &txs.BaseTx{ - BaseTx: baseTx, - }, - } - require.NoError(tx.SignSECP256K1Fx( - codec, - [][]*secp256k1.PrivateKey{ - {keys[0]}, - }, - )) - return tx - }, - err: errIncompatibleFx, - }, - { - name: "unknown asset", - stateFunc: func(ctrl *gomock.Controller) state.Chain { - state := state.NewMockChain(ctrl) - - state.EXPECT().GetUTXO(utxoID.InputID()).Return(&utxo, nil) - state.EXPECT().GetTx(asset.ID).Return(nil, database.ErrNotFound) - - return state - }, - txFunc: func(require *require.Assertions) *txs.Tx { - tx := &txs.Tx{ - Unsigned: &txs.BaseTx{ - BaseTx: baseTx, - }, - } - require.NoError(tx.SignSECP256K1Fx( - codec, - [][]*secp256k1.PrivateKey{ - {keys[0]}, - }, - )) - return tx - }, - err: database.ErrNotFound, - }, - { - name: "not an asset", - stateFunc: func(ctrl *gomock.Controller) state.Chain { - state := state.NewMockChain(ctrl) - - tx := txs.Tx{ - Unsigned: &txs.BaseTx{ - BaseTx: baseTx, - }, - } - - state.EXPECT().GetUTXO(utxoID.InputID()).Return(&utxo, nil) - state.EXPECT().GetTx(asset.ID).Return(&tx, nil) - - return state - }, - txFunc: func(require *require.Assertions) *txs.Tx { - tx := &txs.Tx{ - Unsigned: &txs.BaseTx{ - BaseTx: baseTx, - }, - } - require.NoError(tx.SignSECP256K1Fx( - codec, - [][]*secp256k1.PrivateKey{ - {keys[0]}, - }, - )) - return tx - }, - err: errNotAnAsset, + err: errNotAnAsset, }, } for _, test := range tests { @@ -719,84 +389,53 @@ func TestSemanticVerifierBaseTx(t *testing.T) { func TestSemanticVerifierExportTx(t *testing.T) { ctx := snowtest.Context(t, snowtest.XChainID) - // UTXO to be spent - inputTxID := ids.GenerateTestID() + typeToFxIndex := make(map[reflect.Type]int) + secpFx := &secp256k1fx.Fx{} + parser, err := txs.NewCustomParser( + typeToFxIndex, + new(mockable.Clock), + logging.NoWarn{}, + []fxs.Fx{ + secpFx, + }, + ) + require.NoError(t, err) + + codec := parser.Codec() + txID := ids.GenerateTestID() utxoID := avax.UTXOID{ - TxID: inputTxID, - OutputIndex: 0, + TxID: txID, + OutputIndex: 2, } - - feeAssetID := ids.GenerateTestID() asset := avax.Asset{ - ID: feeAssetID, - } - outputOwners := secp256k1fx.OutputOwners{ - Threshold: 1, - Addrs: []ids.ShortID{keys[0].PublicKey().Address()}, - } - utxoAmount := 100 + feeConfig.TxFee + 50 - utxoOut := secp256k1fx.TransferOutput{ - Amt: utxoAmount, - OutputOwners: outputOwners, - } - utxo := avax.UTXO{ - UTXOID: utxoID, - Asset: asset, - Out: &utxoOut, + ID: ids.GenerateTestID(), } - - // Input spending the UTXO - inputSigners := secp256k1fx.Input{ - SigIndices: []uint32{0}, + inputSigner := secp256k1fx.Input{ + SigIndices: []uint32{ + 0, + }, } fxInput := secp256k1fx.TransferInput{ - Amt: utxoAmount, - Input: inputSigners, + Amt: 12345, + Input: inputSigner, } input := avax.TransferableInput{ UTXOID: utxoID, Asset: asset, In: &fxInput, } - - // Output produced by BaseTx - fxOutput := secp256k1fx.TransferOutput{ - Amt: 100, - OutputOwners: outputOwners, - } - output := avax.TransferableOutput{ - Asset: asset, - Out: &fxOutput, - } - - baseTx := avax.BaseTx{ - Outs: []*avax.TransferableOutput{ - &output, - }, - Ins: []*avax.TransferableInput{ - &input, + baseTx := txs.BaseTx{ + BaseTx: avax.BaseTx{ + Ins: []*avax.TransferableInput{ + &input, + }, }, } - exportTx := txs.ExportTx{ - BaseTx: txs.BaseTx{ - BaseTx: baseTx, - }, + BaseTx: baseTx, DestinationChain: ctx.CChainID, } - typeToFxIndex := make(map[reflect.Type]int) - secpFx := &secp256k1fx.Fx{} - parser, err := txs.NewCustomParser( - typeToFxIndex, - new(mockable.Clock), - logging.NoWarn{}, - []fxs.Fx{ - secpFx, - }, - ) - require.NoError(t, err) - codec := parser.Codec() backend := &Backend{ Ctx: ctx, Config: &feeConfig, @@ -808,11 +447,26 @@ func TestSemanticVerifierExportTx(t *testing.T) { }, TypeToFxIndex: typeToFxIndex, Codec: codec, - FeeAssetID: feeAssetID, + FeeAssetID: ids.GenerateTestID(), Bootstrapped: true, } require.NoError(t, secpFx.Bootstrapped()) + outputOwners := secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{ + keys[0].Address(), + }, + } + output := secp256k1fx.TransferOutput{ + Amt: 12345, + OutputOwners: outputOwners, + } + utxo := avax.UTXO{ + UTXOID: utxoID, + Asset: asset, + Out: &output, + } unsignedCreateAssetTx := txs.CreateAssetTx{ States: []*txs.InitialState{{ FxIndex: 0, @@ -834,7 +488,7 @@ func TestSemanticVerifierExportTx(t *testing.T) { state := state.NewMockChain(ctrl) state.EXPECT().GetUTXO(utxoID.InputID()).Return(&utxo, nil) - state.EXPECT().GetTx(asset.ID).Return(&createAssetTx, nil).Times(2) + state.EXPECT().GetTx(asset.ID).Return(&createAssetTx, nil) return state }, @@ -853,25 +507,21 @@ func TestSemanticVerifierExportTx(t *testing.T) { err: nil, }, { - name: "invalid output", - stateFunc: func(*gomock.Controller) state.Chain { - return nil + name: "assetID mismatch", + stateFunc: func(ctrl *gomock.Controller) state.Chain { + state := state.NewMockChain(ctrl) + + utxo := utxo + utxo.Asset.ID = ids.GenerateTestID() + + state.EXPECT().GetUTXO(utxoID.InputID()).Return(&utxo, nil) + + return state }, txFunc: func(require *require.Assertions) *txs.Tx { - output := output - output.Out = &secp256k1fx.TransferOutput{ - Amt: 0, - OutputOwners: outputOwners, - } - - baseTx := baseTx - baseTx.Outs = []*avax.TransferableOutput{ - &output, + tx := &txs.Tx{ + Unsigned: &exportTx, } - - eTx := exportTx - eTx.BaseTx.BaseTx = baseTx - tx := &txs.Tx{Unsigned: &eTx} require.NoError(tx.SignSECP256K1Fx( codec, [][]*secp256k1.PrivateKey{ @@ -880,39 +530,29 @@ func TestSemanticVerifierExportTx(t *testing.T) { )) return tx }, - err: secp256k1fx.ErrNoValueOutput, + err: errAssetIDMismatch, }, { - name: "unsorted outputs", - stateFunc: func(*gomock.Controller) state.Chain { - return nil - }, - txFunc: func(require *require.Assertions) *txs.Tx { - output0 := output - output0.Out = &secp256k1fx.TransferOutput{ - Amt: 1, - OutputOwners: outputOwners, - } + name: "not allowed input feature extension", + stateFunc: func(ctrl *gomock.Controller) state.Chain { + state := state.NewMockChain(ctrl) - output1 := output - output1.Out = &secp256k1fx.TransferOutput{ - Amt: 2, - OutputOwners: outputOwners, - } + unsignedCreateAssetTx := unsignedCreateAssetTx + unsignedCreateAssetTx.States = nil - outputs := []*avax.TransferableOutput{ - &output0, - &output1, + createAssetTx := txs.Tx{ + Unsigned: &unsignedCreateAssetTx, } - avax.SortTransferableOutputs(outputs, codec) - outputs[0], outputs[1] = outputs[1], outputs[0] - baseTx := baseTx - baseTx.Outs = outputs + state.EXPECT().GetUTXO(utxoID.InputID()).Return(&utxo, nil) + state.EXPECT().GetTx(asset.ID).Return(&createAssetTx, nil) - eTx := exportTx - eTx.BaseTx.BaseTx = baseTx - tx := &txs.Tx{Unsigned: &eTx} + return state + }, + txFunc: func(require *require.Assertions) *txs.Tx { + tx := &txs.Tx{ + Unsigned: &exportTx, + } require.NoError(tx.SignSECP256K1Fx( codec, [][]*secp256k1.PrivateKey{ @@ -921,66 +561,45 @@ func TestSemanticVerifierExportTx(t *testing.T) { )) return tx }, - err: avax.ErrOutputsNotSorted, + err: errIncompatibleFx, }, { - name: "unsorted exported outputs", - stateFunc: func(*gomock.Controller) state.Chain { - return nil - }, - txFunc: func(require *require.Assertions) *txs.Tx { - output0 := output - output0.Out = &secp256k1fx.TransferOutput{ - Amt: 1, - OutputOwners: outputOwners, - } + name: "invalid signature", + stateFunc: func(ctrl *gomock.Controller) state.Chain { + state := state.NewMockChain(ctrl) - output1 := output - output1.Out = &secp256k1fx.TransferOutput{ - Amt: 2, - OutputOwners: outputOwners, - } + state.EXPECT().GetUTXO(utxoID.InputID()).Return(&utxo, nil) + state.EXPECT().GetTx(asset.ID).Return(&createAssetTx, nil) - outputs := []*avax.TransferableOutput{ - &output0, - &output1, + return state + }, + txFunc: func(require *require.Assertions) *txs.Tx { + tx := &txs.Tx{ + Unsigned: &exportTx, } - avax.SortTransferableOutputs(outputs, codec) - outputs[0], outputs[1] = outputs[1], outputs[0] - - utx := exportTx - utx.ExportedOuts = outputs - tx := &txs.Tx{Unsigned: &utx} require.NoError(tx.SignSECP256K1Fx( codec, [][]*secp256k1.PrivateKey{ - {keys[0]}, + {keys[1]}, }, )) return tx }, - err: avax.ErrOutputsNotSorted, + err: secp256k1fx.ErrWrongSig, }, { - name: "invalid input", - stateFunc: func(*gomock.Controller) state.Chain { - return nil + name: "missing UTXO", + stateFunc: func(ctrl *gomock.Controller) state.Chain { + state := state.NewMockChain(ctrl) + + state.EXPECT().GetUTXO(utxoID.InputID()).Return(nil, database.ErrNotFound) + + return state }, txFunc: func(require *require.Assertions) *txs.Tx { - input := input - input.In = &secp256k1fx.TransferInput{ - Amt: 0, - Input: inputSigners, - } - - baseTx := baseTx - baseTx.Ins = []*avax.TransferableInput{ - &input, + tx := &txs.Tx{ + Unsigned: &exportTx, } - - eTx := exportTx - eTx.BaseTx.BaseTx = baseTx - tx := &txs.Tx{Unsigned: &eTx} require.NoError(tx.SignSECP256K1Fx( codec, [][]*secp256k1.PrivateKey{ @@ -989,329 +608,14 @@ func TestSemanticVerifierExportTx(t *testing.T) { )) return tx }, - err: secp256k1fx.ErrNoValueInput, - }, - { - name: "duplicate inputs", - stateFunc: func(*gomock.Controller) state.Chain { - return nil - }, - txFunc: func(require *require.Assertions) *txs.Tx { - baseTx := baseTx - baseTx.Ins = []*avax.TransferableInput{ - &input, - &input, - } - - eTx := exportTx - eTx.BaseTx.BaseTx = baseTx - tx := &txs.Tx{Unsigned: &eTx} - require.NoError(tx.SignSECP256K1Fx( - codec, - [][]*secp256k1.PrivateKey{ - {keys[0]}, - {keys[0]}, - }, - )) - return tx - }, - err: avax.ErrInputsNotSortedUnique, - }, - { - name: "input overflow", - stateFunc: func(*gomock.Controller) state.Chain { - return nil - }, - txFunc: func(require *require.Assertions) *txs.Tx { - input0 := input - input0.In = &secp256k1fx.TransferInput{ - Amt: 1, - Input: inputSigners, - } - - input1 := input - input1.UTXOID.OutputIndex++ - input1.In = &secp256k1fx.TransferInput{ - Amt: math.MaxUint64, - Input: inputSigners, - } - - baseTx := baseTx - baseTx.Ins = []*avax.TransferableInput{ - &input0, - &input1, - } - avax.SortTransferableInputsWithSigners(baseTx.Ins, make([][]*secp256k1.PrivateKey, 2)) - - eTx := exportTx - eTx.BaseTx.BaseTx = baseTx - tx := &txs.Tx{Unsigned: &eTx} - require.NoError(tx.SignSECP256K1Fx( - codec, - [][]*secp256k1.PrivateKey{ - {keys[0]}, - }, - )) - return tx - }, - err: safemath.ErrOverflow, - }, - { - name: "output overflow", - stateFunc: func(*gomock.Controller) state.Chain { - return nil - }, - txFunc: func(require *require.Assertions) *txs.Tx { - output0 := output - output0.Out = &secp256k1fx.TransferOutput{ - Amt: 1, - OutputOwners: outputOwners, - } - - output1 := output - output1.Out = &secp256k1fx.TransferOutput{ - Amt: math.MaxUint64, - OutputOwners: outputOwners, - } - - outputs := []*avax.TransferableOutput{ - &output0, - &output1, - } - avax.SortTransferableOutputs(outputs, codec) - - baseTx := baseTx - baseTx.Outs = outputs - - eTx := exportTx - eTx.BaseTx.BaseTx = baseTx - tx := &txs.Tx{Unsigned: &eTx} - require.NoError(tx.SignSECP256K1Fx( - codec, - [][]*secp256k1.PrivateKey{ - {keys[0]}, - }, - )) - return tx - }, - err: safemath.ErrOverflow, - }, - { - name: "barely sufficient funds", - stateFunc: func(ctrl *gomock.Controller) state.Chain { - state := state.NewMockChain(ctrl) - - utxoAmount := 100 + feeConfig.TxFee - utxoOut := secp256k1fx.TransferOutput{ - Amt: utxoAmount, - OutputOwners: outputOwners, - } - utxo := avax.UTXO{ - UTXOID: utxoID, - Asset: asset, - Out: &utxoOut, - } - - state.EXPECT().GetUTXO(utxoID.InputID()).Return(&utxo, nil) - state.EXPECT().GetTx(asset.ID).Return(&createAssetTx, nil).Times(2) - - return state - }, - txFunc: func(require *require.Assertions) *txs.Tx { - input := input - input.In = &secp256k1fx.TransferInput{ - Amt: fxOutput.Amt + feeConfig.TxFee, - Input: inputSigners, - } - - baseTx := baseTx - baseTx.Ins = []*avax.TransferableInput{ - &input, - } - - eTx := exportTx - eTx.BaseTx.BaseTx = baseTx - tx := &txs.Tx{Unsigned: &eTx} - require.NoError(tx.SignSECP256K1Fx( - codec, - [][]*secp256k1.PrivateKey{ - {keys[0]}, - }, - )) - return tx - }, - err: nil, - }, - { - name: "insufficient funds", - stateFunc: func(*gomock.Controller) state.Chain { - return nil - }, - txFunc: func(require *require.Assertions) *txs.Tx { - input := input - input.In = &secp256k1fx.TransferInput{ - Amt: 1, - Input: inputSigners, - } - - baseTx := baseTx - baseTx.Ins = []*avax.TransferableInput{ - &input, - } - - eTx := exportTx - eTx.BaseTx.BaseTx = baseTx - tx := &txs.Tx{Unsigned: &eTx} - require.NoError(tx.SignSECP256K1Fx( - codec, - [][]*secp256k1.PrivateKey{ - {keys[0]}, - }, - )) - return tx - }, - err: avax.ErrInsufficientFunds, - }, - { - name: "barely insufficient funds", - stateFunc: func(*gomock.Controller) state.Chain { - return nil - }, - txFunc: func(require *require.Assertions) *txs.Tx { - input := input - input.In = &secp256k1fx.TransferInput{ - Amt: fxOutput.Amt + feeConfig.TxFee - 1, - Input: inputSigners, - } - - baseTx := baseTx - baseTx.Ins = []*avax.TransferableInput{ - &input, - } - - eTx := exportTx - eTx.BaseTx.BaseTx = baseTx - tx := &txs.Tx{Unsigned: &eTx} - require.NoError(tx.SignSECP256K1Fx( - codec, - [][]*secp256k1.PrivateKey{ - {keys[0]}, - }, - )) - return tx - }, - err: avax.ErrInsufficientFunds, - }, - { - name: "assetID mismatch", - stateFunc: func(ctrl *gomock.Controller) state.Chain { - state := state.NewMockChain(ctrl) - - utxo := utxo - utxo.Asset.ID = ids.GenerateTestID() - - state.EXPECT().GetUTXO(utxoID.InputID()).Return(&utxo, nil) - - return state - }, - txFunc: func(require *require.Assertions) *txs.Tx { - tx := &txs.Tx{ - Unsigned: &exportTx, - } - require.NoError(tx.SignSECP256K1Fx( - codec, - [][]*secp256k1.PrivateKey{ - {keys[0]}, - }, - )) - return tx - }, - err: errAssetIDMismatch, - }, - { - name: "not allowed input feature extension", - stateFunc: func(ctrl *gomock.Controller) state.Chain { - state := state.NewMockChain(ctrl) - - unsignedCreateAssetTx := unsignedCreateAssetTx - unsignedCreateAssetTx.States = nil - - createAssetTx := txs.Tx{ - Unsigned: &unsignedCreateAssetTx, - } - - state.EXPECT().GetUTXO(utxoID.InputID()).Return(&utxo, nil) - state.EXPECT().GetTx(asset.ID).Return(&createAssetTx, nil) - - return state - }, - txFunc: func(require *require.Assertions) *txs.Tx { - tx := &txs.Tx{ - Unsigned: &exportTx, - } - require.NoError(tx.SignSECP256K1Fx( - codec, - [][]*secp256k1.PrivateKey{ - {keys[0]}, - }, - )) - return tx - }, - err: errIncompatibleFx, - }, - { - name: "invalid signature", - stateFunc: func(ctrl *gomock.Controller) state.Chain { - state := state.NewMockChain(ctrl) - - state.EXPECT().GetUTXO(utxoID.InputID()).Return(&utxo, nil) - state.EXPECT().GetTx(asset.ID).Return(&createAssetTx, nil) - - return state - }, - txFunc: func(require *require.Assertions) *txs.Tx { - tx := &txs.Tx{ - Unsigned: &exportTx, - } - require.NoError(tx.SignSECP256K1Fx( - codec, - [][]*secp256k1.PrivateKey{ - {keys[1]}, - }, - )) - return tx - }, - err: secp256k1fx.ErrWrongSig, - }, - { - name: "missing UTXO", - stateFunc: func(ctrl *gomock.Controller) state.Chain { - state := state.NewMockChain(ctrl) - - state.EXPECT().GetUTXO(utxoID.InputID()).Return(nil, database.ErrNotFound) - - return state - }, - txFunc: func(require *require.Assertions) *txs.Tx { - tx := &txs.Tx{ - Unsigned: &exportTx, - } - require.NoError(tx.SignSECP256K1Fx( - codec, - [][]*secp256k1.PrivateKey{ - {keys[0]}, - }, - )) - return tx - }, - err: database.ErrNotFound, + err: database.ErrNotFound, }, { name: "invalid UTXO amount", stateFunc: func(ctrl *gomock.Controller) state.Chain { state := state.NewMockChain(ctrl) - output := utxoOut + output := output output.Amt-- utxo := utxo @@ -1349,19 +653,24 @@ func TestSemanticVerifierExportTx(t *testing.T) { } state.EXPECT().GetTx(asset.ID).Return(&createAssetTx, nil) - state.EXPECT().GetUTXO(utxoID.InputID()).Return(&utxo, nil) return state }, txFunc: func(require *require.Assertions) *txs.Tx { + exportTx := exportTx + exportTx.Ins = nil + exportTx.ExportedOuts = []*avax.TransferableOutput{ + { + Asset: asset, + Out: &output, + }, + } tx := &txs.Tx{ Unsigned: &exportTx, } require.NoError(tx.SignSECP256K1Fx( codec, - [][]*secp256k1.PrivateKey{ - {keys[0]}, - }, + [][]*secp256k1.PrivateKey{}, )) return tx }, @@ -1397,7 +706,7 @@ func TestSemanticVerifierExportTx(t *testing.T) { state := state.NewMockChain(ctrl) tx := txs.Tx{ - Unsigned: &exportTx, + Unsigned: &baseTx, } state.EXPECT().GetUTXO(utxoID.InputID()).Return(&utxo, nil) @@ -1448,86 +757,53 @@ func TestSemanticVerifierExportTxDifferentSubnet(t *testing.T) { validatorState.EXPECT().GetSubnetID(gomock.Any(), ctx.CChainID).AnyTimes().Return(ids.GenerateTestID(), nil) ctx.ValidatorState = validatorState - // UTXO to be spent - inputTxID := ids.GenerateTestID() + typeToFxIndex := make(map[reflect.Type]int) + secpFx := &secp256k1fx.Fx{} + parser, err := txs.NewCustomParser( + typeToFxIndex, + new(mockable.Clock), + logging.NoWarn{}, + []fxs.Fx{ + secpFx, + }, + ) + require.NoError(err) + + codec := parser.Codec() + txID := ids.GenerateTestID() utxoID := avax.UTXOID{ - TxID: inputTxID, - OutputIndex: 0, + TxID: txID, + OutputIndex: 2, } - - feeAssetID := ids.GenerateTestID() asset := avax.Asset{ - ID: feeAssetID, - } - outputOwners := secp256k1fx.OutputOwners{ - Threshold: 1, - Addrs: []ids.ShortID{keys[0].PublicKey().Address()}, - } - utxoAmount := 100 + feeConfig.TxFee - utxoOut := secp256k1fx.TransferOutput{ - Amt: utxoAmount, - OutputOwners: outputOwners, - } - utxo := avax.UTXO{ - UTXOID: utxoID, - Asset: asset, - Out: &utxoOut, + ID: ids.GenerateTestID(), } - - // Input spending the UTXO - inputSigners := secp256k1fx.Input{ - SigIndices: []uint32{0}, + inputSigner := secp256k1fx.Input{ + SigIndices: []uint32{ + 0, + }, } fxInput := secp256k1fx.TransferInput{ - Amt: utxoAmount, - Input: inputSigners, + Amt: 12345, + Input: inputSigner, } input := avax.TransferableInput{ UTXOID: utxoID, Asset: asset, In: &fxInput, } - - // Output produced by BaseTx - fxOutput := secp256k1fx.TransferOutput{ - Amt: 100, - OutputOwners: outputOwners, - } - output := avax.TransferableOutput{ - Asset: asset, - Out: &fxOutput, - } - - // BaseTx - baseTx := avax.BaseTx{ - Outs: []*avax.TransferableOutput{ - &output, - }, - Ins: []*avax.TransferableInput{ - &input, + baseTx := txs.BaseTx{ + BaseTx: avax.BaseTx{ + Ins: []*avax.TransferableInput{ + &input, + }, }, } - exportTx := txs.ExportTx{ - BaseTx: txs.BaseTx{ - BaseTx: baseTx, - }, + BaseTx: baseTx, DestinationChain: ctx.CChainID, } - typeToFxIndex := make(map[reflect.Type]int) - secpFx := &secp256k1fx.Fx{} - parser, err := txs.NewCustomParser( - typeToFxIndex, - new(mockable.Clock), - logging.NoWarn{}, - []fxs.Fx{ - secpFx, - }, - ) - require.NoError(err) - - codec := parser.Codec() backend := &Backend{ Ctx: ctx, Config: &feeConfig, @@ -1539,11 +815,26 @@ func TestSemanticVerifierExportTxDifferentSubnet(t *testing.T) { }, TypeToFxIndex: typeToFxIndex, Codec: codec, - FeeAssetID: feeAssetID, + FeeAssetID: ids.GenerateTestID(), Bootstrapped: true, } require.NoError(secpFx.Bootstrapped()) + outputOwners := secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{ + keys[0].Address(), + }, + } + output := secp256k1fx.TransferOutput{ + Amt: 12345, + OutputOwners: outputOwners, + } + utxo := avax.UTXO{ + UTXOID: utxoID, + Asset: asset, + Out: &output, + } unsignedCreateAssetTx := txs.CreateAssetTx{ States: []*txs.InitialState{{ FxIndex: 0, @@ -1556,7 +847,7 @@ func TestSemanticVerifierExportTxDifferentSubnet(t *testing.T) { state := state.NewMockChain(ctrl) state.EXPECT().GetUTXO(utxoID.InputID()).Return(&utxo, nil) - state.EXPECT().GetTx(asset.ID).Return(&createAssetTx, nil).Times(2) + state.EXPECT().GetTx(asset.ID).Return(&createAssetTx, nil) tx := &txs.Tx{ Unsigned: &exportTx, @@ -1593,84 +884,50 @@ func TestSemanticVerifierImportTx(t *testing.T) { }, ) require.NoError(t, err) - codec := parser.Codec() - // UTXOs to be spent - utxoAmount := 100 + feeConfig.TxFee - inputTxID := ids.GenerateTestID() + codec := parser.Codec() utxoID := avax.UTXOID{ - TxID: inputTxID, - OutputIndex: 0, + TxID: ids.GenerateTestID(), + OutputIndex: 2, } - feeAssetID := ids.GenerateTestID() asset := avax.Asset{ - ID: feeAssetID, + ID: ids.GenerateTestID(), } outputOwners := secp256k1fx.OutputOwners{ Threshold: 1, - Addrs: []ids.ShortID{keys[0].PublicKey().Address()}, - } - utxoOut := secp256k1fx.TransferOutput{ - Amt: utxoAmount, - OutputOwners: outputOwners, - } - utxo := avax.UTXO{ - UTXOID: utxoID, - Asset: asset, - Out: &utxoOut, - } - - // Input spending the UTXO - inputSigners := secp256k1fx.Input{ - SigIndices: []uint32{0}, - } - fxInput := secp256k1fx.TransferInput{ - Amt: utxoAmount, - Input: inputSigners, - } - input := avax.TransferableInput{ - UTXOID: utxoID, - Asset: asset, - In: &fxInput, - } - - // Output produced by BaseTx - fxOutput := secp256k1fx.TransferOutput{ - Amt: 100, - OutputOwners: outputOwners, - } - output := avax.TransferableOutput{ - Asset: asset, - Out: &fxOutput, + Addrs: []ids.ShortID{ + keys[0].Address(), + }, } - - baseTx := avax.BaseTx{ - NetworkID: constants.UnitTestID, - BlockchainID: ctx.ChainID, - Outs: []*avax.TransferableOutput{ - &output, + baseTx := txs.BaseTx{ + BaseTx: avax.BaseTx{ + NetworkID: constants.UnitTestID, + BlockchainID: ctx.ChainID, + Outs: []*avax.TransferableOutput{{ + Asset: asset, + Out: &secp256k1fx.TransferOutput{ + Amt: 1000, + OutputOwners: outputOwners, + }, + }}, }, - // no inputs here, only imported ones } - - importedInput := avax.TransferableInput{ + input := avax.TransferableInput{ UTXOID: utxoID, Asset: asset, In: &secp256k1fx.TransferInput{ - Amt: utxoAmount, + Amt: 12345, Input: secp256k1fx.Input{ SigIndices: []uint32{0}, }, }, } unsignedImportTx := txs.ImportTx{ - BaseTx: txs.BaseTx{ - BaseTx: baseTx, - }, + BaseTx: baseTx, SourceChain: ctx.CChainID, ImportedIns: []*avax.TransferableInput{ - &importedInput, + &input, }, } importTx := &txs.Tx{ @@ -1680,7 +937,6 @@ func TestSemanticVerifierImportTx(t *testing.T) { codec, [][]*secp256k1.PrivateKey{ {keys[0]}, - {keys[0]}, }, )) @@ -1695,11 +951,20 @@ func TestSemanticVerifierImportTx(t *testing.T) { }, TypeToFxIndex: typeToFxIndex, Codec: codec, - FeeAssetID: feeAssetID, + FeeAssetID: ids.GenerateTestID(), Bootstrapped: true, } require.NoError(t, fx.Bootstrapped()) + output := secp256k1fx.TransferOutput{ + Amt: 12345, + OutputOwners: outputOwners, + } + utxo := avax.UTXO{ + UTXOID: utxoID, + Asset: asset, + Out: &output, + } utxoBytes, err := codec.Marshal(txs.CodecVersion, utxo) require.NoError(t, err) @@ -1740,237 +1005,6 @@ func TestSemanticVerifierImportTx(t *testing.T) { }, expectedErr: nil, }, - { - name: "invalid output", - stateFunc: func(*gomock.Controller) state.Chain { - return nil - }, - txFunc: func(require *require.Assertions) *txs.Tx { - output := output - output.Out = &secp256k1fx.TransferOutput{ - Amt: 0, - OutputOwners: outputOwners, - } - - utx := unsignedImportTx - utx.Outs = []*avax.TransferableOutput{ - &output, - } - - tx := &txs.Tx{Unsigned: &utx} - require.NoError(tx.SignSECP256K1Fx( - codec, - [][]*secp256k1.PrivateKey{ - {keys[0]}, - }, - )) - return tx - }, - expectedErr: secp256k1fx.ErrNoValueOutput, - }, - { - name: "unsorted outputs", - stateFunc: func(*gomock.Controller) state.Chain { - return nil - }, - txFunc: func(require *require.Assertions) *txs.Tx { - output0 := output - output0.Out = &secp256k1fx.TransferOutput{ - Amt: 1, - OutputOwners: outputOwners, - } - - output1 := output - output1.Out = &secp256k1fx.TransferOutput{ - Amt: 2, - OutputOwners: outputOwners, - } - - outputs := []*avax.TransferableOutput{ - &output0, - &output1, - } - avax.SortTransferableOutputs(outputs, codec) - outputs[0], outputs[1] = outputs[1], outputs[0] - - utx := unsignedImportTx - utx.Outs = outputs - tx := &txs.Tx{Unsigned: &utx} - require.NoError(tx.SignSECP256K1Fx( - codec, - [][]*secp256k1.PrivateKey{ - {keys[0]}, - }, - )) - return tx - }, - expectedErr: avax.ErrOutputsNotSorted, - }, - { - name: "invalid input", - stateFunc: func(*gomock.Controller) state.Chain { - return nil - }, - txFunc: func(require *require.Assertions) *txs.Tx { - input := input - input.In = &secp256k1fx.TransferInput{ - Amt: 0, - Input: inputSigners, - } - - utx := unsignedImportTx - utx.Ins = []*avax.TransferableInput{ - &input, - } - tx := &txs.Tx{Unsigned: &utx} - require.NoError(tx.SignSECP256K1Fx( - codec, - [][]*secp256k1.PrivateKey{ - {keys[0]}, - }, - )) - return tx - }, - expectedErr: secp256k1fx.ErrNoValueInput, - }, - { - name: "duplicate inputs", - stateFunc: func(*gomock.Controller) state.Chain { - return nil - }, - txFunc: func(require *require.Assertions) *txs.Tx { - utx := unsignedImportTx - utx.Ins = []*avax.TransferableInput{ - &input, - &input, - } - tx := &txs.Tx{Unsigned: &utx} - require.NoError(tx.SignSECP256K1Fx( - codec, - [][]*secp256k1.PrivateKey{ - {keys[0]}, - {keys[0]}, - {keys[0]}, - })) - return tx - }, - expectedErr: avax.ErrInputsNotSortedUnique, - }, - { - name: "duplicate imported inputs", - stateFunc: func(*gomock.Controller) state.Chain { - return nil - }, - txFunc: func(require *require.Assertions) *txs.Tx { - utx := unsignedImportTx - utx.ImportedIns = []*avax.TransferableInput{ - &input, - &input, - } - tx := &txs.Tx{Unsigned: &utx} - require.NoError(tx.SignSECP256K1Fx( - codec, - [][]*secp256k1.PrivateKey{ - {keys[0]}, - {keys[0]}, - })) - return tx - }, - expectedErr: avax.ErrInputsNotSortedUnique, - }, - { - name: "input overflow", - stateFunc: func(*gomock.Controller) state.Chain { - return nil - }, - txFunc: func(require *require.Assertions) *txs.Tx { - input0 := input - input0.In = &secp256k1fx.TransferInput{ - Amt: 1, - Input: inputSigners, - } - - input1 := input - input1.UTXOID.OutputIndex++ - input1.In = &secp256k1fx.TransferInput{ - Amt: math.MaxUint64, - Input: inputSigners, - } - - utx := unsignedImportTx - utx.Ins = []*avax.TransferableInput{ - &input0, - &input1, - } - avax.SortTransferableInputsWithSigners(utx.Ins, make([][]*secp256k1.PrivateKey, 2)) - tx := &txs.Tx{Unsigned: &utx} - require.NoError(tx.SignSECP256K1Fx( - codec, - [][]*secp256k1.PrivateKey{ - {keys[0]}, - {keys[0]}, - })) - return tx - }, - expectedErr: safemath.ErrOverflow, - }, - { - name: "output overflow", - stateFunc: func(*gomock.Controller) state.Chain { - return nil - }, - txFunc: func(require *require.Assertions) *txs.Tx { - output := output - output.Out = &secp256k1fx.TransferOutput{ - Amt: math.MaxUint64, - OutputOwners: outputOwners, - } - - outputs := []*avax.TransferableOutput{ - &output, - } - avax.SortTransferableOutputs(outputs, codec) - - utx := unsignedImportTx - utx.Outs = outputs - tx := &txs.Tx{Unsigned: &utx} - require.NoError(tx.SignSECP256K1Fx( - codec, - [][]*secp256k1.PrivateKey{ - {keys[0]}, - {keys[0]}, - })) - return tx - }, - expectedErr: safemath.ErrOverflow, - }, - { - name: "insufficient funds", - stateFunc: func(*gomock.Controller) state.Chain { - return nil - }, - txFunc: func(require *require.Assertions) *txs.Tx { - input := input - input.In = &secp256k1fx.TransferInput{ - Amt: 1, - Input: inputSigners, - } - - utx := unsignedImportTx - utx.ImportedIns = []*avax.TransferableInput{ - &input, - } - tx := &txs.Tx{Unsigned: &utx} - require.NoError(tx.SignSECP256K1Fx( - codec, - [][]*secp256k1.PrivateKey{ - {keys[0]}, - {keys[0]}, - })) - return tx - }, - expectedErr: avax.ErrInsufficientFunds, - }, { name: "not allowed input feature extension", stateFunc: func(ctrl *gomock.Controller) state.Chain { @@ -2058,9 +1092,7 @@ func TestSemanticVerifierImportTx(t *testing.T) { stateFunc: func(ctrl *gomock.Controller) state.Chain { state := state.NewMockChain(ctrl) tx := txs.Tx{ - Unsigned: &txs.BaseTx{ - BaseTx: baseTx, - }, + Unsigned: &baseTx, } state.EXPECT().GetUTXO(utxoID.InputID()).Return(&utxo, nil).AnyTimes() state.EXPECT().GetTx(asset.ID).Return(&tx, nil) @@ -2088,451 +1120,3 @@ func TestSemanticVerifierImportTx(t *testing.T) { }) } } - -func TestSemanticVerifierOperationTx(t *testing.T) { - ctx := snowtest.Context(t, snowtest.XChainID) - - var ( - secpFx = &secp256k1fx.Fx{} - nftFx = &nftfx.Fx{} - propertyFx = &propertyfx.Fx{} - ) - - typeToFxIndex := make(map[reflect.Type]int) - parser, err := txs.NewCustomParser( - typeToFxIndex, - new(mockable.Clock), - logging.NoWarn{}, - []fxs.Fx{ - secpFx, - nftFx, - propertyFx, - }, - ) - - require.NoError(t, err) - codec := parser.Codec() - - feeAssetID := ids.GenerateTestID() - feeAsset := avax.Asset{ - ID: feeAssetID, - } - - outputOwners := secp256k1fx.OutputOwners{ - Threshold: 1, - Addrs: []ids.ShortID{ - keys[0].Address(), - }, - } - - utxoAmount := 20 * units.KiloAvax - utxoID := avax.UTXOID{ - TxID: ids.GenerateTestID(), - OutputIndex: 1, - } - utxo := &avax.UTXO{ - UTXOID: utxoID, - Asset: feeAsset, - Out: &secp256k1fx.TransferOutput{ - Amt: 20 * units.KiloAvax, - OutputOwners: outputOwners, - }, - } - - opUTXOID := avax.UTXOID{ - TxID: ids.GenerateTestID(), - OutputIndex: 1, - } - opUTXO := &avax.UTXO{ - UTXOID: opUTXOID, - Asset: avax.Asset{ID: assetID}, - Out: &secp256k1fx.MintOutput{ - OutputOwners: outputOwners, - }, - } - - unsignedCreateAssetTx := txs.CreateAssetTx{ - States: []*txs.InitialState{{ - FxIndex: 0, - }}, - } - createAssetTx := &txs.Tx{ - Unsigned: &unsignedCreateAssetTx, - } - - opTxInSigner := secp256k1fx.Input{ - SigIndices: []uint32{ - 0, - }, - } - opTxIn := avax.TransferableInput{ - UTXOID: utxoID, - Asset: feeAsset, - In: &secp256k1fx.TransferInput{ - Amt: utxoAmount, - Input: opTxInSigner, - }, - } - opTxOut := avax.TransferableOutput{ - Asset: avax.Asset{ID: feeAssetID}, - Out: &secp256k1fx.TransferOutput{ - Amt: units.NanoAvax, - OutputOwners: outputOwners, - }, - } - unsignedOperationTx := txs.OperationTx{ - BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ - NetworkID: constants.UnitTestID, - BlockchainID: chainID, - Ins: []*avax.TransferableInput{&opTxIn}, - Outs: []*avax.TransferableOutput{&opTxOut}, - }}, - Ops: []*txs.Operation{{ - Asset: avax.Asset{ID: assetID}, - UTXOIDs: []*avax.UTXOID{ - &opUTXOID, - }, - Op: &secp256k1fx.MintOperation{ - MintInput: secp256k1fx.Input{ - SigIndices: []uint32{0}, - }, - MintOutput: secp256k1fx.MintOutput{ - OutputOwners: outputOwners, - }, - TransferOutput: secp256k1fx.TransferOutput{ - Amt: 1, - OutputOwners: outputOwners, - }, - }, - }}, - } - - operationTx := txs.Tx{Unsigned: &unsignedOperationTx} - require.NoError(t, operationTx.SignSECP256K1Fx( - codec, - [][]*secp256k1.PrivateKey{ - {keys[0]}, - {keys[0]}, - }, - )) - - backend := &Backend{ - Ctx: ctx, - Config: &feeConfig, - Fxs: []*fxs.ParsedFx{ - { - ID: secp256k1fx.ID, - Fx: secpFx, - }, - { - ID: nftfx.ID, - Fx: nftFx, - }, - { - ID: propertyfx.ID, - Fx: propertyFx, - }, - }, - Codec: codec, - TypeToFxIndex: typeToFxIndex, - FeeAssetID: feeAssetID, - } - require.NoError(t, secpFx.Bootstrapped()) - require.NoError(t, nftFx.Bootstrapped()) - require.NoError(t, propertyFx.Bootstrapped()) - - tests := []struct { - name string - stateFunc func(*gomock.Controller) state.Chain - txFunc func(*require.Assertions) *txs.Tx - expectedErr error - }{ - { - name: "valid", - stateFunc: func(ctrl *gomock.Controller) state.Chain { - state := state.NewMockChain(ctrl) - state.EXPECT().GetUTXO(utxoID.InputID()).Return(utxo, nil).AnyTimes() - state.EXPECT().GetUTXO(opUTXO.InputID()).Return(opUTXO, nil).AnyTimes() - state.EXPECT().GetTx(feeAssetID).Return(createAssetTx, nil).AnyTimes() - return state - }, - txFunc: func(*require.Assertions) *txs.Tx { - return &operationTx - }, - expectedErr: nil, - }, - { - name: "invalid output", - stateFunc: func(ctrl *gomock.Controller) state.Chain { - state := state.NewMockChain(ctrl) - return state - }, - txFunc: func(*require.Assertions) *txs.Tx { - output := opTxOut - output.Out = &secp256k1fx.TransferOutput{ - Amt: 0, - OutputOwners: outputOwners, - } - - unsignedTx := unsignedOperationTx - unsignedTx.Outs = []*avax.TransferableOutput{ - &output, - } - return &txs.Tx{ - Unsigned: &unsignedTx, - Creds: operationTx.Creds, - } - }, - expectedErr: secp256k1fx.ErrNoValueOutput, - }, - { - name: "unsorted outputs", - stateFunc: func(ctrl *gomock.Controller) state.Chain { - state := state.NewMockChain(ctrl) - return state - }, - txFunc: func(*require.Assertions) *txs.Tx { - output0 := opTxOut - output0.Out = &secp256k1fx.TransferOutput{ - Amt: 1, - OutputOwners: outputOwners, - } - - output1 := opTxOut - output1.Out = &secp256k1fx.TransferOutput{ - Amt: 2, - OutputOwners: outputOwners, - } - - outputs := []*avax.TransferableOutput{ - &output0, - &output1, - } - avax.SortTransferableOutputs(outputs, codec) - outputs[0], outputs[1] = outputs[1], outputs[0] - - unsignedTx := unsignedOperationTx - unsignedTx.Outs = outputs - return &txs.Tx{ - Unsigned: &unsignedTx, - Creds: operationTx.Creds, - } - }, - expectedErr: avax.ErrOutputsNotSorted, - }, - { - name: "invalid input", - stateFunc: func(ctrl *gomock.Controller) state.Chain { - state := state.NewMockChain(ctrl) - return state - }, - txFunc: func(*require.Assertions) *txs.Tx { - input := opTxIn - input.In = &secp256k1fx.TransferInput{ - Amt: 0, - Input: opTxInSigner, - } - - tx := unsignedOperationTx - tx.Ins = []*avax.TransferableInput{ - &input, - } - return &txs.Tx{ - Unsigned: &tx, - Creds: operationTx.Creds, - } - }, - expectedErr: secp256k1fx.ErrNoValueInput, - }, - { - name: "duplicate inputs", - stateFunc: func(ctrl *gomock.Controller) state.Chain { - state := state.NewMockChain(ctrl) - return state - }, - txFunc: func(*require.Assertions) *txs.Tx { - unsignedTx := unsignedOperationTx - unsignedTx.Ins = []*avax.TransferableInput{ - &opTxIn, - &opTxIn, - } - - tx := &txs.Tx{Unsigned: &unsignedTx} - require.NoError(t, tx.SignSECP256K1Fx( - codec, - [][]*secp256k1.PrivateKey{ - {keys[0]}, - {keys[0]}, - })) - - return tx - }, - expectedErr: avax.ErrInputsNotSortedUnique, - }, - { - name: "input overflow", - stateFunc: func(ctrl *gomock.Controller) state.Chain { - state := state.NewMockChain(ctrl) - return state - }, - txFunc: func(*require.Assertions) *txs.Tx { - input0 := opTxIn - input0.In = &secp256k1fx.TransferInput{ - Amt: 1, - Input: opTxInSigner, - } - - input1 := opTxIn - input1.UTXOID.OutputIndex++ - input1.In = &secp256k1fx.TransferInput{ - Amt: math.MaxUint64, - Input: opTxInSigner, - } - - unsignedTx := unsignedOperationTx - unsignedTx.Ins = []*avax.TransferableInput{ - &input0, - &input1, - } - avax.SortTransferableInputsWithSigners(unsignedTx.Ins, make([][]*secp256k1.PrivateKey, 2)) - - tx := &txs.Tx{Unsigned: &unsignedTx} - require.NoError(t, tx.SignSECP256K1Fx( - codec, - [][]*secp256k1.PrivateKey{ - {keys[0]}, - {keys[0]}, - })) - return tx - }, - expectedErr: safemath.ErrOverflow, - }, - { - name: "output overflow", - stateFunc: func(ctrl *gomock.Controller) state.Chain { - state := state.NewMockChain(ctrl) - return state - }, - txFunc: func(*require.Assertions) *txs.Tx { - output := opTxOut - output.Out = &secp256k1fx.TransferOutput{ - Amt: math.MaxUint64, - OutputOwners: outputOwners, - } - - outputs := []*avax.TransferableOutput{ - &output, - } - avax.SortTransferableOutputs(outputs, codec) - - unsignedTx := unsignedOperationTx - unsignedTx.Outs = outputs - return &txs.Tx{ - Unsigned: &unsignedTx, - Creds: operationTx.Creds, - } - }, - expectedErr: safemath.ErrOverflow, - }, - { - name: "insufficient funds", - stateFunc: func(ctrl *gomock.Controller) state.Chain { - state := state.NewMockChain(ctrl) - return state - }, - txFunc: func(*require.Assertions) *txs.Tx { - input := opTxIn - input.In = &secp256k1fx.TransferInput{ - Amt: 1, - Input: opTxInSigner, - } - - unsignedTx := unsignedOperationTx - unsignedTx.Ins = []*avax.TransferableInput{ - &input, - } - return &txs.Tx{ - Unsigned: &unsignedTx, - Creds: operationTx.Creds, - } - }, - expectedErr: avax.ErrInsufficientFunds, - }, - { - name: "barely sufficient funds", - stateFunc: func(ctrl *gomock.Controller) state.Chain { - state := state.NewMockChain(ctrl) - - barelySufficientUtxo := &avax.UTXO{ - UTXOID: utxoID, - Asset: feeAsset, - Out: &secp256k1fx.TransferOutput{ - Amt: units.NanoAvax + feeConfig.TxFee, - OutputOwners: outputOwners, - }, - } - - state.EXPECT().GetUTXO(utxoID.InputID()).Return(barelySufficientUtxo, nil).AnyTimes() - state.EXPECT().GetUTXO(opUTXO.InputID()).Return(opUTXO, nil).AnyTimes() - state.EXPECT().GetTx(feeAssetID).Return(createAssetTx, nil).AnyTimes() - return state - }, - txFunc: func(*require.Assertions) *txs.Tx { - input := opTxIn - input.In = &secp256k1fx.TransferInput{ - Amt: units.NanoAvax + feeConfig.TxFee, - Input: opTxInSigner, - } - - unsignedTx := unsignedOperationTx - unsignedTx.Ins = []*avax.TransferableInput{ - &input, - } - return &txs.Tx{ - Unsigned: &unsignedTx, - Creds: operationTx.Creds, - } - }, - expectedErr: nil, - }, - { - name: "barely insufficient funds", - stateFunc: func(ctrl *gomock.Controller) state.Chain { - state := state.NewMockChain(ctrl) - return state - }, - txFunc: func(*require.Assertions) *txs.Tx { - input := opTxIn - input.In = &secp256k1fx.TransferInput{ - Amt: feeConfig.TxFee, - Input: opTxInSigner, - } - - unsignedTx := unsignedOperationTx - unsignedTx.Ins = []*avax.TransferableInput{ - &input, - } - return &txs.Tx{ - Unsigned: &unsignedTx, - Creds: operationTx.Creds, - } - }, - expectedErr: avax.ErrInsufficientFunds, - }, - } - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - require := require.New(t) - ctrl := gomock.NewController(t) - - state := test.stateFunc(ctrl) - tx := test.txFunc(require) - err := tx.Unsigned.Visit(&SemanticVerifier{ - Backend: backend, - State: state, - Tx: tx, - }) - require.ErrorIs(err, test.expectedErr) - }) - } -} diff --git a/vms/avm/txs/executor/syntactic_verifier.go b/vms/avm/txs/executor/syntactic_verifier.go index 726f69644ee..b964ca1df02 100644 --- a/vms/avm/txs/executor/syntactic_verifier.go +++ b/vms/avm/txs/executor/syntactic_verifier.go @@ -13,6 +13,8 @@ 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/fee" + "github.com/ava-labs/avalanchego/vms/components/avax" ) const ( @@ -50,7 +52,7 @@ type SyntacticVerifier struct { } func (v *SyntacticVerifier) BaseTx(tx *txs.BaseTx) error { - if err := tx.BaseTx.Verify(v.Ctx); err != nil { + if err := v.verifyBaseTx(tx, nil, nil); err != nil { return err } @@ -102,7 +104,7 @@ func (v *SyntacticVerifier) CreateAssetTx(tx *txs.CreateAssetTx) error { } } - if err := tx.BaseTx.BaseTx.Verify(v.Ctx); err != nil { + if err := v.verifyBaseTx(&tx.BaseTx, nil, nil); err != nil { return err } @@ -139,7 +141,7 @@ func (v *SyntacticVerifier) OperationTx(tx *txs.OperationTx) error { return errNoOperations } - if err := tx.BaseTx.BaseTx.Verify(v.Ctx); err != nil { + if err := v.verifyBaseTx(&tx.BaseTx, nil, nil); err != nil { return err } @@ -188,7 +190,7 @@ func (v *SyntacticVerifier) ImportTx(tx *txs.ImportTx) error { return errNoImportInputs } - if err := tx.BaseTx.BaseTx.Verify(v.Ctx); err != nil { + if err := v.verifyBaseTx(&tx.BaseTx, tx.ImportedIns, nil); err != nil { return err } @@ -216,7 +218,7 @@ func (v *SyntacticVerifier) ExportTx(tx *txs.ExportTx) error { return errNoExportOutputs } - if err := tx.BaseTx.BaseTx.Verify(v.Ctx); err != nil { + if err := v.verifyBaseTx(&tx.BaseTx, nil, tx.ExportedOuts); err != nil { return err } @@ -238,3 +240,27 @@ func (v *SyntacticVerifier) ExportTx(tx *txs.ExportTx) error { return nil } + +func (v *SyntacticVerifier) verifyBaseTx( + bTx *txs.BaseTx, + importedIns []*avax.TransferableInput, + exportedOuts []*avax.TransferableOutput, +) error { + if err := bTx.BaseTx.Verify(v.Ctx); err != nil { + return err + } + + feeCalculator := fee.NewStaticCalculator(v.Backend.Config.StaticConfig) + fee, err := feeCalculator.CalculateFee(v.Tx) + if err != nil { + return err + } + + return avax.VerifyTx( + fee, + v.FeeAssetID, + [][]*avax.TransferableInput{bTx.Ins, importedIns}, + [][]*avax.TransferableOutput{bTx.Outs, exportedOuts}, + v.Codec, + ) +} diff --git a/vms/avm/txs/executor/syntactic_verifier_test.go b/vms/avm/txs/executor/syntactic_verifier_test.go index b473b4515e9..4fc6b10968e 100644 --- a/vms/avm/txs/executor/syntactic_verifier_test.go +++ b/vms/avm/txs/executor/syntactic_verifier_test.go @@ -4,6 +4,7 @@ package executor import ( + "math" "strings" "testing" @@ -21,6 +22,8 @@ import ( "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/components/verify" "github.com/ava-labs/avalanchego/vms/secp256k1fx" + + safemath "github.com/ava-labs/avalanchego/utils/math" ) var ( @@ -160,6 +163,177 @@ func TestSyntacticVerifierBaseTx(t *testing.T) { }, err: avax.ErrMemoTooLarge, }, + { + name: "invalid output", + txFunc: func() *txs.Tx { + output := output + output.Out = &secp256k1fx.TransferOutput{ + Amt: 0, + OutputOwners: outputOwners, + } + + baseTx := baseTx + baseTx.Outs = []*avax.TransferableOutput{ + &output, + } + return &txs.Tx{ + Unsigned: &txs.BaseTx{BaseTx: baseTx}, + Creds: creds, + } + }, + err: secp256k1fx.ErrNoValueOutput, + }, + { + name: "unsorted outputs", + txFunc: func() *txs.Tx { + output0 := output + output0.Out = &secp256k1fx.TransferOutput{ + Amt: 1, + OutputOwners: outputOwners, + } + + output1 := output + output1.Out = &secp256k1fx.TransferOutput{ + Amt: 2, + OutputOwners: outputOwners, + } + + outputs := []*avax.TransferableOutput{ + &output0, + &output1, + } + avax.SortTransferableOutputs(outputs, codec) + outputs[0], outputs[1] = outputs[1], outputs[0] + + baseTx := baseTx + baseTx.Outs = outputs + return &txs.Tx{ + Unsigned: &txs.BaseTx{BaseTx: baseTx}, + Creds: creds, + } + }, + err: avax.ErrOutputsNotSorted, + }, + { + name: "invalid input", + txFunc: func() *txs.Tx { + input := input + input.In = &secp256k1fx.TransferInput{ + Amt: 0, + Input: inputSigners, + } + + baseTx := baseTx + baseTx.Ins = []*avax.TransferableInput{ + &input, + } + return &txs.Tx{ + Unsigned: &txs.BaseTx{BaseTx: baseTx}, + Creds: creds, + } + }, + err: secp256k1fx.ErrNoValueInput, + }, + { + name: "duplicate inputs", + txFunc: func() *txs.Tx { + baseTx := baseTx + baseTx.Ins = []*avax.TransferableInput{ + &input, + &input, + } + return &txs.Tx{ + Unsigned: &txs.BaseTx{BaseTx: baseTx}, + Creds: []*fxs.FxCredential{ + &cred, + &cred, + }, + } + }, + err: avax.ErrInputsNotSortedUnique, + }, + { + name: "input overflow", + txFunc: func() *txs.Tx { + input0 := input + input0.In = &secp256k1fx.TransferInput{ + Amt: 1, + Input: inputSigners, + } + + input1 := input + input1.UTXOID.OutputIndex++ + input1.In = &secp256k1fx.TransferInput{ + Amt: math.MaxUint64, + Input: inputSigners, + } + + baseTx := baseTx + baseTx.Ins = []*avax.TransferableInput{ + &input0, + &input1, + } + avax.SortTransferableInputsWithSigners(baseTx.Ins, make([][]*secp256k1.PrivateKey, 2)) + return &txs.Tx{ + Unsigned: &txs.BaseTx{BaseTx: baseTx}, + Creds: []*fxs.FxCredential{ + &cred, + &cred, + }, + } + }, + err: safemath.ErrOverflow, + }, + { + name: "output overflow", + txFunc: func() *txs.Tx { + output0 := output + output0.Out = &secp256k1fx.TransferOutput{ + Amt: 1, + OutputOwners: outputOwners, + } + + output1 := output + output1.Out = &secp256k1fx.TransferOutput{ + Amt: math.MaxUint64, + OutputOwners: outputOwners, + } + + outputs := []*avax.TransferableOutput{ + &output0, + &output1, + } + avax.SortTransferableOutputs(outputs, codec) + + baseTx := baseTx + baseTx.Outs = outputs + return &txs.Tx{ + Unsigned: &txs.BaseTx{BaseTx: baseTx}, + Creds: creds, + } + }, + err: safemath.ErrOverflow, + }, + { + name: "insufficient funds", + txFunc: func() *txs.Tx { + input := input + input.In = &secp256k1fx.TransferInput{ + Amt: 1, + Input: inputSigners, + } + + baseTx := baseTx + baseTx.Ins = []*avax.TransferableInput{ + &input, + } + return &txs.Tx{ + Unsigned: &txs.BaseTx{BaseTx: baseTx}, + Creds: creds, + } + }, + err: avax.ErrInsufficientFunds, + }, { name: "invalid credential", txFunc: func() *txs.Tx { @@ -181,6 +355,46 @@ func TestSyntacticVerifierBaseTx(t *testing.T) { }, err: errWrongNumberOfCredentials, }, + { + name: "barely sufficient funds", + txFunc: func() *txs.Tx { + input := input + input.In = &secp256k1fx.TransferInput{ + Amt: fxOutput.Amt + feeConfig.TxFee, + Input: inputSigners, + } + + baseTx := baseTx + baseTx.Ins = []*avax.TransferableInput{ + &input, + } + return &txs.Tx{ + Unsigned: &txs.BaseTx{BaseTx: baseTx}, + Creds: creds, + } + }, + err: nil, + }, + { + name: "barely insufficient funds", + txFunc: func() *txs.Tx { + input := input + input.In = &secp256k1fx.TransferInput{ + Amt: fxOutput.Amt + feeConfig.TxFee - 1, + Input: inputSigners, + } + + baseTx := baseTx + baseTx.Ins = []*avax.TransferableInput{ + &input, + } + return &txs.Tx{ + Unsigned: &txs.BaseTx{BaseTx: baseTx}, + Creds: creds, + } + }, + err: avax.ErrInsufficientFunds, + }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { @@ -444,6 +658,177 @@ func TestSyntacticVerifierCreateAssetTx(t *testing.T) { }, err: avax.ErrMemoTooLarge, }, + { + name: "invalid output", + txFunc: func() *txs.Tx { + output := output + output.Out = &secp256k1fx.TransferOutput{ + Amt: 0, + OutputOwners: outputOwners, + } + + tx := tx + tx.Outs = []*avax.TransferableOutput{ + &output, + } + return &txs.Tx{ + Unsigned: &tx, + Creds: creds, + } + }, + err: secp256k1fx.ErrNoValueOutput, + }, + { + name: "unsorted outputs", + txFunc: func() *txs.Tx { + output0 := output + output0.Out = &secp256k1fx.TransferOutput{ + Amt: 1, + OutputOwners: outputOwners, + } + + output1 := output + output1.Out = &secp256k1fx.TransferOutput{ + Amt: 2, + OutputOwners: outputOwners, + } + + outputs := []*avax.TransferableOutput{ + &output0, + &output1, + } + avax.SortTransferableOutputs(outputs, codec) + outputs[0], outputs[1] = outputs[1], outputs[0] + + tx := tx + tx.Outs = outputs + return &txs.Tx{ + Unsigned: &tx, + Creds: creds, + } + }, + err: avax.ErrOutputsNotSorted, + }, + { + name: "invalid input", + txFunc: func() *txs.Tx { + input := input + input.In = &secp256k1fx.TransferInput{ + Amt: 0, + Input: inputSigners, + } + + tx := tx + tx.Ins = []*avax.TransferableInput{ + &input, + } + return &txs.Tx{ + Unsigned: &tx, + Creds: creds, + } + }, + err: secp256k1fx.ErrNoValueInput, + }, + { + name: "duplicate inputs", + txFunc: func() *txs.Tx { + tx := tx + tx.Ins = []*avax.TransferableInput{ + &input, + &input, + } + return &txs.Tx{ + Unsigned: &tx, + Creds: []*fxs.FxCredential{ + &cred, + &cred, + }, + } + }, + err: avax.ErrInputsNotSortedUnique, + }, + { + name: "input overflow", + txFunc: func() *txs.Tx { + input0 := input + input0.In = &secp256k1fx.TransferInput{ + Amt: 1, + Input: inputSigners, + } + + input1 := input + input1.UTXOID.OutputIndex++ + input1.In = &secp256k1fx.TransferInput{ + Amt: math.MaxUint64, + Input: inputSigners, + } + + tx := tx + tx.Ins = []*avax.TransferableInput{ + &input0, + &input1, + } + avax.SortTransferableInputsWithSigners(baseTx.Ins, make([][]*secp256k1.PrivateKey, 2)) + return &txs.Tx{ + Unsigned: &tx, + Creds: []*fxs.FxCredential{ + &cred, + &cred, + }, + } + }, + err: safemath.ErrOverflow, + }, + { + name: "output overflow", + txFunc: func() *txs.Tx { + output0 := output + output0.Out = &secp256k1fx.TransferOutput{ + Amt: 1, + OutputOwners: outputOwners, + } + + output1 := output + output1.Out = &secp256k1fx.TransferOutput{ + Amt: math.MaxUint64, + OutputOwners: outputOwners, + } + + outputs := []*avax.TransferableOutput{ + &output0, + &output1, + } + avax.SortTransferableOutputs(outputs, codec) + + tx := tx + tx.Outs = outputs + return &txs.Tx{ + Unsigned: &tx, + Creds: creds, + } + }, + err: safemath.ErrOverflow, + }, + { + name: "insufficient funds", + txFunc: func() *txs.Tx { + input := input + input.In = &secp256k1fx.TransferInput{ + Amt: 1, + Input: inputSigners, + } + + tx := tx + tx.Ins = []*avax.TransferableInput{ + &input, + } + return &txs.Tx{ + Unsigned: &tx, + Creds: creds, + } + }, + err: avax.ErrInsufficientFunds, + }, { name: "invalid nil state", txFunc: func() *txs.Tx { @@ -579,6 +964,46 @@ func TestSyntacticVerifierCreateAssetTx(t *testing.T) { }, err: errWrongNumberOfCredentials, }, + { + name: "barely sufficient funds", + txFunc: func() *txs.Tx { + input := input + input.In = &secp256k1fx.TransferInput{ + Amt: fxOutput.Amt + feeConfig.CreateAssetTxFee, + Input: inputSigners, + } + + tx := tx + tx.Ins = []*avax.TransferableInput{ + &input, + } + return &txs.Tx{ + Unsigned: &tx, + Creds: creds, + } + }, + err: nil, + }, + { + name: "barely insufficient funds", + txFunc: func() *txs.Tx { + input := input + input.In = &secp256k1fx.TransferInput{ + Amt: fxOutput.Amt + feeConfig.CreateAssetTxFee - 1, + Input: inputSigners, + } + + tx := tx + tx.Ins = []*avax.TransferableInput{ + &input, + } + return &txs.Tx{ + Unsigned: &tx, + Creds: creds, + } + }, + err: avax.ErrInsufficientFunds, + }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { @@ -755,55 +1180,219 @@ func TestSyntacticVerifierOperationTx(t *testing.T) { err: avax.ErrMemoTooLarge, }, { - name: "invalid nil op", + name: "invalid output", txFunc: func() *txs.Tx { + output := output + output.Out = &secp256k1fx.TransferOutput{ + Amt: 0, + OutputOwners: outputOwners, + } + tx := tx - tx.Ops = []*txs.Operation{ - nil, + tx.Outs = []*avax.TransferableOutput{ + &output, } return &txs.Tx{ Unsigned: &tx, Creds: creds, } }, - err: txs.ErrNilOperation, + err: secp256k1fx.ErrNoValueOutput, }, { - name: "invalid nil fx op", + name: "unsorted outputs", txFunc: func() *txs.Tx { - op := op - op.Op = nil + output0 := output + output0.Out = &secp256k1fx.TransferOutput{ + Amt: 1, + OutputOwners: outputOwners, + } - tx := tx - tx.Ops = []*txs.Operation{ - &op, + output1 := output + output1.Out = &secp256k1fx.TransferOutput{ + Amt: 2, + OutputOwners: outputOwners, + } + + outputs := []*avax.TransferableOutput{ + &output0, + &output1, } + avax.SortTransferableOutputs(outputs, codec) + outputs[0], outputs[1] = outputs[1], outputs[0] + + tx := tx + tx.Outs = outputs return &txs.Tx{ Unsigned: &tx, Creds: creds, } }, - err: txs.ErrNilFxOperation, + err: avax.ErrOutputsNotSorted, }, { - name: "invalid duplicated op UTXOs", + name: "invalid input", txFunc: func() *txs.Tx { - op := op - op.UTXOIDs = []*avax.UTXOID{ - &opUTXOID, - &opUTXOID, + input := input + input.In = &secp256k1fx.TransferInput{ + Amt: 0, + Input: inputSigners, } tx := tx - tx.Ops = []*txs.Operation{ - &op, + tx.Ins = []*avax.TransferableInput{ + &input, } return &txs.Tx{ Unsigned: &tx, Creds: creds, } }, - err: txs.ErrNotSortedAndUniqueUTXOIDs, + err: secp256k1fx.ErrNoValueInput, + }, + { + name: "duplicate inputs", + txFunc: func() *txs.Tx { + tx := tx + tx.Ins = []*avax.TransferableInput{ + &input, + &input, + } + return &txs.Tx{ + Unsigned: &tx, + Creds: []*fxs.FxCredential{ + &cred, + &cred, + }, + } + }, + err: avax.ErrInputsNotSortedUnique, + }, + { + name: "input overflow", + txFunc: func() *txs.Tx { + input0 := input + input0.In = &secp256k1fx.TransferInput{ + Amt: 1, + Input: inputSigners, + } + + input1 := input + input1.UTXOID.OutputIndex++ + input1.In = &secp256k1fx.TransferInput{ + Amt: math.MaxUint64, + Input: inputSigners, + } + + tx := tx + tx.Ins = []*avax.TransferableInput{ + &input0, + &input1, + } + avax.SortTransferableInputsWithSigners(tx.Ins, make([][]*secp256k1.PrivateKey, 2)) + return &txs.Tx{ + Unsigned: &tx, + Creds: []*fxs.FxCredential{ + &cred, + &cred, + }, + } + }, + err: safemath.ErrOverflow, + }, + { + name: "output overflow", + txFunc: func() *txs.Tx { + output := output + output.Out = &secp256k1fx.TransferOutput{ + Amt: math.MaxUint64, + OutputOwners: outputOwners, + } + + outputs := []*avax.TransferableOutput{ + &output, + } + avax.SortTransferableOutputs(outputs, codec) + + tx := tx + tx.Outs = outputs + return &txs.Tx{ + Unsigned: &tx, + Creds: creds, + } + }, + err: safemath.ErrOverflow, + }, + { + name: "insufficient funds", + txFunc: func() *txs.Tx { + input := input + input.In = &secp256k1fx.TransferInput{ + Amt: 1, + Input: inputSigners, + } + + tx := tx + tx.Ins = []*avax.TransferableInput{ + &input, + } + return &txs.Tx{ + Unsigned: &tx, + Creds: creds, + } + }, + err: avax.ErrInsufficientFunds, + }, + { + name: "invalid nil op", + txFunc: func() *txs.Tx { + tx := tx + tx.Ops = []*txs.Operation{ + nil, + } + return &txs.Tx{ + Unsigned: &tx, + Creds: creds, + } + }, + err: txs.ErrNilOperation, + }, + { + name: "invalid nil fx op", + txFunc: func() *txs.Tx { + op := op + op.Op = nil + + tx := tx + tx.Ops = []*txs.Operation{ + &op, + } + return &txs.Tx{ + Unsigned: &tx, + Creds: creds, + } + }, + err: txs.ErrNilFxOperation, + }, + { + name: "invalid duplicated op UTXOs", + txFunc: func() *txs.Tx { + op := op + op.UTXOIDs = []*avax.UTXOID{ + &opUTXOID, + &opUTXOID, + } + + tx := tx + tx.Ops = []*txs.Operation{ + &op, + } + return &txs.Tx{ + Unsigned: &tx, + Creds: creds, + } + }, + err: txs.ErrNotSortedAndUniqueUTXOIDs, }, { name: "invalid duplicated UTXOs across ops", @@ -864,6 +1453,46 @@ func TestSyntacticVerifierOperationTx(t *testing.T) { }, err: errWrongNumberOfCredentials, }, + { + name: "barely sufficient funds", + txFunc: func() *txs.Tx { + input := input + input.In = &secp256k1fx.TransferInput{ + Amt: fxOutput.Amt + feeConfig.TxFee, + Input: inputSigners, + } + + tx := tx + tx.Ins = []*avax.TransferableInput{ + &input, + } + return &txs.Tx{ + Unsigned: &tx, + Creds: creds, + } + }, + err: nil, + }, + { + name: "barely insufficient funds", + txFunc: func() *txs.Tx { + input := input + input.In = &secp256k1fx.TransferInput{ + Amt: fxOutput.Amt + feeConfig.TxFee - 1, + Input: inputSigners, + } + + tx := tx + tx.Ins = []*avax.TransferableInput{ + &input, + } + return &txs.Tx{ + Unsigned: &tx, + Creds: creds, + } + }, + err: avax.ErrInsufficientFunds, + }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { @@ -1020,6 +1649,189 @@ func TestSyntacticVerifierImportTx(t *testing.T) { }, err: avax.ErrMemoTooLarge, }, + { + name: "invalid output", + txFunc: func() *txs.Tx { + output := output + output.Out = &secp256k1fx.TransferOutput{ + Amt: 0, + OutputOwners: outputOwners, + } + + tx := tx + tx.Outs = []*avax.TransferableOutput{ + &output, + } + return &txs.Tx{ + Unsigned: &tx, + Creds: creds, + } + }, + err: secp256k1fx.ErrNoValueOutput, + }, + { + name: "unsorted outputs", + txFunc: func() *txs.Tx { + output0 := output + output0.Out = &secp256k1fx.TransferOutput{ + Amt: 1, + OutputOwners: outputOwners, + } + + output1 := output + output1.Out = &secp256k1fx.TransferOutput{ + Amt: 2, + OutputOwners: outputOwners, + } + + outputs := []*avax.TransferableOutput{ + &output0, + &output1, + } + avax.SortTransferableOutputs(outputs, codec) + outputs[0], outputs[1] = outputs[1], outputs[0] + + tx := tx + tx.Outs = outputs + return &txs.Tx{ + Unsigned: &tx, + Creds: creds, + } + }, + err: avax.ErrOutputsNotSorted, + }, + { + name: "invalid input", + txFunc: func() *txs.Tx { + input := input + input.In = &secp256k1fx.TransferInput{ + Amt: 0, + Input: inputSigners, + } + + tx := tx + tx.Ins = []*avax.TransferableInput{ + &input, + } + return &txs.Tx{ + Unsigned: &tx, + Creds: creds, + } + }, + err: secp256k1fx.ErrNoValueInput, + }, + { + name: "duplicate inputs", + txFunc: func() *txs.Tx { + tx := tx + tx.Ins = []*avax.TransferableInput{ + &input, + &input, + } + return &txs.Tx{ + Unsigned: &tx, + Creds: []*fxs.FxCredential{ + &cred, + &cred, + &cred, + }, + } + }, + err: avax.ErrInputsNotSortedUnique, + }, + { + name: "duplicate imported inputs", + txFunc: func() *txs.Tx { + tx := tx + tx.ImportedIns = []*avax.TransferableInput{ + &input, + &input, + } + return &txs.Tx{ + Unsigned: &tx, + Creds: []*fxs.FxCredential{ + &cred, + &cred, + }, + } + }, + err: avax.ErrInputsNotSortedUnique, + }, + { + name: "input overflow", + txFunc: func() *txs.Tx { + input0 := input + input0.In = &secp256k1fx.TransferInput{ + Amt: 1, + Input: inputSigners, + } + + input1 := input + input1.UTXOID.OutputIndex++ + input1.In = &secp256k1fx.TransferInput{ + Amt: math.MaxUint64, + Input: inputSigners, + } + + tx := tx + tx.Ins = []*avax.TransferableInput{ + &input0, + &input1, + } + avax.SortTransferableInputsWithSigners(tx.Ins, make([][]*secp256k1.PrivateKey, 2)) + return &txs.Tx{ + Unsigned: &tx, + Creds: []*fxs.FxCredential{ + &cred, + &cred, + }, + } + }, + err: safemath.ErrOverflow, + }, + { + name: "output overflow", + txFunc: func() *txs.Tx { + output := output + output.Out = &secp256k1fx.TransferOutput{ + Amt: math.MaxUint64, + OutputOwners: outputOwners, + } + + outputs := []*avax.TransferableOutput{ + &output, + } + avax.SortTransferableOutputs(outputs, codec) + + tx := tx + tx.Outs = outputs + return &txs.Tx{ + Unsigned: &tx, + Creds: creds, + } + }, + err: safemath.ErrOverflow, + }, + { + name: "insufficient funds", + txFunc: func() *txs.Tx { + input := input + input.In = &secp256k1fx.TransferInput{ + Amt: 1, + Input: inputSigners, + } + + tx := tx + tx.ImportedIns = []*avax.TransferableInput{ + &input, + } + return &txs.Tx{ + Unsigned: &tx, + Creds: creds, + } + }, + err: avax.ErrInsufficientFunds, + }, { name: "invalid credential", txFunc: func() *txs.Tx { @@ -1041,6 +1853,46 @@ func TestSyntacticVerifierImportTx(t *testing.T) { }, err: errWrongNumberOfCredentials, }, + { + name: "barely sufficient funds", + txFunc: func() *txs.Tx { + input := input + input.In = &secp256k1fx.TransferInput{ + Amt: fxOutput.Amt + feeConfig.TxFee, + Input: inputSigners, + } + + tx := tx + tx.ImportedIns = []*avax.TransferableInput{ + &input, + } + return &txs.Tx{ + Unsigned: &tx, + Creds: creds, + } + }, + err: nil, + }, + { + name: "barely insufficient funds", + txFunc: func() *txs.Tx { + input := input + input.In = &secp256k1fx.TransferInput{ + Amt: fxOutput.Amt + feeConfig.TxFee - 1, + Input: inputSigners, + } + + tx := tx + tx.ImportedIns = []*avax.TransferableInput{ + &input, + } + return &txs.Tx{ + Unsigned: &tx, + Creds: creds, + } + }, + err: avax.ErrInsufficientFunds, + }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { @@ -1197,6 +2049,201 @@ func TestSyntacticVerifierExportTx(t *testing.T) { }, err: avax.ErrMemoTooLarge, }, + { + name: "invalid output", + txFunc: func() *txs.Tx { + output := output + output.Out = &secp256k1fx.TransferOutput{ + Amt: 0, + OutputOwners: outputOwners, + } + + tx := tx + tx.Outs = []*avax.TransferableOutput{ + &output, + } + return &txs.Tx{ + Unsigned: &tx, + Creds: creds, + } + }, + err: secp256k1fx.ErrNoValueOutput, + }, + { + name: "unsorted outputs", + txFunc: func() *txs.Tx { + output0 := output + output0.Out = &secp256k1fx.TransferOutput{ + Amt: 1, + OutputOwners: outputOwners, + } + + output1 := output + output1.Out = &secp256k1fx.TransferOutput{ + Amt: 2, + OutputOwners: outputOwners, + } + + outputs := []*avax.TransferableOutput{ + &output0, + &output1, + } + avax.SortTransferableOutputs(outputs, codec) + outputs[0], outputs[1] = outputs[1], outputs[0] + + tx := tx + tx.Outs = outputs + return &txs.Tx{ + Unsigned: &tx, + Creds: creds, + } + }, + err: avax.ErrOutputsNotSorted, + }, + { + name: "unsorted exported outputs", + txFunc: func() *txs.Tx { + output0 := output + output0.Out = &secp256k1fx.TransferOutput{ + Amt: 1, + OutputOwners: outputOwners, + } + + output1 := output + output1.Out = &secp256k1fx.TransferOutput{ + Amt: 2, + OutputOwners: outputOwners, + } + + outputs := []*avax.TransferableOutput{ + &output0, + &output1, + } + avax.SortTransferableOutputs(outputs, codec) + outputs[0], outputs[1] = outputs[1], outputs[0] + + tx := tx + tx.ExportedOuts = outputs + return &txs.Tx{ + Unsigned: &tx, + Creds: creds, + } + }, + err: avax.ErrOutputsNotSorted, + }, + { + name: "invalid input", + txFunc: func() *txs.Tx { + input := input + input.In = &secp256k1fx.TransferInput{ + Amt: 0, + Input: inputSigners, + } + + tx := tx + tx.Ins = []*avax.TransferableInput{ + &input, + } + return &txs.Tx{ + Unsigned: &tx, + Creds: creds, + } + }, + err: secp256k1fx.ErrNoValueInput, + }, + { + name: "duplicate inputs", + txFunc: func() *txs.Tx { + tx := tx + tx.Ins = []*avax.TransferableInput{ + &input, + &input, + } + return &txs.Tx{ + Unsigned: &tx, + Creds: []*fxs.FxCredential{ + &cred, + &cred, + }, + } + }, + err: avax.ErrInputsNotSortedUnique, + }, + { + name: "input overflow", + txFunc: func() *txs.Tx { + input0 := input + input0.In = &secp256k1fx.TransferInput{ + Amt: 1, + Input: inputSigners, + } + + input1 := input + input1.UTXOID.OutputIndex++ + input1.In = &secp256k1fx.TransferInput{ + Amt: math.MaxUint64, + Input: inputSigners, + } + + tx := tx + tx.Ins = []*avax.TransferableInput{ + &input0, + &input1, + } + avax.SortTransferableInputsWithSigners(tx.Ins, make([][]*secp256k1.PrivateKey, 2)) + return &txs.Tx{ + Unsigned: &tx, + Creds: []*fxs.FxCredential{ + &cred, + &cred, + }, + } + }, + err: safemath.ErrOverflow, + }, + { + name: "output overflow", + txFunc: func() *txs.Tx { + output := output + output.Out = &secp256k1fx.TransferOutput{ + Amt: math.MaxUint64, + OutputOwners: outputOwners, + } + + outputs := []*avax.TransferableOutput{ + &output, + } + avax.SortTransferableOutputs(outputs, codec) + + tx := tx + tx.Outs = outputs + return &txs.Tx{ + Unsigned: &tx, + Creds: creds, + } + }, + err: safemath.ErrOverflow, + }, + { + name: "insufficient funds", + txFunc: func() *txs.Tx { + input := input + input.In = &secp256k1fx.TransferInput{ + Amt: 1, + Input: inputSigners, + } + + tx := tx + tx.Ins = []*avax.TransferableInput{ + &input, + } + return &txs.Tx{ + Unsigned: &tx, + Creds: creds, + } + }, + err: avax.ErrInsufficientFunds, + }, { name: "invalid credential", txFunc: func() *txs.Tx { @@ -1218,6 +2265,46 @@ func TestSyntacticVerifierExportTx(t *testing.T) { }, err: errWrongNumberOfCredentials, }, + { + name: "barely sufficient funds", + txFunc: func() *txs.Tx { + input := input + input.In = &secp256k1fx.TransferInput{ + Amt: fxOutput.Amt + feeConfig.TxFee, + Input: inputSigners, + } + + tx := tx + tx.Ins = []*avax.TransferableInput{ + &input, + } + return &txs.Tx{ + Unsigned: &tx, + Creds: creds, + } + }, + err: nil, + }, + { + name: "barely insufficient funds", + txFunc: func() *txs.Tx { + input := input + input.In = &secp256k1fx.TransferInput{ + Amt: fxOutput.Amt + feeConfig.TxFee - 1, + Input: inputSigners, + } + + tx := tx + tx.Ins = []*avax.TransferableInput{ + &input, + } + return &txs.Tx{ + Unsigned: &tx, + Creds: creds, + } + }, + err: avax.ErrInsufficientFunds, + }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) {