github.com/ava-labs/avalanchego@v1.11.11/vms/platformvm/txs/fee/complexity.go (about)

     1  // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  package fee
     5  
     6  import (
     7  	"errors"
     8  
     9  	"github.com/ava-labs/avalanchego/codec"
    10  	"github.com/ava-labs/avalanchego/ids"
    11  	"github.com/ava-labs/avalanchego/utils/crypto/bls"
    12  	"github.com/ava-labs/avalanchego/utils/crypto/secp256k1"
    13  	"github.com/ava-labs/avalanchego/utils/math"
    14  	"github.com/ava-labs/avalanchego/utils/wrappers"
    15  	"github.com/ava-labs/avalanchego/vms/components/avax"
    16  	"github.com/ava-labs/avalanchego/vms/components/gas"
    17  	"github.com/ava-labs/avalanchego/vms/components/verify"
    18  	"github.com/ava-labs/avalanchego/vms/platformvm/fx"
    19  	"github.com/ava-labs/avalanchego/vms/platformvm/signer"
    20  	"github.com/ava-labs/avalanchego/vms/platformvm/stakeable"
    21  	"github.com/ava-labs/avalanchego/vms/platformvm/txs"
    22  	"github.com/ava-labs/avalanchego/vms/secp256k1fx"
    23  )
    24  
    25  const (
    26  	intrinsicValidatorBandwidth = ids.NodeIDLen + // nodeID
    27  		wrappers.LongLen + // start
    28  		wrappers.LongLen + // end
    29  		wrappers.LongLen // weight
    30  
    31  	intrinsicSubnetValidatorBandwidth = intrinsicValidatorBandwidth + // validator
    32  		ids.IDLen // subnetID
    33  
    34  	intrinsicOutputBandwidth = ids.IDLen + // assetID
    35  		wrappers.IntLen // output typeID
    36  
    37  	intrinsicStakeableLockedOutputBandwidth = wrappers.LongLen + // locktime
    38  		wrappers.IntLen // output typeID
    39  
    40  	intrinsicSECP256k1FxOutputOwnersBandwidth = wrappers.LongLen + // locktime
    41  		wrappers.IntLen + // threshold
    42  		wrappers.IntLen // num addresses
    43  
    44  	intrinsicSECP256k1FxOutputBandwidth = wrappers.LongLen + // amount
    45  		intrinsicSECP256k1FxOutputOwnersBandwidth
    46  
    47  	intrinsicInputBandwidth = ids.IDLen + // txID
    48  		wrappers.IntLen + // output index
    49  		ids.IDLen + // assetID
    50  		wrappers.IntLen + // input typeID
    51  		wrappers.IntLen // credential typeID
    52  
    53  	intrinsicStakeableLockedInputBandwidth = wrappers.LongLen + // locktime
    54  		wrappers.IntLen // input typeID
    55  
    56  	intrinsicSECP256k1FxInputBandwidth = wrappers.IntLen + // num indices
    57  		wrappers.IntLen // num signatures
    58  
    59  	intrinsicSECP256k1FxTransferableInputBandwidth = wrappers.LongLen + // amount
    60  		intrinsicSECP256k1FxInputBandwidth
    61  
    62  	intrinsicSECP256k1FxSignatureBandwidth = wrappers.IntLen + // signature index
    63  		secp256k1.SignatureLen // signature length
    64  
    65  	intrinsicPoPBandwidth = bls.PublicKeyLen + // public key
    66  		bls.SignatureLen // signature
    67  
    68  	intrinsicInputDBRead = 1
    69  
    70  	intrinsicInputDBWrite  = 1
    71  	intrinsicOutputDBWrite = 1
    72  )
    73  
    74  var (
    75  	_ txs.Visitor = (*complexityVisitor)(nil)
    76  
    77  	IntrinsicAddPermissionlessValidatorTxComplexities = gas.Dimensions{
    78  		gas.Bandwidth: IntrinsicBaseTxComplexities[gas.Bandwidth] +
    79  			intrinsicValidatorBandwidth + // validator
    80  			ids.IDLen + // subnetID
    81  			wrappers.IntLen + // signer typeID
    82  			wrappers.IntLen + // num stake outs
    83  			wrappers.IntLen + // validator rewards typeID
    84  			wrappers.IntLen + // delegator rewards typeID
    85  			wrappers.IntLen, // delegation shares
    86  		gas.DBRead:  1,
    87  		gas.DBWrite: 1,
    88  		gas.Compute: 0,
    89  	}
    90  	IntrinsicAddPermissionlessDelegatorTxComplexities = gas.Dimensions{
    91  		gas.Bandwidth: IntrinsicBaseTxComplexities[gas.Bandwidth] +
    92  			intrinsicValidatorBandwidth + // validator
    93  			ids.IDLen + // subnetID
    94  			wrappers.IntLen + // num stake outs
    95  			wrappers.IntLen, // delegator rewards typeID
    96  		gas.DBRead:  1,
    97  		gas.DBWrite: 1,
    98  		gas.Compute: 0,
    99  	}
   100  	IntrinsicAddSubnetValidatorTxComplexities = gas.Dimensions{
   101  		gas.Bandwidth: IntrinsicBaseTxComplexities[gas.Bandwidth] +
   102  			intrinsicSubnetValidatorBandwidth + // subnetValidator
   103  			wrappers.IntLen + // subnetAuth typeID
   104  			wrappers.IntLen, // subnetAuthCredential typeID
   105  		gas.DBRead:  2,
   106  		gas.DBWrite: 1,
   107  		gas.Compute: 0,
   108  	}
   109  	IntrinsicBaseTxComplexities = gas.Dimensions{
   110  		gas.Bandwidth: codec.VersionSize + // codecVersion
   111  			wrappers.IntLen + // typeID
   112  			wrappers.IntLen + // networkID
   113  			ids.IDLen + // blockchainID
   114  			wrappers.IntLen + // number of outputs
   115  			wrappers.IntLen + // number of inputs
   116  			wrappers.IntLen + // length of memo
   117  			wrappers.IntLen, // number of credentials
   118  		gas.DBRead:  0,
   119  		gas.DBWrite: 0,
   120  		gas.Compute: 0,
   121  	}
   122  	IntrinsicCreateChainTxComplexities = gas.Dimensions{
   123  		gas.Bandwidth: IntrinsicBaseTxComplexities[gas.Bandwidth] +
   124  			ids.IDLen + // subnetID
   125  			wrappers.ShortLen + // chainName length
   126  			ids.IDLen + // vmID
   127  			wrappers.IntLen + // num fxIDs
   128  			wrappers.IntLen + // genesis length
   129  			wrappers.IntLen + // subnetAuth typeID
   130  			wrappers.IntLen, // subnetAuthCredential typeID
   131  		gas.DBRead:  1,
   132  		gas.DBWrite: 1,
   133  		gas.Compute: 0,
   134  	}
   135  	IntrinsicCreateSubnetTxComplexities = gas.Dimensions{
   136  		gas.Bandwidth: IntrinsicBaseTxComplexities[gas.Bandwidth] +
   137  			wrappers.IntLen, // owner typeID
   138  		gas.DBRead:  0,
   139  		gas.DBWrite: 1,
   140  		gas.Compute: 0,
   141  	}
   142  	IntrinsicExportTxComplexities = gas.Dimensions{
   143  		gas.Bandwidth: IntrinsicBaseTxComplexities[gas.Bandwidth] +
   144  			ids.IDLen + // destination chainID
   145  			wrappers.IntLen, // num exported outputs
   146  		gas.DBRead:  0,
   147  		gas.DBWrite: 0,
   148  		gas.Compute: 0,
   149  	}
   150  	IntrinsicImportTxComplexities = gas.Dimensions{
   151  		gas.Bandwidth: IntrinsicBaseTxComplexities[gas.Bandwidth] +
   152  			ids.IDLen + // source chainID
   153  			wrappers.IntLen, // num importing inputs
   154  		gas.DBRead:  0,
   155  		gas.DBWrite: 0,
   156  		gas.Compute: 0,
   157  	}
   158  	IntrinsicRemoveSubnetValidatorTxComplexities = gas.Dimensions{
   159  		gas.Bandwidth: IntrinsicBaseTxComplexities[gas.Bandwidth] +
   160  			ids.NodeIDLen + // nodeID
   161  			ids.IDLen + // subnetID
   162  			wrappers.IntLen + // subnetAuth typeID
   163  			wrappers.IntLen, // subnetAuthCredential typeID
   164  		gas.DBRead:  2,
   165  		gas.DBWrite: 1,
   166  		gas.Compute: 0,
   167  	}
   168  	IntrinsicTransferSubnetOwnershipTxComplexities = gas.Dimensions{
   169  		gas.Bandwidth: IntrinsicBaseTxComplexities[gas.Bandwidth] +
   170  			ids.IDLen + // subnetID
   171  			wrappers.IntLen + // subnetAuth typeID
   172  			wrappers.IntLen + // owner typeID
   173  			wrappers.IntLen, // subnetAuthCredential typeID
   174  		gas.DBRead:  1,
   175  		gas.DBWrite: 1,
   176  		gas.Compute: 0,
   177  	}
   178  
   179  	errUnsupportedOutput = errors.New("unsupported output type")
   180  	errUnsupportedInput  = errors.New("unsupported input type")
   181  	errUnsupportedOwner  = errors.New("unsupported owner type")
   182  	errUnsupportedAuth   = errors.New("unsupported auth type")
   183  	errUnsupportedSigner = errors.New("unsupported signer type")
   184  )
   185  
   186  func TxComplexity(txs ...txs.UnsignedTx) (gas.Dimensions, error) {
   187  	var (
   188  		c          complexityVisitor
   189  		complexity gas.Dimensions
   190  	)
   191  	for _, tx := range txs {
   192  		c = complexityVisitor{}
   193  		err := tx.Visit(&c)
   194  		if err != nil {
   195  			return gas.Dimensions{}, err
   196  		}
   197  
   198  		complexity, err = complexity.Add(&c.output)
   199  		if err != nil {
   200  			return gas.Dimensions{}, err
   201  		}
   202  	}
   203  	return complexity, nil
   204  }
   205  
   206  // OutputComplexity returns the complexity outputs add to a transaction.
   207  func OutputComplexity(outs ...*avax.TransferableOutput) (gas.Dimensions, error) {
   208  	var complexity gas.Dimensions
   209  	for _, out := range outs {
   210  		outputComplexity, err := outputComplexity(out)
   211  		if err != nil {
   212  			return gas.Dimensions{}, err
   213  		}
   214  
   215  		complexity, err = complexity.Add(&outputComplexity)
   216  		if err != nil {
   217  			return gas.Dimensions{}, err
   218  		}
   219  	}
   220  	return complexity, nil
   221  }
   222  
   223  func outputComplexity(out *avax.TransferableOutput) (gas.Dimensions, error) {
   224  	complexity := gas.Dimensions{
   225  		gas.Bandwidth: intrinsicOutputBandwidth + intrinsicSECP256k1FxOutputBandwidth,
   226  		gas.DBRead:    0,
   227  		gas.DBWrite:   intrinsicOutputDBWrite,
   228  		gas.Compute:   0,
   229  	}
   230  
   231  	outIntf := out.Out
   232  	if stakeableOut, ok := outIntf.(*stakeable.LockOut); ok {
   233  		complexity[gas.Bandwidth] += intrinsicStakeableLockedOutputBandwidth
   234  		outIntf = stakeableOut.TransferableOut
   235  	}
   236  
   237  	secp256k1Out, ok := outIntf.(*secp256k1fx.TransferOutput)
   238  	if !ok {
   239  		return gas.Dimensions{}, errUnsupportedOutput
   240  	}
   241  
   242  	numAddresses := uint64(len(secp256k1Out.Addrs))
   243  	addressBandwidth, err := math.Mul(numAddresses, ids.ShortIDLen)
   244  	if err != nil {
   245  		return gas.Dimensions{}, err
   246  	}
   247  	complexity[gas.Bandwidth], err = math.Add(complexity[gas.Bandwidth], addressBandwidth)
   248  	return complexity, err
   249  }
   250  
   251  // InputComplexity returns the complexity inputs add to a transaction.
   252  // It includes the complexity that the corresponding credentials will add.
   253  func InputComplexity(ins ...*avax.TransferableInput) (gas.Dimensions, error) {
   254  	var complexity gas.Dimensions
   255  	for _, in := range ins {
   256  		inputComplexity, err := inputComplexity(in)
   257  		if err != nil {
   258  			return gas.Dimensions{}, err
   259  		}
   260  
   261  		complexity, err = complexity.Add(&inputComplexity)
   262  		if err != nil {
   263  			return gas.Dimensions{}, err
   264  		}
   265  	}
   266  	return complexity, nil
   267  }
   268  
   269  func inputComplexity(in *avax.TransferableInput) (gas.Dimensions, error) {
   270  	complexity := gas.Dimensions{
   271  		gas.Bandwidth: intrinsicInputBandwidth + intrinsicSECP256k1FxTransferableInputBandwidth,
   272  		gas.DBRead:    intrinsicInputDBRead,
   273  		gas.DBWrite:   intrinsicInputDBWrite,
   274  		gas.Compute:   0, // TODO: Add compute complexity
   275  	}
   276  
   277  	inIntf := in.In
   278  	if stakeableIn, ok := inIntf.(*stakeable.LockIn); ok {
   279  		complexity[gas.Bandwidth] += intrinsicStakeableLockedInputBandwidth
   280  		inIntf = stakeableIn.TransferableIn
   281  	}
   282  
   283  	secp256k1In, ok := inIntf.(*secp256k1fx.TransferInput)
   284  	if !ok {
   285  		return gas.Dimensions{}, errUnsupportedInput
   286  	}
   287  
   288  	numSignatures := uint64(len(secp256k1In.SigIndices))
   289  	signatureBandwidth, err := math.Mul(numSignatures, intrinsicSECP256k1FxSignatureBandwidth)
   290  	if err != nil {
   291  		return gas.Dimensions{}, err
   292  	}
   293  	complexity[gas.Bandwidth], err = math.Add(complexity[gas.Bandwidth], signatureBandwidth)
   294  	return complexity, err
   295  }
   296  
   297  // OwnerComplexity returns the complexity an owner adds to a transaction.
   298  // It does not include the typeID of the owner.
   299  func OwnerComplexity(ownerIntf fx.Owner) (gas.Dimensions, error) {
   300  	owner, ok := ownerIntf.(*secp256k1fx.OutputOwners)
   301  	if !ok {
   302  		return gas.Dimensions{}, errUnsupportedOwner
   303  	}
   304  
   305  	numAddresses := uint64(len(owner.Addrs))
   306  	addressBandwidth, err := math.Mul(numAddresses, ids.ShortIDLen)
   307  	if err != nil {
   308  		return gas.Dimensions{}, err
   309  	}
   310  
   311  	bandwidth, err := math.Add(addressBandwidth, intrinsicSECP256k1FxOutputOwnersBandwidth)
   312  	if err != nil {
   313  		return gas.Dimensions{}, err
   314  	}
   315  
   316  	return gas.Dimensions{
   317  		gas.Bandwidth: bandwidth,
   318  		gas.DBRead:    0,
   319  		gas.DBWrite:   0,
   320  		gas.Compute:   0,
   321  	}, nil
   322  }
   323  
   324  // AuthComplexity returns the complexity an authorization adds to a transaction.
   325  // It does not include the typeID of the authorization.
   326  // It does includes the complexity that the corresponding credential will add.
   327  // It does not include the typeID of the credential.
   328  func AuthComplexity(authIntf verify.Verifiable) (gas.Dimensions, error) {
   329  	auth, ok := authIntf.(*secp256k1fx.Input)
   330  	if !ok {
   331  		return gas.Dimensions{}, errUnsupportedAuth
   332  	}
   333  
   334  	numSignatures := uint64(len(auth.SigIndices))
   335  	signatureBandwidth, err := math.Mul(numSignatures, intrinsicSECP256k1FxSignatureBandwidth)
   336  	if err != nil {
   337  		return gas.Dimensions{}, err
   338  	}
   339  
   340  	bandwidth, err := math.Add(signatureBandwidth, intrinsicSECP256k1FxInputBandwidth)
   341  	if err != nil {
   342  		return gas.Dimensions{}, err
   343  	}
   344  
   345  	return gas.Dimensions{
   346  		gas.Bandwidth: bandwidth,
   347  		gas.DBRead:    0,
   348  		gas.DBWrite:   0,
   349  		gas.Compute:   0, // TODO: Add compute complexity
   350  	}, nil
   351  }
   352  
   353  // SignerComplexity returns the complexity a signer adds to a transaction.
   354  // It does not include the typeID of the signer.
   355  func SignerComplexity(s signer.Signer) (gas.Dimensions, error) {
   356  	switch s.(type) {
   357  	case *signer.Empty:
   358  		return gas.Dimensions{}, nil
   359  	case *signer.ProofOfPossession:
   360  		return gas.Dimensions{
   361  			gas.Bandwidth: intrinsicPoPBandwidth,
   362  			gas.DBRead:    0,
   363  			gas.DBWrite:   0,
   364  			gas.Compute:   0, // TODO: Add compute complexity
   365  		}, nil
   366  	default:
   367  		return gas.Dimensions{}, errUnsupportedSigner
   368  	}
   369  }
   370  
   371  type complexityVisitor struct {
   372  	output gas.Dimensions
   373  }
   374  
   375  func (*complexityVisitor) AddDelegatorTx(*txs.AddDelegatorTx) error {
   376  	return ErrUnsupportedTx
   377  }
   378  
   379  func (*complexityVisitor) AddValidatorTx(*txs.AddValidatorTx) error {
   380  	return ErrUnsupportedTx
   381  }
   382  
   383  func (*complexityVisitor) AdvanceTimeTx(*txs.AdvanceTimeTx) error {
   384  	return ErrUnsupportedTx
   385  }
   386  
   387  func (*complexityVisitor) RewardValidatorTx(*txs.RewardValidatorTx) error {
   388  	return ErrUnsupportedTx
   389  }
   390  
   391  func (*complexityVisitor) TransformSubnetTx(*txs.TransformSubnetTx) error {
   392  	return ErrUnsupportedTx
   393  }
   394  
   395  func (c *complexityVisitor) AddPermissionlessValidatorTx(tx *txs.AddPermissionlessValidatorTx) error {
   396  	// TODO: Should we include additional complexity for subnets?
   397  	baseTxComplexity, err := baseTxComplexity(&tx.BaseTx)
   398  	if err != nil {
   399  		return err
   400  	}
   401  	signerComplexity, err := SignerComplexity(tx.Signer)
   402  	if err != nil {
   403  		return err
   404  	}
   405  	outputsComplexity, err := OutputComplexity(tx.StakeOuts...)
   406  	if err != nil {
   407  		return err
   408  	}
   409  	validatorOwnerComplexity, err := OwnerComplexity(tx.ValidatorRewardsOwner)
   410  	if err != nil {
   411  		return err
   412  	}
   413  	delegatorOwnerComplexity, err := OwnerComplexity(tx.DelegatorRewardsOwner)
   414  	if err != nil {
   415  		return err
   416  	}
   417  	c.output, err = IntrinsicAddPermissionlessValidatorTxComplexities.Add(
   418  		&baseTxComplexity,
   419  		&signerComplexity,
   420  		&outputsComplexity,
   421  		&validatorOwnerComplexity,
   422  		&delegatorOwnerComplexity,
   423  	)
   424  	return err
   425  }
   426  
   427  func (c *complexityVisitor) AddPermissionlessDelegatorTx(tx *txs.AddPermissionlessDelegatorTx) error {
   428  	// TODO: Should we include additional complexity for subnets?
   429  	baseTxComplexity, err := baseTxComplexity(&tx.BaseTx)
   430  	if err != nil {
   431  		return err
   432  	}
   433  	ownerComplexity, err := OwnerComplexity(tx.DelegationRewardsOwner)
   434  	if err != nil {
   435  		return err
   436  	}
   437  	outputsComplexity, err := OutputComplexity(tx.StakeOuts...)
   438  	if err != nil {
   439  		return err
   440  	}
   441  	c.output, err = IntrinsicAddPermissionlessDelegatorTxComplexities.Add(
   442  		&baseTxComplexity,
   443  		&ownerComplexity,
   444  		&outputsComplexity,
   445  	)
   446  	return err
   447  }
   448  
   449  func (c *complexityVisitor) AddSubnetValidatorTx(tx *txs.AddSubnetValidatorTx) error {
   450  	baseTxComplexity, err := baseTxComplexity(&tx.BaseTx)
   451  	if err != nil {
   452  		return err
   453  	}
   454  	authComplexity, err := AuthComplexity(tx.SubnetAuth)
   455  	if err != nil {
   456  		return err
   457  	}
   458  	c.output, err = IntrinsicAddSubnetValidatorTxComplexities.Add(
   459  		&baseTxComplexity,
   460  		&authComplexity,
   461  	)
   462  	return err
   463  }
   464  
   465  func (c *complexityVisitor) BaseTx(tx *txs.BaseTx) error {
   466  	baseTxComplexity, err := baseTxComplexity(tx)
   467  	if err != nil {
   468  		return err
   469  	}
   470  	c.output, err = IntrinsicBaseTxComplexities.Add(&baseTxComplexity)
   471  	return err
   472  }
   473  
   474  func (c *complexityVisitor) CreateChainTx(tx *txs.CreateChainTx) error {
   475  	bandwidth, err := math.Mul(uint64(len(tx.FxIDs)), ids.IDLen)
   476  	if err != nil {
   477  		return err
   478  	}
   479  	bandwidth, err = math.Add(bandwidth, uint64(len(tx.ChainName)))
   480  	if err != nil {
   481  		return err
   482  	}
   483  	bandwidth, err = math.Add(bandwidth, uint64(len(tx.GenesisData)))
   484  	if err != nil {
   485  		return err
   486  	}
   487  	dynamicComplexity := gas.Dimensions{
   488  		gas.Bandwidth: bandwidth,
   489  		gas.DBRead:    0,
   490  		gas.DBWrite:   0,
   491  		gas.Compute:   0,
   492  	}
   493  
   494  	baseTxComplexity, err := baseTxComplexity(&tx.BaseTx)
   495  	if err != nil {
   496  		return err
   497  	}
   498  	authComplexity, err := AuthComplexity(tx.SubnetAuth)
   499  	if err != nil {
   500  		return err
   501  	}
   502  	c.output, err = IntrinsicCreateChainTxComplexities.Add(
   503  		&dynamicComplexity,
   504  		&baseTxComplexity,
   505  		&authComplexity,
   506  	)
   507  	return err
   508  }
   509  
   510  func (c *complexityVisitor) CreateSubnetTx(tx *txs.CreateSubnetTx) error {
   511  	baseTxComplexity, err := baseTxComplexity(&tx.BaseTx)
   512  	if err != nil {
   513  		return err
   514  	}
   515  	ownerComplexity, err := OwnerComplexity(tx.Owner)
   516  	if err != nil {
   517  		return err
   518  	}
   519  	c.output, err = IntrinsicCreateSubnetTxComplexities.Add(
   520  		&baseTxComplexity,
   521  		&ownerComplexity,
   522  	)
   523  	return err
   524  }
   525  
   526  func (c *complexityVisitor) ExportTx(tx *txs.ExportTx) error {
   527  	baseTxComplexity, err := baseTxComplexity(&tx.BaseTx)
   528  	if err != nil {
   529  		return err
   530  	}
   531  	// TODO: Should exported outputs be more complex?
   532  	outputsComplexity, err := OutputComplexity(tx.ExportedOutputs...)
   533  	if err != nil {
   534  		return err
   535  	}
   536  	c.output, err = IntrinsicExportTxComplexities.Add(
   537  		&baseTxComplexity,
   538  		&outputsComplexity,
   539  	)
   540  	return err
   541  }
   542  
   543  func (c *complexityVisitor) ImportTx(tx *txs.ImportTx) error {
   544  	baseTxComplexity, err := baseTxComplexity(&tx.BaseTx)
   545  	if err != nil {
   546  		return err
   547  	}
   548  	// TODO: Should imported inputs be more complex?
   549  	inputsComplexity, err := InputComplexity(tx.ImportedInputs...)
   550  	if err != nil {
   551  		return err
   552  	}
   553  	c.output, err = IntrinsicImportTxComplexities.Add(
   554  		&baseTxComplexity,
   555  		&inputsComplexity,
   556  	)
   557  	return err
   558  }
   559  
   560  func (c *complexityVisitor) RemoveSubnetValidatorTx(tx *txs.RemoveSubnetValidatorTx) error {
   561  	baseTxComplexity, err := baseTxComplexity(&tx.BaseTx)
   562  	if err != nil {
   563  		return err
   564  	}
   565  	authComplexity, err := AuthComplexity(tx.SubnetAuth)
   566  	if err != nil {
   567  		return err
   568  	}
   569  	c.output, err = IntrinsicRemoveSubnetValidatorTxComplexities.Add(
   570  		&baseTxComplexity,
   571  		&authComplexity,
   572  	)
   573  	return err
   574  }
   575  
   576  func (c *complexityVisitor) TransferSubnetOwnershipTx(tx *txs.TransferSubnetOwnershipTx) error {
   577  	baseTxComplexity, err := baseTxComplexity(&tx.BaseTx)
   578  	if err != nil {
   579  		return err
   580  	}
   581  	authComplexity, err := AuthComplexity(tx.SubnetAuth)
   582  	if err != nil {
   583  		return err
   584  	}
   585  	ownerComplexity, err := OwnerComplexity(tx.Owner)
   586  	if err != nil {
   587  		return err
   588  	}
   589  	c.output, err = IntrinsicTransferSubnetOwnershipTxComplexities.Add(
   590  		&baseTxComplexity,
   591  		&authComplexity,
   592  		&ownerComplexity,
   593  	)
   594  	return err
   595  }
   596  
   597  func baseTxComplexity(tx *txs.BaseTx) (gas.Dimensions, error) {
   598  	outputsComplexity, err := OutputComplexity(tx.Outs...)
   599  	if err != nil {
   600  		return gas.Dimensions{}, err
   601  	}
   602  	inputsComplexity, err := InputComplexity(tx.Ins...)
   603  	if err != nil {
   604  		return gas.Dimensions{}, err
   605  	}
   606  	complexity, err := outputsComplexity.Add(&inputsComplexity)
   607  	if err != nil {
   608  		return gas.Dimensions{}, err
   609  	}
   610  	complexity[gas.Bandwidth], err = math.Add(
   611  		complexity[gas.Bandwidth],
   612  		uint64(len(tx.Memo)),
   613  	)
   614  	return complexity, err
   615  }