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