github.com/MetalBlockchain/metalgo@v1.11.9/vms/platformvm/txs/executor/create_chain_test.go (about) 1 // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package executor 5 6 import ( 7 "context" 8 "testing" 9 "time" 10 11 "github.com/stretchr/testify/require" 12 13 "github.com/MetalBlockchain/metalgo/database" 14 "github.com/MetalBlockchain/metalgo/ids" 15 "github.com/MetalBlockchain/metalgo/utils/constants" 16 "github.com/MetalBlockchain/metalgo/utils/crypto/secp256k1" 17 "github.com/MetalBlockchain/metalgo/utils/hashing" 18 "github.com/MetalBlockchain/metalgo/utils/set" 19 "github.com/MetalBlockchain/metalgo/utils/units" 20 "github.com/MetalBlockchain/metalgo/vms/platformvm/state" 21 "github.com/MetalBlockchain/metalgo/vms/platformvm/txs" 22 "github.com/MetalBlockchain/metalgo/vms/platformvm/txs/txstest" 23 "github.com/MetalBlockchain/metalgo/vms/platformvm/utxo" 24 "github.com/MetalBlockchain/metalgo/vms/secp256k1fx" 25 26 walletsigner "github.com/MetalBlockchain/metalgo/wallet/chain/p/signer" 27 ) 28 29 // Ensure Execute fails when there are not enough control sigs 30 func TestCreateChainTxInsufficientControlSigs(t *testing.T) { 31 require := require.New(t) 32 env := newEnvironment(t, banff) 33 env.ctx.Lock.Lock() 34 defer env.ctx.Lock.Unlock() 35 36 builder, signer := env.factory.NewWallet(preFundedKeys[0], preFundedKeys[1]) 37 utx, err := builder.NewCreateChainTx( 38 testSubnet1.ID(), 39 nil, 40 constants.AVMID, 41 nil, 42 "chain name", 43 ) 44 require.NoError(err) 45 tx, err := walletsigner.SignUnsigned(context.Background(), signer, utx) 46 require.NoError(err) 47 48 // Remove a signature 49 tx.Creds[0].(*secp256k1fx.Credential).Sigs = tx.Creds[0].(*secp256k1fx.Credential).Sigs[1:] 50 51 stateDiff, err := state.NewDiff(lastAcceptedID, env) 52 require.NoError(err) 53 54 executor := StandardTxExecutor{ 55 Backend: &env.backend, 56 State: stateDiff, 57 Tx: tx, 58 } 59 err = tx.Unsigned.Visit(&executor) 60 require.ErrorIs(err, errUnauthorizedSubnetModification) 61 } 62 63 // Ensure Execute fails when an incorrect control signature is given 64 func TestCreateChainTxWrongControlSig(t *testing.T) { 65 require := require.New(t) 66 env := newEnvironment(t, banff) 67 env.ctx.Lock.Lock() 68 defer env.ctx.Lock.Unlock() 69 70 builder, signer := env.factory.NewWallet(testSubnet1ControlKeys[0], testSubnet1ControlKeys[1]) 71 utx, err := builder.NewCreateChainTx( 72 testSubnet1.ID(), 73 nil, 74 constants.AVMID, 75 nil, 76 "chain name", 77 ) 78 require.NoError(err) 79 tx, err := walletsigner.SignUnsigned(context.Background(), signer, utx) 80 require.NoError(err) 81 82 // Generate new, random key to sign tx with 83 key, err := secp256k1.NewPrivateKey() 84 require.NoError(err) 85 86 // Replace a valid signature with one from another key 87 sig, err := key.SignHash(hashing.ComputeHash256(tx.Unsigned.Bytes())) 88 require.NoError(err) 89 copy(tx.Creds[0].(*secp256k1fx.Credential).Sigs[0][:], sig) 90 91 stateDiff, err := state.NewDiff(lastAcceptedID, env) 92 require.NoError(err) 93 94 executor := StandardTxExecutor{ 95 Backend: &env.backend, 96 State: stateDiff, 97 Tx: tx, 98 } 99 err = tx.Unsigned.Visit(&executor) 100 require.ErrorIs(err, errUnauthorizedSubnetModification) 101 } 102 103 // Ensure Execute fails when the Subnet the blockchain specifies as 104 // its validator set doesn't exist 105 func TestCreateChainTxNoSuchSubnet(t *testing.T) { 106 require := require.New(t) 107 env := newEnvironment(t, banff) 108 env.ctx.Lock.Lock() 109 defer env.ctx.Lock.Unlock() 110 111 builder, signer := env.factory.NewWallet(testSubnet1ControlKeys[0], testSubnet1ControlKeys[1]) 112 utx, err := builder.NewCreateChainTx( 113 testSubnet1.ID(), 114 nil, 115 constants.AVMID, 116 nil, 117 "chain name", 118 ) 119 require.NoError(err) 120 tx, err := walletsigner.SignUnsigned(context.Background(), signer, utx) 121 require.NoError(err) 122 123 tx.Unsigned.(*txs.CreateChainTx).SubnetID = ids.GenerateTestID() 124 125 stateDiff, err := state.NewDiff(lastAcceptedID, env) 126 require.NoError(err) 127 128 executor := StandardTxExecutor{ 129 Backend: &env.backend, 130 State: stateDiff, 131 Tx: tx, 132 } 133 err = tx.Unsigned.Visit(&executor) 134 require.ErrorIs(err, database.ErrNotFound) 135 } 136 137 // Ensure valid tx passes semanticVerify 138 func TestCreateChainTxValid(t *testing.T) { 139 require := require.New(t) 140 env := newEnvironment(t, banff) 141 env.ctx.Lock.Lock() 142 defer env.ctx.Lock.Unlock() 143 144 builder, signer := env.factory.NewWallet(testSubnet1ControlKeys[0], testSubnet1ControlKeys[1]) 145 utx, err := builder.NewCreateChainTx( 146 testSubnet1.ID(), 147 nil, 148 constants.AVMID, 149 nil, 150 "chain name", 151 ) 152 require.NoError(err) 153 tx, err := walletsigner.SignUnsigned(context.Background(), signer, utx) 154 require.NoError(err) 155 156 stateDiff, err := state.NewDiff(lastAcceptedID, env) 157 require.NoError(err) 158 159 executor := StandardTxExecutor{ 160 Backend: &env.backend, 161 State: stateDiff, 162 Tx: tx, 163 } 164 require.NoError(tx.Unsigned.Visit(&executor)) 165 } 166 167 func TestCreateChainTxAP3FeeChange(t *testing.T) { 168 ap3Time := defaultGenesisTime.Add(time.Hour) 169 tests := []struct { 170 name string 171 time time.Time 172 fee uint64 173 expectedError error 174 }{ 175 { 176 name: "pre-fork - correctly priced", 177 time: defaultGenesisTime, 178 fee: 0, 179 expectedError: nil, 180 }, 181 { 182 name: "post-fork - incorrectly priced", 183 time: ap3Time, 184 fee: 100*defaultTxFee - 1*units.NanoAvax, 185 expectedError: utxo.ErrInsufficientUnlockedFunds, 186 }, 187 { 188 name: "post-fork - correctly priced", 189 time: ap3Time, 190 fee: 100 * defaultTxFee, 191 expectedError: nil, 192 }, 193 } 194 for _, test := range tests { 195 t.Run(test.name, func(t *testing.T) { 196 require := require.New(t) 197 198 env := newEnvironment(t, banff) 199 env.config.UpgradeConfig.ApricotPhase3Time = ap3Time 200 201 addrs := set.NewSet[ids.ShortID](len(preFundedKeys)) 202 for _, key := range preFundedKeys { 203 addrs.Add(key.Address()) 204 } 205 206 env.state.SetTimestamp(test.time) // to duly set fee 207 208 cfg := *env.config 209 210 cfg.StaticFeeConfig.CreateBlockchainTxFee = test.fee 211 factory := txstest.NewWalletFactory(env.ctx, &cfg, env.state) 212 builder, signer := factory.NewWallet(preFundedKeys...) 213 utx, err := builder.NewCreateChainTx( 214 testSubnet1.ID(), 215 nil, 216 ids.GenerateTestID(), 217 nil, 218 "", 219 ) 220 require.NoError(err) 221 tx, err := walletsigner.SignUnsigned(context.Background(), signer, utx) 222 require.NoError(err) 223 224 stateDiff, err := state.NewDiff(lastAcceptedID, env) 225 require.NoError(err) 226 227 stateDiff.SetTimestamp(test.time) 228 229 executor := StandardTxExecutor{ 230 Backend: &env.backend, 231 State: stateDiff, 232 Tx: tx, 233 } 234 err = tx.Unsigned.Visit(&executor) 235 require.ErrorIs(err, test.expectedError) 236 }) 237 } 238 }