diff --git a/api/info/service.go b/api/info/service.go index e315afd259e..9bdf245569a 100644 --- a/api/info/service.go +++ b/api/info/service.go @@ -25,7 +25,10 @@ import ( "github.com/ava-labs/avalanchego/utils/set" "github.com/ava-labs/avalanchego/version" "github.com/ava-labs/avalanchego/vms" + "github.com/ava-labs/avalanchego/vms/nftfx" "github.com/ava-labs/avalanchego/vms/platformvm/signer" + "github.com/ava-labs/avalanchego/vms/propertyfx" + "github.com/ava-labs/avalanchego/vms/secp256k1fx" ) var errNoChainProvided = errors.New("argument 'chain' not given") @@ -416,6 +419,7 @@ func (i *Info) GetTxFee(_ *http.Request, _ *struct{}, reply *GetTxFeeResponse) e // GetVMsReply contains the response metadata for GetVMs type GetVMsReply struct { VMs map[ids.ID][]string `json:"vms"` + Fxs map[ids.ID]string `json:"fxs"` } // GetVMs lists the virtual machines installed on the node @@ -432,5 +436,10 @@ func (i *Info) GetVMs(_ *http.Request, _ *struct{}, reply *GetVMsReply) error { } reply.VMs, err = ids.GetRelevantAliases(i.VMManager, vmIDs) + reply.Fxs = map[ids.ID]string{ + secp256k1fx.ID: secp256k1fx.Name, + nftfx.ID: nftfx.Name, + propertyfx.ID: propertyfx.Name, + } return err } diff --git a/chains/manager.go b/chains/manager.go index 84762d3eb3f..e7c49afcd02 100644 --- a/chains/manager.go +++ b/chains/manager.go @@ -55,9 +55,13 @@ import ( "github.com/ava-labs/avalanchego/utils/set" "github.com/ava-labs/avalanchego/version" "github.com/ava-labs/avalanchego/vms" + "github.com/ava-labs/avalanchego/vms/fx" "github.com/ava-labs/avalanchego/vms/metervm" + "github.com/ava-labs/avalanchego/vms/nftfx" "github.com/ava-labs/avalanchego/vms/platformvm/warp" + "github.com/ava-labs/avalanchego/vms/propertyfx" "github.com/ava-labs/avalanchego/vms/proposervm" + "github.com/ava-labs/avalanchego/vms/secp256k1fx" "github.com/ava-labs/avalanchego/vms/tracedvm" timetracker "github.com/ava-labs/avalanchego/snow/networking/tracker" @@ -96,6 +100,12 @@ var ( errNoPrimaryNetworkConfig = errors.New("no subnet config for primary network found") errPartialSyncAsAValidator = errors.New("partial sync should not be configured for a validator") + fxs = map[ids.ID]fx.Factory{ + secp256k1fx.ID: &secp256k1fx.Factory{}, + nftfx.ID: &nftfx.Factory{}, + propertyfx.ID: &propertyfx.Factory{}, + } + _ Manager = (*manager)(nil) ) @@ -511,23 +521,16 @@ func (m *manager) buildChain(chainParams ChainParameters, sb subnets.Subnet) (*c } // TODO: Shutdown VM if an error occurs - fxs := make([]*common.Fx, len(chainParams.FxIDs)) + chainFxs := make([]*common.Fx, len(chainParams.FxIDs)) for i, fxID := range chainParams.FxIDs { - // Get a factory for the fx we want to use on our chain - fxFactory, err := m.VMManager.GetFactory(fxID) - if err != nil { - return nil, fmt.Errorf("error while getting fxFactory: %w", err) - } - - fx, err := fxFactory.New(chainLog) - if err != nil { - return nil, fmt.Errorf("error while creating fx: %w", err) + fxFactory, ok := fxs[fxID] + if !ok { + return nil, fmt.Errorf("fx %s not found", fxID) } - // Create the fx - fxs[i] = &common.Fx{ + chainFxs[i] = &common.Fx{ ID: fxID, - Fx: fx, + Fx: fxFactory.New(), } } @@ -539,7 +542,7 @@ func (m *manager) buildChain(chainParams ChainParameters, sb subnets.Subnet) (*c chainParams.GenesisData, m.Validators, vm, - fxs, + chainFxs, sb, ) if err != nil { @@ -557,7 +560,7 @@ func (m *manager) buildChain(chainParams ChainParameters, sb subnets.Subnet) (*c m.Validators, beacons, vm, - fxs, + chainFxs, sb, ) if err != nil { diff --git a/node/node.go b/node/node.go index 1aeaddcf624..7842259c8a9 100644 --- a/node/node.go +++ b/node/node.go @@ -78,15 +78,12 @@ 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/nftfx" "github.com/ava-labs/avalanchego/vms/platformvm" "github.com/ava-labs/avalanchego/vms/platformvm/block" "github.com/ava-labs/avalanchego/vms/platformvm/signer" "github.com/ava-labs/avalanchego/vms/platformvm/txs" - "github.com/ava-labs/avalanchego/vms/propertyfx" "github.com/ava-labs/avalanchego/vms/registry" "github.com/ava-labs/avalanchego/vms/rpcchainvm/runtime" - "github.com/ava-labs/avalanchego/vms/secp256k1fx" ipcsapi "github.com/ava-labs/avalanchego/api/ipcs" avmconfig "github.com/ava-labs/avalanchego/vms/avm/config" @@ -1226,9 +1223,6 @@ func (n *Node) initVMs() error { }, }), n.VMManager.RegisterFactory(context.TODO(), constants.EVMID, &coreth.Factory{}), - n.VMManager.RegisterFactory(context.TODO(), secp256k1fx.ID, &secp256k1fx.Factory{}), - n.VMManager.RegisterFactory(context.TODO(), nftfx.ID, &nftfx.Factory{}), - n.VMManager.RegisterFactory(context.TODO(), propertyfx.ID, &propertyfx.Factory{}), ) if err != nil { return err diff --git a/vms/components/avax/base_tx.go b/vms/components/avax/base_tx.go index 10561ae0ad5..5afed5f3a16 100644 --- a/vms/components/avax/base_tx.go +++ b/vms/components/avax/base_tx.go @@ -65,3 +65,21 @@ func (t *BaseTx) Verify(ctx *snow.Context) error { return nil } } + +func VerifyMemoFieldLength(memo types.JSONByteSlice, isDurangoActive bool) error { + if !isDurangoActive { + // SyntacticVerify validates this field pre-Durango + return nil + } + + if len(memo) != 0 { + return fmt.Errorf( + "%w: %d > %d", + ErrMemoTooLarge, + len(memo), + 0, + ) + } + + return nil +} diff --git a/vms/fx/factory.go b/vms/fx/factory.go new file mode 100644 index 00000000000..a2c957a5bf6 --- /dev/null +++ b/vms/fx/factory.go @@ -0,0 +1,9 @@ +// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package fx + +// Factory returns an instance of a feature extension +type Factory interface { + New() any +} diff --git a/vms/nftfx/factory.go b/vms/nftfx/factory.go index a111bc0ed7e..c8be03661bb 100644 --- a/vms/nftfx/factory.go +++ b/vms/nftfx/factory.go @@ -5,12 +5,13 @@ package nftfx import ( "github.com/ava-labs/avalanchego/ids" - "github.com/ava-labs/avalanchego/utils/logging" - "github.com/ava-labs/avalanchego/vms" + "github.com/ava-labs/avalanchego/vms/fx" ) +const Name = "nftfx" + var ( - _ vms.Factory = (*Factory)(nil) + _ fx.Factory = (*Factory)(nil) // ID that this Fx uses when labeled ID = ids.ID{'n', 'f', 't', 'f', 'x'} @@ -18,6 +19,6 @@ var ( type Factory struct{} -func (*Factory) New(logging.Logger) (interface{}, error) { - return &Fx{}, nil +func (*Factory) New() any { + return &Fx{} } diff --git a/vms/nftfx/factory_test.go b/vms/nftfx/factory_test.go index 6b4fba9861a..6b5ecafbeec 100644 --- a/vms/nftfx/factory_test.go +++ b/vms/nftfx/factory_test.go @@ -7,15 +7,11 @@ import ( "testing" "github.com/stretchr/testify/require" - - "github.com/ava-labs/avalanchego/utils/logging" ) func TestFactory(t *testing.T) { require := require.New(t) factory := Factory{} - fx, err := factory.New(logging.NoLog{}) - require.NoError(err) - require.NotNil(fx) + require.Equal(&Fx{}, factory.New()) } diff --git a/vms/platformvm/txs/executor/staker_tx_verification.go b/vms/platformvm/txs/executor/staker_tx_verification.go index a17bbbffc14..aafeb6f1697 100644 --- a/vms/platformvm/txs/executor/staker_tx_verification.go +++ b/vms/platformvm/txs/executor/staker_tx_verification.go @@ -103,11 +103,16 @@ func verifyAddValidatorTx( var ( currentTimestamp = chainState.GetTimestamp() isDurangoActive = backend.Config.IsDurangoActivated(currentTimestamp) - startTime = currentTimestamp ) + if err := avax.VerifyMemoFieldLength(tx.Memo, isDurangoActive); err != nil { + return nil, err + } + + startTime := currentTimestamp if !isDurangoActive { startTime = tx.StartTime() } + duration := tx.EndTime().Sub(startTime) switch { case tx.Validator.Wght < backend.Config.MinValidatorStake: @@ -194,8 +199,12 @@ func verifyAddSubnetValidatorTx( var ( currentTimestamp = chainState.GetTimestamp() isDurangoActive = backend.Config.IsDurangoActivated(currentTimestamp) - startTime = currentTimestamp ) + if err := avax.VerifyMemoFieldLength(tx.Memo, isDurangoActive); err != nil { + return err + } + + startTime := currentTimestamp if !isDurangoActive { startTime = tx.StartTime() } @@ -283,6 +292,14 @@ func verifyRemoveSubnetValidatorTx( return nil, false, err } + var ( + currentTimestamp = chainState.GetTimestamp() + isDurangoActive = backend.Config.IsDurangoActivated(currentTimestamp) + ) + if err := avax.VerifyMemoFieldLength(tx.Memo, isDurangoActive); err != nil { + return nil, false, err + } + isCurrentValidator := true vdr, err := chainState.GetCurrentValidator(tx.Subnet, tx.NodeID) if err == database.ErrNotFound { @@ -351,8 +368,14 @@ func verifyAddDelegatorTx( var ( currentTimestamp = chainState.GetTimestamp() isDurangoActive = backend.Config.IsDurangoActivated(currentTimestamp) - endTime = tx.EndTime() - startTime = currentTimestamp + ) + if err := avax.VerifyMemoFieldLength(tx.Memo, isDurangoActive); err != nil { + return nil, err + } + + var ( + endTime = tx.EndTime() + startTime = currentTimestamp ) if !isDurangoActive { startTime = tx.StartTime() @@ -458,15 +481,19 @@ func verifyAddPermissionlessValidatorTx( return err } - if !backend.Bootstrapped.Get() { - return nil - } - var ( currentTimestamp = chainState.GetTimestamp() isDurangoActive = backend.Config.IsDurangoActivated(currentTimestamp) - startTime = currentTimestamp ) + if err := avax.VerifyMemoFieldLength(tx.Memo, isDurangoActive); err != nil { + return err + } + + if !backend.Bootstrapped.Get() { + return nil + } + + startTime := currentTimestamp if !isDurangoActive { startTime = tx.StartTime() } @@ -578,15 +605,21 @@ func verifyAddPermissionlessDelegatorTx( return err } + var ( + currentTimestamp = chainState.GetTimestamp() + isDurangoActive = backend.Config.IsDurangoActivated(currentTimestamp) + ) + if err := avax.VerifyMemoFieldLength(tx.Memo, isDurangoActive); err != nil { + return err + } + if !backend.Bootstrapped.Get() { return nil } var ( - currentTimestamp = chainState.GetTimestamp() - isDurangoActive = backend.Config.IsDurangoActivated(currentTimestamp) - endTime = tx.EndTime() - startTime = currentTimestamp + endTime = tx.EndTime() + startTime = currentTimestamp ) if !isDurangoActive { startTime = tx.StartTime() @@ -728,6 +761,10 @@ func verifyTransferSubnetOwnershipTx( return err } + if err := avax.VerifyMemoFieldLength(tx.Memo, true /*=isDurangoActive*/); err != nil { + return err + } + if !backend.Bootstrapped.Get() { // Not bootstrapped yet -- don't need to do full verification. return nil diff --git a/vms/platformvm/txs/executor/staker_tx_verification_test.go b/vms/platformvm/txs/executor/staker_tx_verification_test.go index b59daf0da2b..1431f32e56f 100644 --- a/vms/platformvm/txs/executor/staker_tx_verification_test.go +++ b/vms/platformvm/txs/executor/staker_tx_verification_test.go @@ -139,13 +139,15 @@ func TestVerifyAddPermissionlessValidatorTx(t *testing.T) { } }, stateF: func(ctrl *gomock.Controller) state.Chain { - return nil + mockState := state.NewMockChain(ctrl) + mockState.EXPECT().GetTimestamp().Return(now) // chain time is after Durango fork activation since now.After(activeForkTime) + return mockState }, sTxF: func() *txs.Tx { return &verifiedSignedTx }, txF: func() *txs.AddPermissionlessValidatorTx { - return nil + return &txs.AddPermissionlessValidatorTx{} }, expectedErr: nil, }, diff --git a/vms/platformvm/txs/executor/standard_tx_executor.go b/vms/platformvm/txs/executor/standard_tx_executor.go index e780673e643..aa3ea9a2aaf 100644 --- a/vms/platformvm/txs/executor/standard_tx_executor.go +++ b/vms/platformvm/txs/executor/standard_tx_executor.go @@ -54,14 +54,21 @@ func (e *StandardTxExecutor) CreateChainTx(tx *txs.CreateChainTx) error { return err } + var ( + currentTimestamp = e.State.GetTimestamp() + isDurangoActive = e.Config.IsDurangoActivated(currentTimestamp) + ) + if err := avax.VerifyMemoFieldLength(tx.Memo, isDurangoActive); err != nil { + return err + } + baseTxCreds, err := verifyPoASubnetAuthorization(e.Backend, e.State, e.Tx, tx.SubnetID, tx.SubnetAuth) if err != nil { return err } // Verify the flowcheck - timestamp := e.State.GetTimestamp() - createBlockchainTxFee := e.Config.GetCreateBlockchainTxFee(timestamp) + createBlockchainTxFee := e.Config.GetCreateBlockchainTxFee(currentTimestamp) if err := e.FlowChecker.VerifySpend( tx, e.State, @@ -98,9 +105,16 @@ func (e *StandardTxExecutor) CreateSubnetTx(tx *txs.CreateSubnetTx) error { return err } + var ( + currentTimestamp = e.State.GetTimestamp() + isDurangoActive = e.Config.IsDurangoActivated(currentTimestamp) + ) + if err := avax.VerifyMemoFieldLength(tx.Memo, isDurangoActive); err != nil { + return err + } + // Verify the flowcheck - timestamp := e.State.GetTimestamp() - createSubnetTxFee := e.Config.GetCreateSubnetTxFee(timestamp) + createSubnetTxFee := e.Config.GetCreateSubnetTxFee(currentTimestamp) if err := e.FlowChecker.VerifySpend( tx, e.State, @@ -131,6 +145,14 @@ func (e *StandardTxExecutor) ImportTx(tx *txs.ImportTx) error { return err } + var ( + currentTimestamp = e.State.GetTimestamp() + isDurangoActive = e.Config.IsDurangoActivated(currentTimestamp) + ) + if err := avax.VerifyMemoFieldLength(tx.Memo, isDurangoActive); err != nil { + return err + } + e.Inputs = set.NewSet[ids.ID](len(tx.ImportedInputs)) utxoIDs := make([][]byte, len(tx.ImportedInputs)) for i, in := range tx.ImportedInputs { @@ -209,6 +231,14 @@ func (e *StandardTxExecutor) ExportTx(tx *txs.ExportTx) error { return err } + var ( + currentTimestamp = e.State.GetTimestamp() + isDurangoActive = e.Config.IsDurangoActivated(currentTimestamp) + ) + if err := avax.VerifyMemoFieldLength(tx.Memo, isDurangoActive); err != nil { + return err + } + outs := make([]*avax.TransferableOutput, len(tx.Outs)+len(tx.ExportedOutputs)) copy(outs, tx.Outs) copy(outs[len(tx.Outs):], tx.ExportedOutputs) @@ -386,6 +416,14 @@ func (e *StandardTxExecutor) TransformSubnetTx(tx *txs.TransformSubnetTx) error return err } + var ( + currentTimestamp = e.State.GetTimestamp() + isDurangoActive = e.Config.IsDurangoActivated(currentTimestamp) + ) + if err := avax.VerifyMemoFieldLength(tx.Memo, isDurangoActive); err != nil { + return err + } + // Note: math.MaxInt32 * time.Second < math.MaxInt64 - so this can never // overflow. if time.Duration(tx.MaxStakeDuration)*time.Second > e.Backend.Config.MaxStakeDuration { @@ -512,6 +550,10 @@ func (e *StandardTxExecutor) BaseTx(tx *txs.BaseTx) error { return err } + if err := avax.VerifyMemoFieldLength(tx.Memo, true /*=isDurangoActive*/); err != nil { + return err + } + // Verify the flowcheck if err := e.FlowChecker.VerifySpend( tx, diff --git a/vms/platformvm/txs/executor/standard_tx_executor_test.go b/vms/platformvm/txs/executor/standard_tx_executor_test.go index b9ad92933d3..f9c54367fac 100644 --- a/vms/platformvm/txs/executor/standard_tx_executor_test.go +++ b/vms/platformvm/txs/executor/standard_tx_executor_test.go @@ -19,18 +19,22 @@ import ( "github.com/ava-labs/avalanchego/snow" "github.com/ava-labs/avalanchego/utils" "github.com/ava-labs/avalanchego/utils/constants" + "github.com/ava-labs/avalanchego/utils/crypto/bls" "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" "github.com/ava-labs/avalanchego/utils/hashing" + "github.com/ava-labs/avalanchego/utils/units" "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/components/verify" "github.com/ava-labs/avalanchego/vms/platformvm/config" "github.com/ava-labs/avalanchego/vms/platformvm/fx" "github.com/ava-labs/avalanchego/vms/platformvm/reward" + "github.com/ava-labs/avalanchego/vms/platformvm/signer" "github.com/ava-labs/avalanchego/vms/platformvm/state" "github.com/ava-labs/avalanchego/vms/platformvm/status" "github.com/ava-labs/avalanchego/vms/platformvm/txs" "github.com/ava-labs/avalanchego/vms/platformvm/utxo" "github.com/ava-labs/avalanchego/vms/secp256k1fx" + "github.com/ava-labs/avalanchego/vms/types" ) // This tests that the math performed during TransformSubnetTx execution can @@ -351,7 +355,7 @@ func TestStandardTxExecutorAddDelegator(t *testing.T) { } } -func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { +func TestApricotStandardTxExecutorAddSubnetValidator(t *testing.T) { require := require.New(t) env := newEnvironment(t, false /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) env.ctx.Lock.Lock() @@ -778,7 +782,7 @@ func TestStandardTxExecutorAddSubnetValidator(t *testing.T) { } } -func TestStandardTxExecutorBanffAddValidator(t *testing.T) { +func TestBanffStandardTxExecutorAddValidator(t *testing.T) { require := require.New(t) env := newEnvironment(t, true /*=postBanff*/, false /*=postCortina*/, false /*=postDurango*/) env.ctx.Lock.Lock() @@ -949,49 +953,640 @@ func TestStandardTxExecutorBanffAddValidator(t *testing.T) { } } -func TestStandardTxExecutorDurangoAddValidator(t *testing.T) { - require := require.New(t) - env := newEnvironment(t, true /*=postBanff*/, true /*=postCortina*/, true /*=postDurango*/) - env.ctx.Lock.Lock() - defer env.ctx.Lock.Unlock() +// Verifies that the Memo field is required to be empty post-Durango +func TestDurangoMemoField(t *testing.T) { + type test struct { + name string + setupTest func(*environment) (txs.UnsignedTx, [][]*secp256k1.PrivateKey, state.Diff, *types.JSONByteSlice) + } - var ( - nodeID = ids.GenerateTestNodeID() - chainTime = env.state.GetTimestamp() - endTime = chainTime.Add(defaultMaxStakingDuration) - ) + tests := []test{ + { + name: "AddValidatorTx", + setupTest: func(env *environment) (txs.UnsignedTx, [][]*secp256k1.PrivateKey, state.Diff, *types.JSONByteSlice) { + ins, unstakedOuts, stakedOuts, signers, err := env.utxosHandler.Spend( + env.state, + preFundedKeys, + defaultMinValidatorStake, + env.config.AddPrimaryNetworkValidatorFee, + ids.ShortEmpty, + ) + require.NoError(t, err) - addValTx, err := env.txBuilder.NewAddValidatorTx( - env.config.MinValidatorStake, - 0, - uint64(endTime.Unix()), - nodeID, - ids.ShortEmpty, - reward.PercentDenominator, - []*secp256k1.PrivateKey{preFundedKeys[0]}, - ids.ShortEmpty, // change addr - ) - require.NoError(err) + var ( + nodeID = ids.GenerateTestNodeID() + chainTime = env.state.GetTimestamp() + endTime = chainTime.Add(defaultMaxStakingDuration) + ) - onAcceptState, err := state.NewDiff(env.state.GetLastAccepted(), env) - require.NoError(err) + onAcceptState, err := state.NewDiff(env.state.GetLastAccepted(), env) + require.NoError(t, err) + + tx := &txs.AddValidatorTx{ + BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ + NetworkID: env.ctx.NetworkID, + BlockchainID: env.ctx.ChainID, + Ins: ins, + Outs: unstakedOuts, + }}, + Validator: txs.Validator{ + NodeID: nodeID, + Start: 0, + End: uint64(endTime.Unix()), + Wght: env.config.MinValidatorStake, + }, + StakeOuts: stakedOuts, + RewardsOwner: &secp256k1fx.OutputOwners{ + Locktime: 0, + Threshold: 1, + Addrs: []ids.ShortID{ids.ShortEmpty}, + }, + DelegationShares: reward.PercentDenominator, + } + return tx, signers, onAcceptState, &tx.Memo + }, + }, + { + name: "AddSubnetValidatorTx", + setupTest: func(env *environment) (txs.UnsignedTx, [][]*secp256k1.PrivateKey, state.Diff, *types.JSONByteSlice) { + var primaryValidator *state.Staker + it, err := env.state.GetCurrentStakerIterator() + require.NoError(t, err) + for it.Next() { + staker := it.Value() + if staker.Priority != txs.PrimaryNetworkValidatorCurrentPriority { + continue + } + primaryValidator = staker + break + } + it.Release() + + ins, unstakedOuts, _, signers, err := env.utxosHandler.Spend( + env.state, + preFundedKeys, + defaultMinValidatorStake, + env.config.TxFee, + ids.ShortEmpty, + ) + require.NoError(t, err) - require.NoError(addValTx.Unsigned.Visit(&StandardTxExecutor{ - Backend: &env.backend, - State: onAcceptState, - Tx: addValTx, - })) + subnetAuth, subnetSigners, err := env.utxosHandler.Authorize(env.state, testSubnet1.TxID, preFundedKeys) + require.NoError(t, err) + signers = append(signers, subnetSigners) - // Check that a current validator is added - val, err := onAcceptState.GetCurrentValidator(constants.PrimaryNetworkID, nodeID) - require.NoError(err) + onAcceptState, err := state.NewDiff(env.state.GetLastAccepted(), env) + require.NoError(t, err) + + tx := &txs.AddSubnetValidatorTx{ + BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ + NetworkID: env.ctx.NetworkID, + BlockchainID: env.ctx.ChainID, + Ins: ins, + Outs: unstakedOuts, + }}, + SubnetValidator: txs.SubnetValidator{ + Validator: txs.Validator{ + NodeID: primaryValidator.NodeID, + End: uint64(primaryValidator.EndTime.Unix()), + Wght: defaultMinValidatorStake, + }, + Subnet: testSubnet1.TxID, + }, + SubnetAuth: subnetAuth, + } + return tx, signers, onAcceptState, &tx.Memo + }, + }, + { + name: "AddDelegatorTx", + setupTest: func(env *environment) (txs.UnsignedTx, [][]*secp256k1.PrivateKey, state.Diff, *types.JSONByteSlice) { + var primaryValidator *state.Staker + it, err := env.state.GetCurrentStakerIterator() + require.NoError(t, err) + for it.Next() { + staker := it.Value() + if staker.Priority != txs.PrimaryNetworkValidatorCurrentPriority { + continue + } + primaryValidator = staker + break + } + it.Release() + + ins, unstakedOuts, stakedOuts, signers, err := env.utxosHandler.Spend( + env.state, + preFundedKeys, + defaultMinValidatorStake, + env.config.AddPrimaryNetworkDelegatorFee, + ids.ShortEmpty, + ) + require.NoError(t, err) + + onAcceptState, err := state.NewDiff(env.state.GetLastAccepted(), env) + require.NoError(t, err) + + tx := &txs.AddDelegatorTx{ + BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ + NetworkID: env.ctx.NetworkID, + BlockchainID: env.ctx.ChainID, + Ins: ins, + Outs: unstakedOuts, + }}, + Validator: txs.Validator{ + NodeID: primaryValidator.NodeID, + End: uint64(primaryValidator.EndTime.Unix()), + Wght: defaultMinValidatorStake, + }, + StakeOuts: stakedOuts, + DelegationRewardsOwner: &secp256k1fx.OutputOwners{ + Locktime: 0, + Threshold: 1, + Addrs: []ids.ShortID{ids.ShortEmpty}, + }, + } + return tx, signers, onAcceptState, &tx.Memo + }, + }, + { + name: "CreateChainTx", + setupTest: func(env *environment) (txs.UnsignedTx, [][]*secp256k1.PrivateKey, state.Diff, *types.JSONByteSlice) { + chainTime := env.state.GetTimestamp() + createBlockchainTxFee := env.config.GetCreateBlockchainTxFee(chainTime) + + ins, unstakedOuts, _, signers, err := env.utxosHandler.Spend( + env.state, + preFundedKeys, + defaultMinValidatorStake, + createBlockchainTxFee, + ids.ShortEmpty, + ) + require.NoError(t, err) + + subnetAuth, subnetSigners, err := env.utxosHandler.Authorize(env.state, testSubnet1.TxID, preFundedKeys) + require.NoError(t, err) + signers = append(signers, subnetSigners) + + onAcceptState, err := state.NewDiff(env.state.GetLastAccepted(), env) + require.NoError(t, err) + + tx := &txs.CreateChainTx{ + BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ + NetworkID: env.ctx.NetworkID, + BlockchainID: env.ctx.ChainID, + Ins: ins, + Outs: unstakedOuts, + }}, + SubnetID: testSubnet1.TxID, + ChainName: "aaa", + VMID: ids.GenerateTestID(), + FxIDs: []ids.ID{}, + GenesisData: []byte{}, + SubnetAuth: subnetAuth, + } + return tx, signers, onAcceptState, &tx.Memo + }, + }, + { + name: "CreateSubnetTx", + setupTest: func(env *environment) (txs.UnsignedTx, [][]*secp256k1.PrivateKey, state.Diff, *types.JSONByteSlice) { + chainTime := env.state.GetTimestamp() + createSubnetTxFee := env.config.GetCreateSubnetTxFee(chainTime) + + ins, unstakedOuts, _, signers, err := env.utxosHandler.Spend( + env.state, + preFundedKeys, + defaultMinValidatorStake, + createSubnetTxFee, + ids.ShortEmpty, + ) + require.NoError(t, err) + + onAcceptState, err := state.NewDiff(env.state.GetLastAccepted(), env) + require.NoError(t, err) + + tx := &txs.CreateSubnetTx{ + BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ + NetworkID: env.ctx.NetworkID, + BlockchainID: env.ctx.ChainID, + Ins: ins, + Outs: unstakedOuts, + }}, + Owner: &secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{ids.ShortEmpty}, + }, + } + return tx, signers, onAcceptState, &tx.Memo + }, + }, + { + name: "ImportTx", + setupTest: func(env *environment) (txs.UnsignedTx, [][]*secp256k1.PrivateKey, state.Diff, *types.JSONByteSlice) { + // Skip shared memory checks + env.backend.Bootstrapped.Set(false) + + utxoID := avax.UTXOID{ + TxID: ids.Empty.Prefix(1), + OutputIndex: 1, + } + amount := uint64(50000) + recipientKey := preFundedKeys[1] + + utxo := &avax.UTXO{ + UTXOID: utxoID, + Asset: avax.Asset{ID: env.ctx.AVAXAssetID}, + Out: &secp256k1fx.TransferOutput{ + Amt: amount, + OutputOwners: secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{recipientKey.PublicKey().Address()}, + }, + }, + } + + signers := [][]*secp256k1.PrivateKey{{recipientKey}} + + onAcceptState, err := state.NewDiff(env.state.GetLastAccepted(), env) + require.NoError(t, err) + + tx := &txs.ImportTx{ + BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ + NetworkID: env.ctx.NetworkID, + BlockchainID: env.ctx.ChainID, + }}, + SourceChain: env.ctx.XChainID, + ImportedInputs: []*avax.TransferableInput{ + { + UTXOID: utxo.UTXOID, + Asset: utxo.Asset, + In: &secp256k1fx.TransferInput{ + Amt: env.config.TxFee, + }, + }, + }, + } + return tx, signers, onAcceptState, &tx.Memo + }, + }, + { + name: "ExportTx", + setupTest: func(env *environment) (txs.UnsignedTx, [][]*secp256k1.PrivateKey, state.Diff, *types.JSONByteSlice) { + amount := units.Avax + ins, unstakedOuts, _, signers, err := env.utxosHandler.Spend( + env.state, + preFundedKeys, + amount, + env.config.TxFee, + ids.ShortEmpty, + ) + require.NoError(t, err) + + onAcceptState, err := state.NewDiff(env.state.GetLastAccepted(), env) + require.NoError(t, err) + + tx := &txs.ExportTx{ + BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ + NetworkID: env.ctx.NetworkID, + BlockchainID: env.ctx.ChainID, + Ins: ins, + Outs: unstakedOuts, + }}, + DestinationChain: env.ctx.XChainID, + ExportedOutputs: []*avax.TransferableOutput{{ + Asset: avax.Asset{ID: env.ctx.AVAXAssetID}, + Out: &secp256k1fx.TransferOutput{ + Amt: amount, + OutputOwners: secp256k1fx.OutputOwners{ + Locktime: 0, + Threshold: 1, + Addrs: []ids.ShortID{ids.GenerateTestShortID()}, + }, + }, + }}, + } + return tx, signers, onAcceptState, &tx.Memo + }, + }, + { + name: "RemoveSubnetValidatorTx", + setupTest: func(env *environment) (txs.UnsignedTx, [][]*secp256k1.PrivateKey, state.Diff, *types.JSONByteSlice) { + var primaryValidator *state.Staker + it, err := env.state.GetCurrentStakerIterator() + require.NoError(t, err) + for it.Next() { + staker := it.Value() + if staker.Priority != txs.PrimaryNetworkValidatorCurrentPriority { + continue + } + primaryValidator = staker + break + } + it.Release() + + endTime := primaryValidator.EndTime + subnetValTx, err := env.txBuilder.NewAddSubnetValidatorTx( + defaultWeight, + 0, + uint64(endTime.Unix()), + primaryValidator.NodeID, + testSubnet1.ID(), + []*secp256k1.PrivateKey{testSubnet1ControlKeys[0], testSubnet1ControlKeys[1]}, + ids.ShortEmpty, + ) + require.NoError(t, err) + + onAcceptState, err := state.NewDiff(env.state.GetLastAccepted(), env) + require.NoError(t, err) + + require.NoError(t, subnetValTx.Unsigned.Visit(&StandardTxExecutor{ + Backend: &env.backend, + State: onAcceptState, + Tx: subnetValTx, + })) + + ins, unstakedOuts, _, signers, err := env.utxosHandler.Spend( + env.state, + preFundedKeys, + defaultMinValidatorStake, + env.config.TxFee, + ids.ShortEmpty, + ) + require.NoError(t, err) + + subnetAuth, subnetSigners, err := env.utxosHandler.Authorize(env.state, testSubnet1.TxID, preFundedKeys) + require.NoError(t, err) + signers = append(signers, subnetSigners) + + tx := &txs.RemoveSubnetValidatorTx{ + BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ + NetworkID: env.ctx.NetworkID, + BlockchainID: env.ctx.ChainID, + Ins: ins, + Outs: unstakedOuts, + }}, + Subnet: testSubnet1.ID(), + NodeID: primaryValidator.NodeID, + SubnetAuth: subnetAuth, + } + return tx, signers, onAcceptState, &tx.Memo + }, + }, + { + name: "TransformSubnetTx", + setupTest: func(env *environment) (txs.UnsignedTx, [][]*secp256k1.PrivateKey, state.Diff, *types.JSONByteSlice) { + ins, unstakedOuts, _, signers, err := env.utxosHandler.Spend( + env.state, + preFundedKeys, + defaultMinValidatorStake, + env.config.TxFee, + ids.ShortEmpty, + ) + require.NoError(t, err) + + subnetAuth, subnetSigners, err := env.utxosHandler.Authorize(env.state, testSubnet1.TxID, preFundedKeys) + require.NoError(t, err) + signers = append(signers, subnetSigners) + + onAcceptState, err := state.NewDiff(env.state.GetLastAccepted(), env) + require.NoError(t, err) + + tx := &txs.TransformSubnetTx{ + BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ + NetworkID: env.ctx.NetworkID, + BlockchainID: env.ctx.ChainID, + Ins: ins, + Outs: unstakedOuts, + }}, + Subnet: testSubnet1.TxID, + AssetID: ids.GenerateTestID(), + InitialSupply: 10, + MaximumSupply: 10, + MinConsumptionRate: 0, + MaxConsumptionRate: reward.PercentDenominator, + MinValidatorStake: 2, + MaxValidatorStake: 10, + MinStakeDuration: 1, + MaxStakeDuration: 2, + MinDelegationFee: reward.PercentDenominator, + MinDelegatorStake: 1, + MaxValidatorWeightFactor: 1, + UptimeRequirement: reward.PercentDenominator, + SubnetAuth: subnetAuth, + } + return tx, signers, onAcceptState, &tx.Memo + }, + }, + { + name: "AddPermissionlessValidatorTx", + setupTest: func(env *environment) (txs.UnsignedTx, [][]*secp256k1.PrivateKey, state.Diff, *types.JSONByteSlice) { + ins, unstakedOuts, stakedOuts, signers, err := env.utxosHandler.Spend( + env.state, + preFundedKeys, + defaultMinValidatorStake, + env.config.AddPrimaryNetworkValidatorFee, + ids.ShortEmpty, + ) + require.NoError(t, err) + + sk, err := bls.NewSecretKey() + require.NoError(t, err) + + var ( + nodeID = ids.GenerateTestNodeID() + chainTime = env.state.GetTimestamp() + endTime = chainTime.Add(defaultMaxStakingDuration) + ) + + onAcceptState, err := state.NewDiff(env.state.GetLastAccepted(), env) + require.NoError(t, err) + + tx := &txs.AddPermissionlessValidatorTx{ + BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ + NetworkID: env.ctx.NetworkID, + BlockchainID: env.ctx.ChainID, + Ins: ins, + Outs: unstakedOuts, + }}, + Validator: txs.Validator{ + NodeID: nodeID, + End: uint64(endTime.Unix()), + Wght: env.config.MinValidatorStake, + }, + Subnet: constants.PrimaryNetworkID, + Signer: signer.NewProofOfPossession(sk), + StakeOuts: stakedOuts, + ValidatorRewardsOwner: &secp256k1fx.OutputOwners{ + Locktime: 0, + Threshold: 1, + Addrs: []ids.ShortID{ + ids.ShortEmpty, + }, + }, + DelegatorRewardsOwner: &secp256k1fx.OutputOwners{ + Locktime: 0, + Threshold: 1, + Addrs: []ids.ShortID{ + ids.ShortEmpty, + }, + }, + DelegationShares: reward.PercentDenominator, + } + return tx, signers, onAcceptState, &tx.Memo + }, + }, + { + name: "AddPermissionlessDelegatorTx", + setupTest: func(env *environment) (txs.UnsignedTx, [][]*secp256k1.PrivateKey, state.Diff, *types.JSONByteSlice) { + var primaryValidator *state.Staker + it, err := env.state.GetCurrentStakerIterator() + require.NoError(t, err) + for it.Next() { + staker := it.Value() + if staker.Priority != txs.PrimaryNetworkValidatorCurrentPriority { + continue + } + primaryValidator = staker + break + } + it.Release() + + ins, unstakedOuts, stakedOuts, signers, err := env.utxosHandler.Spend( + env.state, + preFundedKeys, + defaultMinValidatorStake, + env.config.AddPrimaryNetworkDelegatorFee, + ids.ShortEmpty, + ) + require.NoError(t, err) - require.Equal(addValTx.ID(), val.TxID) - require.Equal(chainTime, val.StartTime) - require.Equal(endTime, val.EndTime) + onAcceptState, err := state.NewDiff(env.state.GetLastAccepted(), env) + require.NoError(t, err) + + tx := &txs.AddPermissionlessDelegatorTx{ + BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ + NetworkID: env.ctx.NetworkID, + BlockchainID: env.ctx.ChainID, + Ins: ins, + Outs: unstakedOuts, + }}, + Validator: txs.Validator{ + NodeID: primaryValidator.NodeID, + End: uint64(primaryValidator.EndTime.Unix()), + Wght: defaultMinValidatorStake, + }, + StakeOuts: stakedOuts, + DelegationRewardsOwner: &secp256k1fx.OutputOwners{ + Locktime: 0, + Threshold: 1, + Addrs: []ids.ShortID{ids.ShortEmpty}, + }, + } + return tx, signers, onAcceptState, &tx.Memo + }, + }, + { + name: "TransferSubnetOwnershipTx", + setupTest: func(env *environment) (txs.UnsignedTx, [][]*secp256k1.PrivateKey, state.Diff, *types.JSONByteSlice) { + ins, unstakedOuts, _, signers, err := env.utxosHandler.Spend( + env.state, + preFundedKeys, + defaultMinValidatorStake, + env.config.TxFee, + ids.ShortEmpty, + ) + require.NoError(t, err) + + subnetAuth, subnetSigners, err := env.utxosHandler.Authorize(env.state, testSubnet1.TxID, preFundedKeys) + require.NoError(t, err) + signers = append(signers, subnetSigners) + + onAcceptState, err := state.NewDiff(env.state.GetLastAccepted(), env) + require.NoError(t, err) + + tx := &txs.TransferSubnetOwnershipTx{ + BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{ + NetworkID: env.ctx.NetworkID, + BlockchainID: env.ctx.ChainID, + Ins: ins, + Outs: unstakedOuts, + }}, + Subnet: testSubnet1.TxID, + SubnetAuth: subnetAuth, + Owner: &secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{ids.ShortEmpty}, + }, + } + return tx, signers, onAcceptState, &tx.Memo + }, + }, + { + name: "BaseTx", + setupTest: func(env *environment) (txs.UnsignedTx, [][]*secp256k1.PrivateKey, state.Diff, *types.JSONByteSlice) { + ins, unstakedOuts, _, signers, err := env.utxosHandler.Spend( + env.state, + preFundedKeys, + defaultMinValidatorStake, + env.config.TxFee, + ids.ShortEmpty, + ) + require.NoError(t, err) + + onAcceptState, err := state.NewDiff(env.state.GetLastAccepted(), env) + require.NoError(t, err) + + tx := &txs.BaseTx{ + BaseTx: avax.BaseTx{ + NetworkID: env.ctx.NetworkID, + BlockchainID: env.ctx.ChainID, + Ins: ins, + Outs: unstakedOuts, + }, + } + return tx, signers, onAcceptState, &tx.Memo + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + require := require.New(t) + + env := newEnvironment(t, true /*=postBanff*/, true /*=postCortina*/, true /*=postDurango*/) + env.ctx.Lock.Lock() + defer env.ctx.Lock.Unlock() + + utx, signers, onAcceptState, memo := tt.setupTest(env) + + // Populated memo field should error + *memo = []byte{'m', 'e', 'm', 'o'} + tx, err := txs.NewSigned(utx, txs.Codec, signers) + require.NoError(err) + + err = tx.Unsigned.Visit(&StandardTxExecutor{ + Backend: &env.backend, + State: onAcceptState, + Tx: tx, + }) + require.ErrorIs(err, avax.ErrMemoTooLarge) + + // Empty memo field should not error + *memo = []byte{} + tx, err = txs.NewSigned(utx, txs.Codec, signers) + require.NoError(err) + + require.NoError(tx.Unsigned.Visit(&StandardTxExecutor{ + Backend: &env.backend, + State: onAcceptState, + Tx: tx, + })) + }) + } } // Returns a RemoveSubnetValidatorTx that passes syntactic verification. +// Memo field is empty as required post Durango activation func newRemoveSubnetValidatorTx(t *testing.T) (*txs.RemoveSubnetValidatorTx, *txs.Tx) { t.Helper() @@ -1034,7 +1629,6 @@ func newRemoveSubnetValidatorTx(t *testing.T) (*txs.RemoveSubnetValidatorTx, *tx }, }, }, - Memo: []byte("hi"), }, }, Subnet: ids.GenerateTestID(), @@ -1102,6 +1696,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { env := newValidRemoveSubnetValidatorTxVerifyEnv(t, ctrl) // Set dependency expectations. + env.state.EXPECT().GetTimestamp().Return(env.latestForkTime) env.state.EXPECT().GetCurrentValidator(env.unsignedTx.Subnet, env.unsignedTx.NodeID).Return(env.staker, nil).Times(1) subnetOwner := fx.NewMockOwner(ctrl) env.state.EXPECT().GetSubnetOwner(env.unsignedTx.Subnet).Return(subnetOwner, nil).Times(1) @@ -1164,6 +1759,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { newExecutor: func(ctrl *gomock.Controller) (*txs.RemoveSubnetValidatorTx, *StandardTxExecutor) { env := newValidRemoveSubnetValidatorTxVerifyEnv(t, ctrl) env.state = state.NewMockDiff(ctrl) + env.state.EXPECT().GetTimestamp().Return(env.latestForkTime) env.state.EXPECT().GetCurrentValidator(env.unsignedTx.Subnet, env.unsignedTx.NodeID).Return(nil, database.ErrNotFound) env.state.EXPECT().GetPendingValidator(env.unsignedTx.Subnet, env.unsignedTx.NodeID).Return(nil, database.ErrNotFound) e := &StandardTxExecutor{ @@ -1195,6 +1791,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { staker.Priority = txs.SubnetPermissionlessValidatorCurrentPriority // Set dependency expectations. + env.state.EXPECT().GetTimestamp().Return(env.latestForkTime) env.state.EXPECT().GetCurrentValidator(env.unsignedTx.Subnet, env.unsignedTx.NodeID).Return(&staker, nil).Times(1) e := &StandardTxExecutor{ Backend: &Backend{ @@ -1223,6 +1820,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { // Remove credentials env.tx.Creds = nil env.state = state.NewMockDiff(ctrl) + env.state.EXPECT().GetTimestamp().Return(env.latestForkTime) env.state.EXPECT().GetCurrentValidator(env.unsignedTx.Subnet, env.unsignedTx.NodeID).Return(env.staker, nil) e := &StandardTxExecutor{ Backend: &Backend{ @@ -1249,6 +1847,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { newExecutor: func(ctrl *gomock.Controller) (*txs.RemoveSubnetValidatorTx, *StandardTxExecutor) { env := newValidRemoveSubnetValidatorTxVerifyEnv(t, ctrl) env.state = state.NewMockDiff(ctrl) + env.state.EXPECT().GetTimestamp().Return(env.latestForkTime) env.state.EXPECT().GetCurrentValidator(env.unsignedTx.Subnet, env.unsignedTx.NodeID).Return(env.staker, nil) env.state.EXPECT().GetSubnetOwner(env.unsignedTx.Subnet).Return(nil, database.ErrNotFound) e := &StandardTxExecutor{ @@ -1276,6 +1875,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { newExecutor: func(ctrl *gomock.Controller) (*txs.RemoveSubnetValidatorTx, *StandardTxExecutor) { env := newValidRemoveSubnetValidatorTxVerifyEnv(t, ctrl) env.state = state.NewMockDiff(ctrl) + env.state.EXPECT().GetTimestamp().Return(env.latestForkTime) env.state.EXPECT().GetCurrentValidator(env.unsignedTx.Subnet, env.unsignedTx.NodeID).Return(env.staker, nil) subnetOwner := fx.NewMockOwner(ctrl) env.state.EXPECT().GetSubnetOwner(env.unsignedTx.Subnet).Return(subnetOwner, nil) @@ -1305,6 +1905,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { newExecutor: func(ctrl *gomock.Controller) (*txs.RemoveSubnetValidatorTx, *StandardTxExecutor) { env := newValidRemoveSubnetValidatorTxVerifyEnv(t, ctrl) env.state = state.NewMockDiff(ctrl) + env.state.EXPECT().GetTimestamp().Return(env.latestForkTime) env.state.EXPECT().GetCurrentValidator(env.unsignedTx.Subnet, env.unsignedTx.NodeID).Return(env.staker, nil) subnetOwner := fx.NewMockOwner(ctrl) env.state.EXPECT().GetSubnetOwner(env.unsignedTx.Subnet).Return(subnetOwner, nil) @@ -1347,6 +1948,7 @@ func TestStandardExecutorRemoveSubnetValidatorTx(t *testing.T) { } // Returns a TransformSubnetTx that passes syntactic verification. +// Memo field is empty as required post Durango activation func newTransformSubnetTx(t *testing.T) (*txs.TransformSubnetTx, *txs.Tx) { t.Helper() @@ -1389,7 +1991,6 @@ func newTransformSubnetTx(t *testing.T) (*txs.TransformSubnetTx, *txs.Tx) { }, }, }, - Memo: []byte("hi"), }, }, Subnet: ids.GenerateTestID(), @@ -1495,6 +2096,7 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { env := newValidTransformSubnetTxVerifyEnv(t, ctrl) env.unsignedTx.MaxStakeDuration = math.MaxUint32 env.state = state.NewMockDiff(ctrl) + env.state.EXPECT().GetTimestamp().Return(env.latestForkTime) e := &StandardTxExecutor{ Backend: &Backend{ Config: &config.Config{ @@ -1522,6 +2124,7 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { // Remove credentials env.tx.Creds = nil env.state = state.NewMockDiff(ctrl) + env.state.EXPECT().GetTimestamp().Return(env.latestForkTime) e := &StandardTxExecutor{ Backend: &Backend{ Config: &config.Config{ @@ -1549,6 +2152,7 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { env := newValidTransformSubnetTxVerifyEnv(t, ctrl) env.state = state.NewMockDiff(ctrl) subnetOwner := fx.NewMockOwner(ctrl) + env.state.EXPECT().GetTimestamp().Return(env.latestForkTime) env.state.EXPECT().GetSubnetOwner(env.unsignedTx.Subnet).Return(subnetOwner, nil) env.state.EXPECT().GetSubnetTransformation(env.unsignedTx.Subnet).Return(nil, database.ErrNotFound).Times(1) env.fx.EXPECT().VerifyPermission(gomock.Any(), env.unsignedTx.SubnetAuth, env.tx.Creds[len(env.tx.Creds)-1], subnetOwner).Return(nil) @@ -1583,6 +2187,7 @@ func TestStandardExecutorTransformSubnetTx(t *testing.T) { // Set dependency expectations. subnetOwner := fx.NewMockOwner(ctrl) + env.state.EXPECT().GetTimestamp().Return(env.latestForkTime) env.state.EXPECT().GetSubnetOwner(env.unsignedTx.Subnet).Return(subnetOwner, nil).Times(1) env.state.EXPECT().GetSubnetTransformation(env.unsignedTx.Subnet).Return(nil, database.ErrNotFound).Times(1) env.fx.EXPECT().VerifyPermission(env.unsignedTx, env.unsignedTx.SubnetAuth, env.tx.Creds[len(env.tx.Creds)-1], subnetOwner).Return(nil).Times(1) diff --git a/vms/propertyfx/factory.go b/vms/propertyfx/factory.go index c42b92c84c5..53d6101b130 100644 --- a/vms/propertyfx/factory.go +++ b/vms/propertyfx/factory.go @@ -5,12 +5,13 @@ package propertyfx import ( "github.com/ava-labs/avalanchego/ids" - "github.com/ava-labs/avalanchego/utils/logging" - "github.com/ava-labs/avalanchego/vms" + "github.com/ava-labs/avalanchego/vms/fx" ) +const Name = "propertyfx" + var ( - _ vms.Factory = (*Factory)(nil) + _ fx.Factory = (*Factory)(nil) // ID that this Fx uses when labeled ID = ids.ID{'p', 'r', 'o', 'p', 'e', 'r', 't', 'y', 'f', 'x'} @@ -18,6 +19,6 @@ var ( type Factory struct{} -func (*Factory) New(logging.Logger) (interface{}, error) { - return &Fx{}, nil +func (*Factory) New() any { + return &Fx{} } diff --git a/vms/propertyfx/factory_test.go b/vms/propertyfx/factory_test.go index f40cb2610a8..9aa461921e4 100644 --- a/vms/propertyfx/factory_test.go +++ b/vms/propertyfx/factory_test.go @@ -7,15 +7,11 @@ import ( "testing" "github.com/stretchr/testify/require" - - "github.com/ava-labs/avalanchego/utils/logging" ) func TestFactory(t *testing.T) { require := require.New(t) factory := Factory{} - fx, err := factory.New(logging.NoLog{}) - require.NoError(err) - require.NotNil(fx) + require.Equal(&Fx{}, factory.New()) } diff --git a/vms/secp256k1fx/factory.go b/vms/secp256k1fx/factory.go index fd52fe79a6f..9630795ea37 100644 --- a/vms/secp256k1fx/factory.go +++ b/vms/secp256k1fx/factory.go @@ -5,12 +5,13 @@ package secp256k1fx import ( "github.com/ava-labs/avalanchego/ids" - "github.com/ava-labs/avalanchego/utils/logging" - "github.com/ava-labs/avalanchego/vms" + "github.com/ava-labs/avalanchego/vms/fx" ) +const Name = "secp256k1fx" + var ( - _ vms.Factory = (*Factory)(nil) + _ fx.Factory = (*Factory)(nil) // ID that this Fx uses when labeled ID = ids.ID{'s', 'e', 'c', 'p', '2', '5', '6', 'k', '1', 'f', 'x'} @@ -18,6 +19,6 @@ var ( type Factory struct{} -func (*Factory) New(logging.Logger) (interface{}, error) { - return &Fx{}, nil +func (*Factory) New() any { + return &Fx{} } diff --git a/vms/secp256k1fx/factory_test.go b/vms/secp256k1fx/factory_test.go index 2b1fa184474..d7653d361f5 100644 --- a/vms/secp256k1fx/factory_test.go +++ b/vms/secp256k1fx/factory_test.go @@ -7,14 +7,10 @@ import ( "testing" "github.com/stretchr/testify/require" - - "github.com/ava-labs/avalanchego/utils/logging" ) func TestFactory(t *testing.T) { require := require.New(t) factory := Factory{} - fx, err := factory.New(logging.NoLog{}) - require.NoError(err) - require.NotNil(fx) + require.Equal(&Fx{}, factory.New()) }