github.com/koko1123/flow-go-1@v0.29.6/engine/execution/testutil/fixtures.go (about) 1 package testutil 2 3 import ( 4 "crypto/rand" 5 "encoding/hex" 6 "errors" 7 "fmt" 8 "testing" 9 10 "github.com/onflow/cadence" 11 jsoncdc "github.com/onflow/cadence/encoding/json" 12 "github.com/stretchr/testify/require" 13 14 "github.com/koko1123/flow-go-1/engine/execution/utils" 15 "github.com/koko1123/flow-go-1/fvm" 16 "github.com/koko1123/flow-go-1/fvm/derived" 17 "github.com/koko1123/flow-go-1/fvm/state" 18 fvmUtils "github.com/koko1123/flow-go-1/fvm/utils" 19 "github.com/koko1123/flow-go-1/model/flow" 20 "github.com/koko1123/flow-go-1/module/epochs" 21 "github.com/koko1123/flow-go-1/utils/unittest" 22 "github.com/onflow/flow-go/crypto" 23 "github.com/onflow/flow-go/crypto/hash" 24 ) 25 26 func CreateContractDeploymentTransaction(contractName string, contract string, authorizer flow.Address, chain flow.Chain) *flow.TransactionBody { 27 28 encoded := hex.EncodeToString([]byte(contract)) 29 30 script := []byte(fmt.Sprintf(`transaction { 31 prepare(signer: AuthAccount, service: AuthAccount) { 32 signer.contracts.add(name: "%s", code: "%s".decodeHex()) 33 } 34 }`, contractName, encoded)) 35 36 txBody := flow.NewTransactionBody(). 37 SetScript(script). 38 AddAuthorizer(authorizer). 39 AddAuthorizer(chain.ServiceAddress()) 40 41 return txBody 42 } 43 44 func UpdateContractDeploymentTransaction(contractName string, contract string, authorizer flow.Address, chain flow.Chain) *flow.TransactionBody { 45 encoded := hex.EncodeToString([]byte(contract)) 46 47 return flow.NewTransactionBody(). 48 SetScript([]byte(fmt.Sprintf(`transaction { 49 prepare(signer: AuthAccount, service: AuthAccount) { 50 signer.contracts.update__experimental(name: "%s", code: "%s".decodeHex()) 51 } 52 }`, contractName, encoded)), 53 ). 54 AddAuthorizer(authorizer). 55 AddAuthorizer(chain.ServiceAddress()) 56 } 57 58 func UpdateContractUnathorizedDeploymentTransaction(contractName string, contract string, authorizer flow.Address) *flow.TransactionBody { 59 encoded := hex.EncodeToString([]byte(contract)) 60 61 return flow.NewTransactionBody(). 62 SetScript([]byte(fmt.Sprintf(`transaction { 63 prepare(signer: AuthAccount) { 64 signer.contracts.update__experimental(name: "%s", code: "%s".decodeHex()) 65 } 66 }`, contractName, encoded)), 67 ). 68 AddAuthorizer(authorizer) 69 } 70 71 func RemoveContractDeploymentTransaction(contractName string, authorizer flow.Address, chain flow.Chain) *flow.TransactionBody { 72 return flow.NewTransactionBody(). 73 SetScript([]byte(fmt.Sprintf(`transaction { 74 prepare(signer: AuthAccount, service: AuthAccount) { 75 signer.contracts.remove(name: "%s") 76 } 77 }`, contractName)), 78 ). 79 AddAuthorizer(authorizer). 80 AddAuthorizer(chain.ServiceAddress()) 81 } 82 83 func RemoveContractUnathorizedDeploymentTransaction(contractName string, authorizer flow.Address) *flow.TransactionBody { 84 return flow.NewTransactionBody(). 85 SetScript([]byte(fmt.Sprintf(`transaction { 86 prepare(signer: AuthAccount) { 87 signer.contracts.remove(name: "%s") 88 } 89 }`, contractName)), 90 ). 91 AddAuthorizer(authorizer) 92 } 93 94 func CreateUnauthorizedContractDeploymentTransaction(contractName string, contract string, authorizer flow.Address) *flow.TransactionBody { 95 encoded := hex.EncodeToString([]byte(contract)) 96 97 return flow.NewTransactionBody(). 98 SetScript([]byte(fmt.Sprintf(`transaction { 99 prepare(signer: AuthAccount) { 100 signer.contracts.add(name: "%s", code: "%s".decodeHex()) 101 } 102 }`, contractName, encoded)), 103 ). 104 AddAuthorizer(authorizer) 105 } 106 107 func SignPayload( 108 tx *flow.TransactionBody, 109 account flow.Address, 110 privateKey flow.AccountPrivateKey, 111 ) error { 112 hasher, err := utils.NewHasher(privateKey.HashAlgo) 113 if err != nil { 114 return fmt.Errorf("failed to create hasher: %w", err) 115 } 116 117 err = tx.SignPayload(account, 0, privateKey.PrivateKey, hasher) 118 119 if err != nil { 120 return fmt.Errorf("failed to sign transaction: %w", err) 121 } 122 123 return nil 124 } 125 126 func SignEnvelope(tx *flow.TransactionBody, account flow.Address, privateKey flow.AccountPrivateKey) error { 127 hasher, err := utils.NewHasher(privateKey.HashAlgo) 128 if err != nil { 129 return fmt.Errorf("failed to create hasher: %w", err) 130 } 131 132 err = tx.SignEnvelope(account, 0, privateKey.PrivateKey, hasher) 133 134 if err != nil { 135 return fmt.Errorf("failed to sign transaction: %w", err) 136 } 137 138 return nil 139 } 140 141 func SignTransaction( 142 tx *flow.TransactionBody, 143 address flow.Address, 144 privateKey flow.AccountPrivateKey, 145 seqNum uint64, 146 ) error { 147 tx.SetProposalKey(address, 0, seqNum) 148 tx.SetPayer(address) 149 return SignEnvelope(tx, address, privateKey) 150 } 151 152 func SignTransactionAsServiceAccount(tx *flow.TransactionBody, seqNum uint64, chain flow.Chain) error { 153 return SignTransaction(tx, chain.ServiceAddress(), unittest.ServiceAccountPrivateKey, seqNum) 154 } 155 156 // GenerateAccountPrivateKeys generates a number of private keys. 157 func GenerateAccountPrivateKeys(numberOfPrivateKeys int) ([]flow.AccountPrivateKey, error) { 158 var privateKeys []flow.AccountPrivateKey 159 for i := 0; i < numberOfPrivateKeys; i++ { 160 pk, err := GenerateAccountPrivateKey() 161 if err != nil { 162 return nil, err 163 } 164 privateKeys = append(privateKeys, pk) 165 } 166 167 return privateKeys, nil 168 } 169 170 // GenerateAccountPrivateKey generates a private key. 171 func GenerateAccountPrivateKey() (flow.AccountPrivateKey, error) { 172 seed := make([]byte, crypto.KeyGenSeedMinLenECDSAP256) 173 _, err := rand.Read(seed) 174 if err != nil { 175 return flow.AccountPrivateKey{}, err 176 } 177 privateKey, err := crypto.GeneratePrivateKey(crypto.ECDSAP256, seed) 178 if err != nil { 179 return flow.AccountPrivateKey{}, err 180 } 181 pk := flow.AccountPrivateKey{ 182 PrivateKey: privateKey, 183 SignAlgo: crypto.ECDSAP256, 184 HashAlgo: hash.SHA2_256, 185 } 186 return pk, nil 187 } 188 189 // CreateAccounts inserts accounts into the ledger using the provided private keys. 190 func CreateAccounts( 191 vm fvm.VM, 192 view state.View, 193 derivedBlockData *derived.DerivedBlockData, 194 privateKeys []flow.AccountPrivateKey, 195 chain flow.Chain, 196 ) ([]flow.Address, error) { 197 return CreateAccountsWithSimpleAddresses(vm, view, derivedBlockData, privateKeys, chain) 198 } 199 200 func CreateAccountsWithSimpleAddresses( 201 vm fvm.VM, 202 view state.View, 203 derivedBlockData *derived.DerivedBlockData, 204 privateKeys []flow.AccountPrivateKey, 205 chain flow.Chain, 206 ) ([]flow.Address, error) { 207 ctx := fvm.NewContext( 208 fvm.WithChain(chain), 209 fvm.WithAuthorizationChecksEnabled(false), 210 fvm.WithSequenceNumberCheckAndIncrementEnabled(false), 211 fvm.WithDerivedBlockData(derivedBlockData), 212 ) 213 214 var accounts []flow.Address 215 216 scriptTemplate := ` 217 transaction(publicKey: [UInt8]) { 218 prepare(signer: AuthAccount) { 219 let acct = AuthAccount(payer: signer) 220 let publicKey2 = PublicKey( 221 publicKey: publicKey, 222 signatureAlgorithm: SignatureAlgorithm.%s 223 ) 224 acct.keys.add( 225 publicKey: publicKey2, 226 hashAlgorithm: HashAlgorithm.%s, 227 weight: %d.0 228 ) 229 } 230 }` 231 232 serviceAddress := chain.ServiceAddress() 233 234 for _, privateKey := range privateKeys { 235 accountKey := privateKey.PublicKey(fvm.AccountKeyWeightThreshold) 236 encPublicKey := accountKey.PublicKey.Encode() 237 cadPublicKey := BytesToCadenceArray(encPublicKey) 238 encCadPublicKey, _ := jsoncdc.Encode(cadPublicKey) 239 240 script := []byte( 241 fmt.Sprintf( 242 scriptTemplate, 243 accountKey.SignAlgo.String(), 244 accountKey.HashAlgo.String(), 245 accountKey.Weight, 246 ), 247 ) 248 249 txBody := flow.NewTransactionBody(). 250 SetScript(script). 251 AddArgument(encCadPublicKey). 252 AddAuthorizer(serviceAddress) 253 254 tx := fvm.Transaction( 255 txBody, 256 derivedBlockData.NextTxIndexForTestingOnly()) 257 err := vm.Run(ctx, tx, view) 258 if err != nil { 259 return nil, err 260 } 261 262 if tx.Err != nil { 263 return nil, fmt.Errorf("failed to create account: %w", tx.Err) 264 } 265 266 var addr flow.Address 267 268 for _, event := range tx.Events { 269 if event.Type == flow.EventAccountCreated { 270 data, err := jsoncdc.Decode(nil, event.Payload) 271 if err != nil { 272 return nil, errors.New("error decoding events") 273 } 274 addr = flow.Address(data.(cadence.Event).Fields[0].(cadence.Address)) 275 break 276 } 277 } 278 if addr == flow.EmptyAddress { 279 return nil, errors.New("no account creation event emitted") 280 } 281 accounts = append(accounts, addr) 282 } 283 284 return accounts, nil 285 } 286 287 func RootBootstrappedLedger(vm fvm.VM, ctx fvm.Context, additionalOptions ...fvm.BootstrapProcedureOption) state.View { 288 view := fvmUtils.NewSimpleView() 289 290 // set 0 clusters to pass n_collectors >= n_clusters check 291 epochConfig := epochs.DefaultEpochConfig() 292 epochConfig.NumCollectorClusters = 0 293 294 options := []fvm.BootstrapProcedureOption{ 295 fvm.WithInitialTokenSupply(unittest.GenesisTokenSupply), 296 fvm.WithEpochConfig(epochConfig), 297 } 298 299 options = append(options, additionalOptions...) 300 301 bootstrap := fvm.Bootstrap( 302 unittest.ServiceAccountPublicKey, 303 options..., 304 ) 305 306 _ = vm.Run(ctx, bootstrap, view) 307 return view 308 } 309 310 func BytesToCadenceArray(l []byte) cadence.Array { 311 values := make([]cadence.Value, len(l)) 312 for i, b := range l { 313 values[i] = cadence.NewUInt8(b) 314 } 315 316 return cadence.NewArray(values).WithType(cadence.NewVariableSizedArrayType(cadence.NewUInt8Type())) 317 } 318 319 // CreateAccountCreationTransaction creates a transaction which will create a new account. 320 // 321 // This function returns a randomly generated private key and the transaction. 322 func CreateAccountCreationTransaction(t testing.TB, chain flow.Chain) (flow.AccountPrivateKey, *flow.TransactionBody) { 323 accountKey, err := GenerateAccountPrivateKey() 324 require.NoError(t, err) 325 encPublicKey := accountKey.PublicKey(1000).PublicKey.Encode() 326 cadPublicKey := BytesToCadenceArray(encPublicKey) 327 encCadPublicKey, err := jsoncdc.Encode(cadPublicKey) 328 require.NoError(t, err) 329 330 // define the cadence script 331 script := fmt.Sprintf(` 332 transaction(publicKey: [UInt8]) { 333 prepare(signer: AuthAccount) { 334 let acct = AuthAccount(payer: signer) 335 let publicKey2 = PublicKey( 336 publicKey: publicKey, 337 signatureAlgorithm: SignatureAlgorithm.%s 338 ) 339 acct.keys.add( 340 publicKey: publicKey2, 341 hashAlgorithm: HashAlgorithm.%s, 342 weight: 1000.0 343 ) 344 } 345 }`, 346 accountKey.SignAlgo.String(), 347 accountKey.HashAlgo.String(), 348 ) 349 350 // create the transaction to create the account 351 tx := flow.NewTransactionBody(). 352 SetScript([]byte(script)). 353 AddArgument(encCadPublicKey). 354 AddAuthorizer(chain.ServiceAddress()) 355 356 return accountKey, tx 357 } 358 359 // CreateMultiAccountCreationTransaction creates a transaction which will create many (n) new account. 360 // 361 // This function returns a randomly generated private key and the transaction. 362 func CreateMultiAccountCreationTransaction(t *testing.T, chain flow.Chain, n int) (flow.AccountPrivateKey, *flow.TransactionBody) { 363 accountKey, err := GenerateAccountPrivateKey() 364 require.NoError(t, err) 365 encPublicKey := accountKey.PublicKey(1000).PublicKey.Encode() 366 cadPublicKey := BytesToCadenceArray(encPublicKey) 367 encCadPublicKey, err := jsoncdc.Encode(cadPublicKey) 368 require.NoError(t, err) 369 370 // define the cadence script 371 script := fmt.Sprintf(` 372 transaction(publicKey: [UInt8]) { 373 prepare(signer: AuthAccount) { 374 var i = 0 375 while i < %d { 376 let account = AuthAccount(payer: signer) 377 let publicKey2 = PublicKey( 378 publicKey: publicKey, 379 signatureAlgorithm: SignatureAlgorithm.%s 380 ) 381 account.keys.add( 382 publicKey: publicKey2, 383 hashAlgorithm: HashAlgorithm.%s, 384 weight: 1000.0 385 ) 386 i = i + 1 387 } 388 } 389 }`, 390 n, 391 accountKey.SignAlgo.String(), 392 accountKey.HashAlgo.String(), 393 ) 394 395 // create the transaction to create the account 396 tx := flow.NewTransactionBody(). 397 SetScript([]byte(script)). 398 AddArgument(encCadPublicKey). 399 AddAuthorizer(chain.ServiceAddress()) 400 401 return accountKey, tx 402 } 403 404 // CreateAddAnAccountKeyMultipleTimesTransaction generates a tx that adds a key several times to an account. 405 // this can be used to exhaust an account's storage. 406 func CreateAddAnAccountKeyMultipleTimesTransaction(t *testing.T, accountKey *flow.AccountPrivateKey, counts int) *flow.TransactionBody { 407 script := []byte(fmt.Sprintf(` 408 transaction(counts: Int, key: [UInt8]) { 409 prepare(signer: AuthAccount) { 410 var i = 0 411 while i < counts { 412 i = i + 1 413 let publicKey2 = PublicKey( 414 publicKey: key, 415 signatureAlgorithm: SignatureAlgorithm.%s 416 ) 417 signer.keys.add( 418 publicKey: publicKey2, 419 hashAlgorithm: HashAlgorithm.%s, 420 weight: 1000.0 421 ) 422 } 423 } 424 } 425 `, accountKey.SignAlgo.String(), accountKey.HashAlgo.String())) 426 427 arg1, err := jsoncdc.Encode(cadence.NewInt(counts)) 428 require.NoError(t, err) 429 430 encPublicKey := accountKey.PublicKey(1000).PublicKey.Encode() 431 cadPublicKey := BytesToCadenceArray(encPublicKey) 432 arg2, err := jsoncdc.Encode(cadPublicKey) 433 require.NoError(t, err) 434 435 addKeysTx := &flow.TransactionBody{ 436 Script: script, 437 } 438 addKeysTx = addKeysTx.AddArgument(arg1).AddArgument(arg2) 439 return addKeysTx 440 } 441 442 // CreateAddAccountKeyTransaction generates a tx that adds a key to an account. 443 func CreateAddAccountKeyTransaction(t *testing.T, accountKey *flow.AccountPrivateKey) *flow.TransactionBody { 444 keyBytes := accountKey.PublicKey(1000).PublicKey.Encode() 445 446 script := []byte(` 447 transaction(key: [UInt8]) { 448 prepare(signer: AuthAccount) { 449 let acct = AuthAccount(payer: signer) 450 let publicKey2 = PublicKey( 451 publicKey: key, 452 signatureAlgorithm: SignatureAlgorithm.%s 453 ) 454 signer.keys.add( 455 publicKey: publicKey2, 456 hashAlgorithm: HashAlgorithm.%s, 457 weight: %d.0 458 ) 459 } 460 } 461 `) 462 463 arg, err := jsoncdc.Encode(bytesToCadenceArray(keyBytes)) 464 require.NoError(t, err) 465 466 addKeysTx := &flow.TransactionBody{ 467 Script: script, 468 } 469 addKeysTx = addKeysTx.AddArgument(arg) 470 471 return addKeysTx 472 } 473 474 func bytesToCadenceArray(l []byte) cadence.Array { 475 values := make([]cadence.Value, len(l)) 476 for i, b := range l { 477 values[i] = cadence.NewUInt8(b) 478 } 479 480 return cadence.NewArray(values) 481 }