github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/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 "github.com/onflow/cadence/encoding/ccf" 12 jsoncdc "github.com/onflow/cadence/encoding/json" 13 "github.com/onflow/cadence/runtime/stdlib" 14 "github.com/stretchr/testify/mock" 15 "github.com/stretchr/testify/require" 16 17 "github.com/onflow/crypto" 18 "github.com/onflow/crypto/hash" 19 20 "github.com/onflow/flow-go/engine/execution" 21 "github.com/onflow/flow-go/engine/execution/utils" 22 "github.com/onflow/flow-go/fvm" 23 "github.com/onflow/flow-go/fvm/environment" 24 envMock "github.com/onflow/flow-go/fvm/environment/mock" 25 "github.com/onflow/flow-go/fvm/storage/snapshot" 26 "github.com/onflow/flow-go/ledger" 27 "github.com/onflow/flow-go/ledger/common/pathfinder" 28 "github.com/onflow/flow-go/ledger/complete" 29 "github.com/onflow/flow-go/model/flow" 30 "github.com/onflow/flow-go/module/epochs" 31 "github.com/onflow/flow-go/module/executiondatasync/execution_data" 32 "github.com/onflow/flow-go/state/protocol" 33 protocolMock "github.com/onflow/flow-go/state/protocol/mock" 34 "github.com/onflow/flow-go/utils/unittest" 35 ) 36 37 func CreateContractDeploymentTransaction(contractName string, contract string, authorizer flow.Address, chain flow.Chain) *flow.TransactionBody { 38 39 encoded := hex.EncodeToString([]byte(contract)) 40 41 script := []byte(fmt.Sprintf(`transaction { 42 prepare(signer: auth(AddContract) &Account, service: &Account) { 43 signer.contracts.add(name: "%s", code: "%s".decodeHex()) 44 } 45 }`, contractName, encoded)) 46 47 txBody := flow.NewTransactionBody(). 48 SetScript(script). 49 AddAuthorizer(authorizer). 50 AddAuthorizer(chain.ServiceAddress()) 51 52 return txBody 53 } 54 55 func UpdateContractDeploymentTransaction(contractName string, contract string, authorizer flow.Address, chain flow.Chain) *flow.TransactionBody { 56 encoded := hex.EncodeToString([]byte(contract)) 57 58 return flow.NewTransactionBody(). 59 SetScript([]byte(fmt.Sprintf(`transaction { 60 prepare(signer: auth(UpdateContract) &Account, service: &Account) { 61 signer.contracts.update(name: "%s", code: "%s".decodeHex()) 62 } 63 }`, contractName, encoded)), 64 ). 65 AddAuthorizer(authorizer). 66 AddAuthorizer(chain.ServiceAddress()) 67 } 68 69 func UpdateContractUnathorizedDeploymentTransaction(contractName string, contract string, authorizer flow.Address) *flow.TransactionBody { 70 encoded := hex.EncodeToString([]byte(contract)) 71 72 return flow.NewTransactionBody(). 73 SetScript([]byte(fmt.Sprintf(`transaction { 74 prepare(signer: auth(UpdateContract) &Account) { 75 signer.contracts.update(name: "%s", code: "%s".decodeHex()) 76 } 77 }`, contractName, encoded)), 78 ). 79 AddAuthorizer(authorizer) 80 } 81 82 func RemoveContractDeploymentTransaction(contractName string, authorizer flow.Address, chain flow.Chain) *flow.TransactionBody { 83 return flow.NewTransactionBody(). 84 SetScript([]byte(fmt.Sprintf(`transaction { 85 prepare(signer: auth(RemoveContract) &Account, service: &Account) { 86 signer.contracts.remove(name: "%s") 87 } 88 }`, contractName)), 89 ). 90 AddAuthorizer(authorizer). 91 AddAuthorizer(chain.ServiceAddress()) 92 } 93 94 func RemoveContractUnathorizedDeploymentTransaction(contractName string, authorizer flow.Address) *flow.TransactionBody { 95 return flow.NewTransactionBody(). 96 SetScript([]byte(fmt.Sprintf(`transaction { 97 prepare(signer: auth(RemoveContract) &Account) { 98 signer.contracts.remove(name: "%s") 99 } 100 }`, contractName)), 101 ). 102 AddAuthorizer(authorizer) 103 } 104 105 func CreateUnauthorizedContractDeploymentTransaction(contractName string, contract string, authorizer flow.Address) *flow.TransactionBody { 106 encoded := hex.EncodeToString([]byte(contract)) 107 108 return flow.NewTransactionBody(). 109 SetScript([]byte(fmt.Sprintf(`transaction { 110 prepare(signer: auth(AddContract) &Account) { 111 signer.contracts.add(name: "%s", code: "%s".decodeHex()) 112 } 113 }`, contractName, encoded)), 114 ). 115 AddAuthorizer(authorizer) 116 } 117 118 func SignPayload( 119 tx *flow.TransactionBody, 120 account flow.Address, 121 privateKey flow.AccountPrivateKey, 122 ) error { 123 hasher, err := utils.NewHasher(privateKey.HashAlgo) 124 if err != nil { 125 return fmt.Errorf("failed to create hasher: %w", err) 126 } 127 128 err = tx.SignPayload(account, 0, privateKey.PrivateKey, hasher) 129 130 if err != nil { 131 return fmt.Errorf("failed to sign transaction: %w", err) 132 } 133 134 return nil 135 } 136 137 func SignEnvelope(tx *flow.TransactionBody, account flow.Address, privateKey flow.AccountPrivateKey) error { 138 hasher, err := utils.NewHasher(privateKey.HashAlgo) 139 if err != nil { 140 return fmt.Errorf("failed to create hasher: %w", err) 141 } 142 143 err = tx.SignEnvelope(account, 0, privateKey.PrivateKey, hasher) 144 145 if err != nil { 146 return fmt.Errorf("failed to sign transaction: %w", err) 147 } 148 149 return nil 150 } 151 152 func SignTransaction( 153 tx *flow.TransactionBody, 154 address flow.Address, 155 privateKey flow.AccountPrivateKey, 156 seqNum uint64, 157 ) error { 158 tx.SetProposalKey(address, 0, seqNum) 159 tx.SetPayer(address) 160 return SignEnvelope(tx, address, privateKey) 161 } 162 163 func SignTransactionAsServiceAccount(tx *flow.TransactionBody, seqNum uint64, chain flow.Chain) error { 164 return SignTransaction(tx, chain.ServiceAddress(), unittest.ServiceAccountPrivateKey, seqNum) 165 } 166 167 // GenerateAccountPrivateKeys generates a number of private keys. 168 func GenerateAccountPrivateKeys(numberOfPrivateKeys int) ([]flow.AccountPrivateKey, error) { 169 var privateKeys []flow.AccountPrivateKey 170 for i := 0; i < numberOfPrivateKeys; i++ { 171 pk, err := GenerateAccountPrivateKey() 172 if err != nil { 173 return nil, err 174 } 175 privateKeys = append(privateKeys, pk) 176 } 177 178 return privateKeys, nil 179 } 180 181 // GenerateAccountPrivateKey generates a private key. 182 func GenerateAccountPrivateKey() (flow.AccountPrivateKey, error) { 183 seed := make([]byte, crypto.KeyGenSeedMinLen) 184 _, err := rand.Read(seed) 185 if err != nil { 186 return flow.AccountPrivateKey{}, err 187 } 188 privateKey, err := crypto.GeneratePrivateKey(crypto.ECDSAP256, seed) 189 if err != nil { 190 return flow.AccountPrivateKey{}, err 191 } 192 pk := flow.AccountPrivateKey{ 193 PrivateKey: privateKey, 194 SignAlgo: crypto.ECDSAP256, 195 HashAlgo: hash.SHA2_256, 196 } 197 return pk, nil 198 } 199 200 // CreateAccounts inserts accounts into the ledger using the provided private keys. 201 func CreateAccounts( 202 vm fvm.VM, 203 snapshotTree snapshot.SnapshotTree, 204 privateKeys []flow.AccountPrivateKey, 205 chain flow.Chain, 206 ) ( 207 snapshot.SnapshotTree, 208 []flow.Address, 209 error, 210 ) { 211 return CreateAccountsWithSimpleAddresses( 212 vm, 213 snapshotTree, 214 privateKeys, 215 chain) 216 } 217 218 func CreateAccountsWithSimpleAddresses( 219 vm fvm.VM, 220 snapshotTree snapshot.SnapshotTree, 221 privateKeys []flow.AccountPrivateKey, 222 chain flow.Chain, 223 ) ( 224 snapshot.SnapshotTree, 225 []flow.Address, 226 error, 227 ) { 228 ctx := fvm.NewContext( 229 fvm.WithChain(chain), 230 fvm.WithAuthorizationChecksEnabled(false), 231 fvm.WithSequenceNumberCheckAndIncrementEnabled(false), 232 ) 233 234 var accounts []flow.Address 235 236 scriptTemplate := ` 237 transaction(publicKey: [UInt8]) { 238 prepare(signer: auth(AddKey, BorrowValue) &Account) { 239 let acct = Account(payer: signer) 240 let publicKey2 = PublicKey( 241 publicKey: publicKey, 242 signatureAlgorithm: SignatureAlgorithm.%s 243 ) 244 acct.keys.add( 245 publicKey: publicKey2, 246 hashAlgorithm: HashAlgorithm.%s, 247 weight: %d.0 248 ) 249 } 250 }` 251 252 serviceAddress := chain.ServiceAddress() 253 254 for _, privateKey := range privateKeys { 255 accountKey := privateKey.PublicKey(fvm.AccountKeyWeightThreshold) 256 encPublicKey := accountKey.PublicKey.Encode() 257 cadPublicKey := BytesToCadenceArray(encPublicKey) 258 encCadPublicKey, _ := jsoncdc.Encode(cadPublicKey) 259 260 script := []byte( 261 fmt.Sprintf( 262 scriptTemplate, 263 accountKey.SignAlgo.String(), 264 accountKey.HashAlgo.String(), 265 accountKey.Weight, 266 ), 267 ) 268 269 txBody := flow.NewTransactionBody(). 270 SetScript(script). 271 AddArgument(encCadPublicKey). 272 AddAuthorizer(serviceAddress) 273 274 tx := fvm.Transaction(txBody, 0) 275 executionSnapshot, output, err := vm.Run(ctx, tx, snapshotTree) 276 if err != nil { 277 return snapshotTree, nil, err 278 } 279 280 if output.Err != nil { 281 return snapshotTree, nil, fmt.Errorf( 282 "failed to create account: %w", 283 output.Err) 284 } 285 286 snapshotTree = snapshotTree.Append(executionSnapshot) 287 288 var addr flow.Address 289 290 for _, event := range output.Events { 291 if event.Type == flow.EventAccountCreated { 292 data, err := ccf.Decode(nil, event.Payload) 293 if err != nil { 294 return snapshotTree, nil, errors.New("error decoding events") 295 } 296 297 event, ok := data.(cadence.Event) 298 if !ok { 299 return snapshotTree, nil, errors.New("error decoding events") 300 } 301 302 address := cadence.SearchFieldByName( 303 event, 304 stdlib.AccountEventAddressParameter.Identifier, 305 ).(cadence.Address) 306 307 addr = flow.ConvertAddress(address) 308 break 309 } 310 } 311 if addr == flow.EmptyAddress { 312 return snapshotTree, nil, errors.New( 313 "no account creation event emitted") 314 } 315 accounts = append(accounts, addr) 316 } 317 318 return snapshotTree, accounts, nil 319 } 320 321 func RootBootstrappedLedger( 322 vm fvm.VM, 323 ctx fvm.Context, 324 additionalOptions ...fvm.BootstrapProcedureOption, 325 ) snapshot.SnapshotTree { 326 // set 0 clusters to pass n_collectors >= n_clusters check 327 epochConfig := epochs.DefaultEpochConfig() 328 epochConfig.NumCollectorClusters = 0 329 330 options := []fvm.BootstrapProcedureOption{ 331 fvm.WithInitialTokenSupply(unittest.GenesisTokenSupply), 332 fvm.WithEpochConfig(epochConfig), 333 } 334 335 options = append(options, additionalOptions...) 336 337 bootstrap := fvm.Bootstrap( 338 unittest.ServiceAccountPublicKey, 339 options..., 340 ) 341 342 executionSnapshot, _, err := vm.Run(ctx, bootstrap, nil) 343 if err != nil { 344 panic(err) 345 } 346 return snapshot.NewSnapshotTree(nil).Append(executionSnapshot) 347 } 348 349 func BytesToCadenceArray(l []byte) cadence.Array { 350 values := make([]cadence.Value, len(l)) 351 for i, b := range l { 352 values[i] = cadence.NewUInt8(b) 353 } 354 355 return cadence.NewArray(values).WithType(cadence.NewVariableSizedArrayType(cadence.UInt8Type)) 356 } 357 358 // CreateAccountCreationTransaction creates a transaction which will create a new account. 359 // 360 // This function returns a randomly generated private key and the transaction. 361 func CreateAccountCreationTransaction(t testing.TB, chain flow.Chain) (flow.AccountPrivateKey, *flow.TransactionBody) { 362 accountKey, err := GenerateAccountPrivateKey() 363 require.NoError(t, err) 364 encPublicKey := accountKey.PublicKey(1000).PublicKey.Encode() 365 cadPublicKey := BytesToCadenceArray(encPublicKey) 366 encCadPublicKey, err := jsoncdc.Encode(cadPublicKey) 367 require.NoError(t, err) 368 369 // define the cadence script 370 script := fmt.Sprintf(` 371 transaction(publicKey: [UInt8]) { 372 prepare(signer: auth(AddKey, BorrowValue) &Account) { 373 let acct = Account(payer: signer) 374 let publicKey2 = PublicKey( 375 publicKey: publicKey, 376 signatureAlgorithm: SignatureAlgorithm.%s 377 ) 378 acct.keys.add( 379 publicKey: publicKey2, 380 hashAlgorithm: HashAlgorithm.%s, 381 weight: 1000.0 382 ) 383 } 384 }`, 385 accountKey.SignAlgo.String(), 386 accountKey.HashAlgo.String(), 387 ) 388 389 // create the transaction to create the account 390 tx := flow.NewTransactionBody(). 391 SetScript([]byte(script)). 392 AddArgument(encCadPublicKey). 393 AddAuthorizer(chain.ServiceAddress()) 394 395 return accountKey, tx 396 } 397 398 // CreateMultiAccountCreationTransaction creates a transaction which will create many (n) new account. 399 // 400 // This function returns a randomly generated private key and the transaction. 401 func CreateMultiAccountCreationTransaction(t *testing.T, chain flow.Chain, n int) (flow.AccountPrivateKey, *flow.TransactionBody) { 402 accountKey, err := GenerateAccountPrivateKey() 403 require.NoError(t, err) 404 encPublicKey := accountKey.PublicKey(1000).PublicKey.Encode() 405 cadPublicKey := BytesToCadenceArray(encPublicKey) 406 encCadPublicKey, err := jsoncdc.Encode(cadPublicKey) 407 require.NoError(t, err) 408 409 // define the cadence script 410 script := fmt.Sprintf(` 411 transaction(publicKey: [UInt8]) { 412 prepare(signer: auth(AddKey, BorrowValue) &Account) { 413 var i = 0 414 while i < %d { 415 let account = Account(payer: signer) 416 let publicKey2 = PublicKey( 417 publicKey: publicKey, 418 signatureAlgorithm: SignatureAlgorithm.%s 419 ) 420 account.keys.add( 421 publicKey: publicKey2, 422 hashAlgorithm: HashAlgorithm.%s, 423 weight: 1000.0 424 ) 425 i = i + 1 426 } 427 } 428 }`, 429 n, 430 accountKey.SignAlgo.String(), 431 accountKey.HashAlgo.String(), 432 ) 433 434 // create the transaction to create the account 435 tx := flow.NewTransactionBody(). 436 SetScript([]byte(script)). 437 AddArgument(encCadPublicKey). 438 AddAuthorizer(chain.ServiceAddress()) 439 440 return accountKey, tx 441 } 442 443 // CreateAddAnAccountKeyMultipleTimesTransaction generates a tx that adds a key several times to an account. 444 // this can be used to exhaust an account's storage. 445 func CreateAddAnAccountKeyMultipleTimesTransaction(t *testing.T, accountKey *flow.AccountPrivateKey, counts int) *flow.TransactionBody { 446 script := []byte(fmt.Sprintf(` 447 transaction(counts: Int, key: [UInt8]) { 448 prepare(signer: auth(AddKey) &Account) { 449 var i = 0 450 while i < counts { 451 i = i + 1 452 let publicKey2 = PublicKey( 453 publicKey: key, 454 signatureAlgorithm: SignatureAlgorithm.%s 455 ) 456 signer.keys.add( 457 publicKey: publicKey2, 458 hashAlgorithm: HashAlgorithm.%s, 459 weight: 1000.0 460 ) 461 } 462 } 463 } 464 `, accountKey.SignAlgo.String(), accountKey.HashAlgo.String())) 465 466 arg1, err := jsoncdc.Encode(cadence.NewInt(counts)) 467 require.NoError(t, err) 468 469 encPublicKey := accountKey.PublicKey(1000).PublicKey.Encode() 470 cadPublicKey := BytesToCadenceArray(encPublicKey) 471 arg2, err := jsoncdc.Encode(cadPublicKey) 472 require.NoError(t, err) 473 474 addKeysTx := &flow.TransactionBody{ 475 Script: script, 476 } 477 addKeysTx = addKeysTx.AddArgument(arg1).AddArgument(arg2) 478 return addKeysTx 479 } 480 481 // CreateAddAccountKeyTransaction generates a tx that adds a key to an account. 482 func CreateAddAccountKeyTransaction(t *testing.T, accountKey *flow.AccountPrivateKey) *flow.TransactionBody { 483 keyBytes := accountKey.PublicKey(1000).PublicKey.Encode() 484 485 script := []byte(` 486 transaction(key: [UInt8]) { 487 prepare(signer: auth(AddKey) &Account) { 488 let acct = Account(payer: signer) 489 let publicKey2 = PublicKey( 490 publicKey: key, 491 signatureAlgorithm: SignatureAlgorithm.%s 492 ) 493 signer.keys.add( 494 publicKey: publicKey2, 495 hashAlgorithm: HashAlgorithm.%s, 496 weight: %d.0 497 ) 498 } 499 } 500 `) 501 502 arg, err := jsoncdc.Encode(bytesToCadenceArray(keyBytes)) 503 require.NoError(t, err) 504 505 addKeysTx := &flow.TransactionBody{ 506 Script: script, 507 } 508 addKeysTx = addKeysTx.AddArgument(arg) 509 510 return addKeysTx 511 } 512 513 func bytesToCadenceArray(l []byte) cadence.Array { 514 values := make([]cadence.Value, len(l)) 515 for i, b := range l { 516 values[i] = cadence.NewUInt8(b) 517 } 518 519 return cadence.NewArray(values) 520 } 521 522 // TODO(ramtin): when we get rid of BlockExecutionData, this could move to the global unittest fixtures 523 // TrieUpdates are internal data to the ledger package and should not have leaked into 524 // packages like uploader in the first place 525 func ComputationResultFixture(t *testing.T) *execution.ComputationResult { 526 startState := unittest.StateCommitmentFixture() 527 update1, err := ledger.NewUpdate( 528 ledger.State(startState), 529 []ledger.Key{ 530 ledger.NewKey([]ledger.KeyPart{ledger.NewKeyPart(3, []byte{33})}), 531 ledger.NewKey([]ledger.KeyPart{ledger.NewKeyPart(1, []byte{11})}), 532 ledger.NewKey([]ledger.KeyPart{ledger.NewKeyPart(2, []byte{1, 1}), ledger.NewKeyPart(3, []byte{2, 5})}), 533 }, 534 []ledger.Value{ 535 []byte{21, 37}, 536 nil, 537 []byte{3, 3, 3, 3, 3}, 538 }, 539 ) 540 require.NoError(t, err) 541 542 trieUpdate1, err := pathfinder.UpdateToTrieUpdate(update1, complete.DefaultPathFinderVersion) 543 require.NoError(t, err) 544 545 update2, err := ledger.NewUpdate( 546 ledger.State(unittest.StateCommitmentFixture()), 547 []ledger.Key{}, 548 []ledger.Value{}, 549 ) 550 require.NoError(t, err) 551 552 trieUpdate2, err := pathfinder.UpdateToTrieUpdate(update2, complete.DefaultPathFinderVersion) 553 require.NoError(t, err) 554 555 update3, err := ledger.NewUpdate( 556 ledger.State(unittest.StateCommitmentFixture()), 557 []ledger.Key{ 558 ledger.NewKey([]ledger.KeyPart{ledger.NewKeyPart(9, []byte{6})}), 559 }, 560 []ledger.Value{ 561 []byte{21, 37}, 562 }, 563 ) 564 require.NoError(t, err) 565 566 trieUpdate3, err := pathfinder.UpdateToTrieUpdate(update3, complete.DefaultPathFinderVersion) 567 require.NoError(t, err) 568 569 update4, err := ledger.NewUpdate( 570 ledger.State(unittest.StateCommitmentFixture()), 571 []ledger.Key{ 572 ledger.NewKey([]ledger.KeyPart{ledger.NewKeyPart(9, []byte{6})}), 573 }, 574 []ledger.Value{ 575 []byte{21, 37}, 576 }, 577 ) 578 require.NoError(t, err) 579 580 trieUpdate4, err := pathfinder.UpdateToTrieUpdate(update4, complete.DefaultPathFinderVersion) 581 require.NoError(t, err) 582 583 executableBlock := unittest.ExecutableBlockFixture([][]flow.Identifier{ 584 {unittest.IdentifierFixture()}, 585 {unittest.IdentifierFixture()}, 586 {unittest.IdentifierFixture()}, 587 }, &startState) 588 589 blockExecResult := execution.NewPopulatedBlockExecutionResult(executableBlock) 590 blockExecResult.CollectionExecutionResultAt(0).AppendTransactionResults( 591 flow.EventsList{ 592 unittest.EventFixture("what", 0, 0, unittest.IdentifierFixture(), 2), 593 unittest.EventFixture("ever", 0, 1, unittest.IdentifierFixture(), 22), 594 }, 595 nil, 596 nil, 597 flow.TransactionResult{ 598 TransactionID: unittest.IdentifierFixture(), 599 ErrorMessage: "", 600 ComputationUsed: 23, 601 MemoryUsed: 101, 602 }, 603 ) 604 blockExecResult.CollectionExecutionResultAt(1).AppendTransactionResults( 605 flow.EventsList{ 606 unittest.EventFixture("what", 2, 0, unittest.IdentifierFixture(), 2), 607 unittest.EventFixture("ever", 2, 1, unittest.IdentifierFixture(), 22), 608 unittest.EventFixture("ever", 2, 2, unittest.IdentifierFixture(), 2), 609 unittest.EventFixture("ever", 2, 3, unittest.IdentifierFixture(), 22), 610 }, 611 nil, 612 nil, 613 flow.TransactionResult{ 614 TransactionID: unittest.IdentifierFixture(), 615 ErrorMessage: "fail", 616 ComputationUsed: 1, 617 MemoryUsed: 22, 618 }, 619 ) 620 621 return &execution.ComputationResult{ 622 BlockExecutionResult: blockExecResult, 623 BlockAttestationResult: &execution.BlockAttestationResult{ 624 BlockExecutionData: &execution_data.BlockExecutionData{ 625 ChunkExecutionDatas: []*execution_data.ChunkExecutionData{ 626 {TrieUpdate: trieUpdate1}, 627 {TrieUpdate: trieUpdate2}, 628 {TrieUpdate: trieUpdate3}, 629 {TrieUpdate: trieUpdate4}, 630 }, 631 }, 632 }, 633 ExecutionReceipt: &flow.ExecutionReceipt{ 634 ExecutionResult: flow.ExecutionResult{ 635 Chunks: flow.ChunkList{ 636 {EndState: unittest.StateCommitmentFixture()}, 637 {EndState: unittest.StateCommitmentFixture()}, 638 {EndState: unittest.StateCommitmentFixture()}, 639 {EndState: unittest.StateCommitmentFixture()}, 640 }, 641 }, 642 }, 643 } 644 } 645 646 // EntropyProviderFixture returns an entropy provider mock that 647 // supports RandomSource(). 648 // If input is nil, a random source fixture is generated. 649 func EntropyProviderFixture(source []byte) environment.EntropyProvider { 650 if source == nil { 651 source = unittest.SignatureFixture() 652 } 653 provider := envMock.EntropyProvider{} 654 provider.On("RandomSource").Return(source, nil) 655 return &provider 656 } 657 658 // ProtocolStateWithSourceFixture returns a protocol state mock that only 659 // supports AtBlockID to return a snapshot mock. 660 // The snapshot mock only supports RandomSource(). 661 // If input is nil, a random source fixture is generated. 662 func ProtocolStateWithSourceFixture(source []byte) protocol.State { 663 if source == nil { 664 source = unittest.SignatureFixture() 665 } 666 snapshot := &protocolMock.Snapshot{} 667 snapshot.On("RandomSource").Return(source, nil) 668 state := protocolMock.State{} 669 state.On("AtBlockID", mock.Anything).Return(snapshot) 670 return &state 671 }