示例#1
0
        public void MockChain_AuctionTest()
        {
            using (PoWMockChain chain = new PoWMockChain(2))
            {
                MockChainNode sender   = chain.Nodes[0];
                MockChainNode receiver = chain.Nodes[1];

                sender.MineBlocks(1);

                ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/Auction.cs");
                Assert.True(compilationResult.Success);

                // Create contract and ensure code exists
                BuildCreateContractTransactionResponse response = sender.SendCreateContractTransaction(compilationResult.Compilation, 0, new string[] { "7#20" });
                receiver.WaitMempoolCount(1);
                receiver.MineBlocks(1);
                Assert.NotNull(receiver.GetCode(response.NewContractAddress));
                Assert.NotNull(sender.GetCode(response.NewContractAddress));

                // Test that the contract address, event name, and logging values are available in the bloom.
                var scBlockHeader = receiver.GetLastBlock().Header as ISmartContractBlockHeader;
                Assert.True(scBlockHeader.LogsBloom.Test(response.NewContractAddress.ToAddress(sender.CoreNode.FullNode.Network).ToBytes()));
                Assert.True(scBlockHeader.LogsBloom.Test(Encoding.UTF8.GetBytes("Created")));
                Assert.True(scBlockHeader.LogsBloom.Test(BitConverter.GetBytes((ulong)20)));
                // And sanity test that a non-indexed field and random value is not available in bloom.
                Assert.False(scBlockHeader.LogsBloom.Test(Encoding.UTF8.GetBytes(sender.MinerAddress.Address)));
                Assert.False(scBlockHeader.LogsBloom.Test(Encoding.UTF8.GetBytes("RandomValue")));

                // Test that the event can be searched for...
                var receiptsFromSearch = sender.GetReceipts(response.NewContractAddress, "Created");
                Assert.Single(receiptsFromSearch);

                // Call contract and ensure owner is now highest bidder
                BuildCallContractTransactionResponse callResponse = sender.SendCallContractTransaction("Bid", response.NewContractAddress, 2);
                receiver.WaitMempoolCount(1);
                receiver.MineBlocks(1);
                Assert.Equal(sender.GetStorageValue(response.NewContractAddress, "Owner"), sender.GetStorageValue(response.NewContractAddress, "HighestBidder"));

                // Wait 20 blocks and end auction and check for transaction to victor
                sender.MineBlocks(20);
                sender.SendCallContractTransaction("AuctionEnd", response.NewContractAddress, 0);
                sender.WaitMempoolCount(1);
                sender.MineBlocks(1);

                NBitcoin.Block block = sender.GetLastBlock();
                Assert.Equal(3, block.Transactions.Count);
            }
        }
示例#2
0
        public void SendAndReceiveLocalSmartContractPropertyCallTransactionsUsingController()
        {
            using (PoWMockChain chain = new PoWMockChain(2))
            {
                MockChainNode sender   = chain.Nodes[0];
                MockChainNode receiver = chain.Nodes[1];

                int maturity = (int)sender.CoreNode.FullNode.Network.Consensus.CoinbaseMaturity;
                sender.MineBlocks(maturity + 5);

                int spendable = GetSpendableBlocks(maturity + 5, maturity);
                Assert.Equal(Money.COIN * spendable * 50, (long)sender.WalletSpendableBalance);

                ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/StorageDemo.cs");
                Assert.True(compilationResult.Success);

                ulong gasLimit = SmartContractFormatLogic.GasLimitMaximum / 2;

                BuildCreateContractTransactionResponse response = sender.SendCreateContractTransaction(compilationResult.Compilation, amount: 0, feeAmount: 0.001M, gasPrice: SmartContractMempoolValidator.MinGasPrice, gasLimit: gasLimit);
                sender.WaitMempoolCount(1);
                sender.MineBlocks(1);

                var localCallResponse = sender.CallContractMethodLocally("Counter", response.NewContractAddress, 0,
                                                                         gasPrice: SmartContractMempoolValidator.MinGasPrice, gasLimit: gasLimit);

                // Check that the locally executed transaction returns the correct results
                Assert.Equal(12345, localCallResponse.Return);
                Assert.False(localCallResponse.Revert);
                Assert.True(localCallResponse.GasConsumed > 0);
                Assert.Null(localCallResponse.ErrorMessage);
                Assert.NotNull(localCallResponse.InternalTransfers);

                receiver.MineBlocks(2);

                // Check that the on-chain storage has not changed after mining
                var counterResult = sender.GetStorageValue(response.NewContractAddress, "Counter");

                Assert.Equal(12345, BitConverter.ToInt32(counterResult));

                // Call increment and check return value on receipt
                BuildCallContractTransactionResponse callResponse = sender.SendCallContractTransaction("Increment", response.NewContractAddress, 0);
                sender.WaitMempoolCount(1);
                sender.MineBlocks(1);

                ReceiptResponse receipt = sender.GetReceipt(callResponse.TransactionId.ToString());
                Assert.Equal("12346", receipt.ReturnValue);
            }
        }
        public void Create_InvalidSignature_Fails()
        {
            using (SignedPoAMockChain chain = new SignedPoAMockChain(2).Build())
            {
                MockChainNode node1 = chain.Nodes[0];
                MockChainNode node2 = chain.Nodes[1];
                this.SetupNodes(chain, node1, node2);

                // Sign file with incorrect key.
                byte[] toSend = new CSharpContractSigner(new ContractSigner()).PackageSignedCSharpFile(new Key(), "SmartContracts/StorageDemo.cs");

                // Try to send create but ensure it fails because code is signed by different key.
                BuildCreateContractTransactionResponse sendResponse = node1.SendCreateContractTransaction(toSend, 30);
                Assert.False(sendResponse.Success);
            }
        }
        public void Create_NoSignature_Fails()
        {
            using (SignedPoAMockChain chain = new SignedPoAMockChain(2).Build())
            {
                MockChainNode node1 = chain.Nodes[0];
                MockChainNode node2 = chain.Nodes[1];
                this.SetupNodes(chain, node1, node2);

                // Compile file
                byte[] contractBytes = ContractCompiler.CompileFile("SmartContracts/Auction.cs").Compilation;

                // Try to send create but ensure it fails because code is in incorrect format.
                BuildCreateContractTransactionResponse sendResponse = node1.SendCreateContractTransaction(contractBytes, 30);
                Assert.False(sendResponse.Success);
            }
        }
示例#5
0
        // TODO: Fix this.

        /*
         * [Retry]
         * public async Task Create_NoWhitelist_Mempool_RejectsAsync()
         * {
         *  using (var chain = new PoAMockChain(2, this.nodeFactory).Build())
         *  {
         *      MockChainNode node1 = chain.Nodes[0];
         *      MockChainNode node2 = chain.Nodes[1];
         *      this.SetupNodes(chain, node1, node2);
         *
         *      // Create a valid transaction.
         *      byte[] toSend = ContractCompiler.CompileFile("SmartContracts/StorageDemo.cs").Compilation;
         *      var buildResult = node1.BuildCreateContractTransaction(toSend, 0);
         *
         *      Transaction tx = node1.CoreNode.FullNode.Network.CreateTransaction(buildResult.Hex);
         *
         *      var broadcasterManager = node1.CoreNode.FullNode.NodeService<IBroadcasterManager>();
         *
         *      await broadcasterManager.BroadcastTransactionAsync(tx);
         *
         *      // Give it enough time to reach if it was valid.
         *      Thread.Sleep(3000);
         *
         *      // Nothing arrives.
         *      Assert.Empty(node1.CoreNode.CreateRPCClient().GetRawMempool());
         *
         *      // If we were to whitelist it later, the mempool increases.
         *      chain.WhitelistCode(toSend);
         *
         *      await broadcasterManager.BroadcastTransactionAsync(tx);
         *      node1.WaitMempoolCount(1);
         *  }
         * }
         */

        private void SetupNodes(IMockChain chain, MockChainNode node1, MockChainNode node2)
        {
            // TODO: Use ready chain data
            // Get premine
            chain.MineBlocks(10);

            // Send half to other from whoever received premine
            if ((long)node1.WalletSpendableBalance == node1.CoreNode.FullNode.Network.Consensus.PremineReward.Satoshi)
            {
                PayHalfPremine(chain, node1, node2);
            }
            else
            {
                PayHalfPremine(chain, node2, node1);
            }
        }
示例#6
0
        public async Task RPC_GetReceipt_Returns_ValueAsync()
        {
            using (var chain = new PoAMockChain(2, this.nodeFactory).Build())
            {
                MockChainNode node1 = chain.Nodes[0];
                MockChainNode node2 = chain.Nodes[1];

                // Get premine
                this.SetupNodes(chain, node1, node2);

                // Create a valid transaction.
                byte[] toSend = ContractCompiler.CompileFile("SmartContracts/StandardToken.cs").Compilation;

                var createParams = new[] { this.methodParameterStringSerializer.Serialize(10000uL) };
                BuildCreateContractTransactionResponse createResponse = node1.SendCreateContractTransaction(toSend, 0, createParams);
                node2.WaitMempoolCount(1);

                chain.MineBlocks(1);

                // Check for the receipt.
                RPCClient rpc    = node2.CoreNode.CreateRPCClient();
                var       result = await rpc.SendCommandAsync("getreceipt", createResponse.TransactionId.ToString());

                Assert.True(result.Result.Value <bool>("success"));

                // Send a token.
                var parameters = new string[]
                {
                    this.methodParameterStringSerializer.Serialize(node1.MinerAddress.Address.ToAddress(node1.CoreNode.FullNode.Network)),
                    this.methodParameterStringSerializer.Serialize(1uL)
                };

                BuildCallContractTransactionResponse callResponse = node1.SendCallContractTransaction("TransferTo", createResponse.NewContractAddress, 0, parameters);

                node2.WaitMempoolCount(1);

                chain.MineBlocks(1);

                result = await rpc.SendCommandAsync("searchreceipts", createResponse.NewContractAddress, "TransferLog");

                Assert.True(result.Result.First.Value <bool>("success"));

                var logs = (JArray)result.Result.First["logs"];
                Assert.NotEmpty(logs);
            }
        }
示例#7
0
        public PoWMockChain(int numberOfNodes)
        {
            this.builder = SmartContractNodeBuilder.Create(this);
            this.nodes   = new MockChainNode[numberOfNodes];

            for (int nodeIndex = 0; nodeIndex < numberOfNodes; nodeIndex++)
            {
                CoreNode node = this.builder.CreateSmartContractPowNode().Start();

                for (int j = 0; j < nodeIndex; j++)
                {
                    MockChainNode otherNode = this.nodes[j];
                    TestHelper.Connect(node, otherNode.CoreNode);
                }

                this.nodes[nodeIndex] = new MockChainNode(node, this);
            }
        }
示例#8
0
        public void Create_NoSignature_Fails()
        {
            using (var chain = new PoAMockChain(2, this.nodeFactory).Build())
            {
                MockChainNode node1 = chain.Nodes[0];
                MockChainNode node2 = chain.Nodes[1];
                this.SetupNodes(chain, node1, node2);

                // Compile file
                byte[] contractBytes = ContractCompiler.CompileFile("SmartContracts/Auction.cs").Compilation;

                // Try to send create but ensure it fails because code is in incorrect format.
                BuildCreateContractTransactionResponse sendResponse = node1.SendCreateContractTransaction(contractBytes, 30);

                // SendCreateContractTransaction returns null for an ErrorResponse
                Assert.Null(sendResponse);
            }
        }
示例#9
0
        public void Validate_ConstructorLoop()
        {
            using (PoWMockChain chain = new PoWMockChain(2))
            {
                MockChainNode sender   = chain.Nodes[0];
                MockChainNode receiver = chain.Nodes[1];

                sender.MineBlocks(1);

                var byteCode = ContractCompiler.CompileFile("SmartContracts/ConstructorLoop.cs").Compilation;

                // Create contract and ensure code exists
                BuildCreateContractTransactionResponse response = sender.SendCreateContractTransaction(byteCode, 0);
                receiver.WaitMempoolCount(1);
                receiver.MineBlocks(2);
                Assert.NotNull(receiver.GetCode(response.NewContractAddress));
                Assert.NotNull(sender.GetCode(response.NewContractAddress));
            }
        }
示例#10
0
        public PoAMockChain Build()
        {
            var network = new SmartContractsPoARegTest();

            for (int nodeIndex = 0; nodeIndex < this.nodes.Length; nodeIndex++)
            {
                CoreNode node = this.builder.CreateSmartContractPoANode(network, nodeIndex).Start();

                for (int j = 0; j < nodeIndex; j++)
                {
                    MockChainNode otherNode = this.nodes[j];
                    TestHelper.Connect(node, otherNode.CoreNode);
                }

                this.nodes[nodeIndex] = new MockChainNode(node, this);
            }

            return(this);
        }
        public void Create_Signed_Contract()
        {
            using (SignedPoAMockChain chain = new SignedPoAMockChain(2).Build())
            {
                MockChainNode node1 = chain.Nodes[0];
                MockChainNode node2 = chain.Nodes[1];
                this.SetupNodes(chain, node1, node2);

                // Compile file
                byte[] toSend = new CSharpContractSigner(new ContractSigner()).PackageSignedCSharpFile(this.network.SigningContractPrivKey, "SmartContracts/StorageDemo.cs");

                // Send create with value, and ensure balance is stored.
                BuildCreateContractTransactionResponse sendResponse = node1.SendCreateContractTransaction(toSend, 30);
                node1.WaitMempoolCount(1);
                chain.MineBlocks(1);

                // Check the balance exists at contract location.
                Assert.Equal((ulong)30 * 100_000_000, node1.GetContractBalance(sendResponse.NewContractAddress));
            }
        }
示例#12
0
        public PoAMockChain(int numNodes)
        {
            this.builder = SmartContractNodeBuilder.Create(this);
            this.nodes   = new MockChainNode[numNodes];
            var network = new SmartContractsPoARegTest();

            this.Network = network;
            for (int i = 0; i < numNodes; i++)
            {
                CoreNode node = this.builder.CreateSmartContractPoANode(network.FederationKeys[i]).Start();

                for (int j = 0; j < i; j++)
                {
                    MockChainNode otherNode = this.nodes[j];
                    TestHelper.Connect(node, otherNode.CoreNode);
                    TestHelper.Connect(otherNode.CoreNode, node);
                }

                this.nodes[i] = new MockChainNode(node, this);
            }
        }
        public PoWMockChain(int numNodes)
        {
            this.Network = new SmartContractsRegTest(); // TODO: Make this configurable.

            this.builder = SmartContractNodeBuilder.Create(this);
            this.nodes   = new MockChainNode[numNodes];

            for (int i = 0; i < numNodes; i++)
            {
                CoreNode node = this.builder.CreateSmartContractPowNode().Start();

                // Add other nodes
                for (int j = 0; j < i; j++)
                {
                    MockChainNode otherNode = this.nodes[j];
                    TestHelper.Connect(node, otherNode.CoreNode);
                    TestHelper.Connect(otherNode.CoreNode, node);
                }

                this.nodes[i] = new MockChainNode(node, this);
            }
        }
        public async Task Create_NoSignature_Mempool_Rejects()
        {
            using (SignedPoAMockChain chain = new SignedPoAMockChain(2).Build())
            {
                MockChainNode node1 = chain.Nodes[0];
                MockChainNode node2 = chain.Nodes[1];
                this.SetupNodes(chain, node1, node2);

                // Create a valid transaction.
                byte[] toSend      = new CSharpContractSigner(new ContractSigner()).PackageSignedCSharpFile(this.network.SigningContractPrivKey, "SmartContracts/StorageDemo.cs");
                var    buildResult = node1.BuildCreateContractTransaction(toSend, 0);

                // Replace the SC output ScriptPubKey with an invalid one.
                Transaction tx            = node1.CoreNode.FullNode.Network.CreateTransaction(buildResult.Hex);
                TxOut       txOut         = tx.TryGetSmartContractTxOut();
                byte[]      contractBytes = ContractCompiler.CompileFile("SmartContracts/Auction.cs").Compilation;
                var         serializer    = new CallDataSerializer(new ContractPrimitiveSerializer(this.network));
                byte[]      newScript     = serializer.Serialize(new ContractTxData(1, SmartContractFormatLogic.GasLimitMaximum, (RuntimeObserver.Gas)SmartContractMempoolValidator.MinGasPrice, contractBytes));
                txOut.ScriptPubKey = new Script(newScript);

                var broadcasterManager = node1.CoreNode.FullNode.NodeService <IBroadcasterManager>();
                // Try and broadcast invalid tx.
                await broadcasterManager.BroadcastTransactionAsync(tx);

                // Give it enough time to reach if it was valid.
                Thread.Sleep(3000);

                // Nothing arrives.
                Assert.Empty(node1.CoreNode.CreateRPCClient().GetRawMempool());

                // If we were to send a valid one the mempool increases.
                buildResult = node1.BuildCreateContractTransaction(toSend, 0);
                tx          = node1.CoreNode.FullNode.Network.CreateTransaction(buildResult.Hex);
                await broadcasterManager.BroadcastTransactionAsync(tx);

                node1.WaitMempoolCount(1);
            }
        }
示例#15
0
        public void Create_Whitelisted_Contract()
        {
            using (var chain = new PoAMockChain(2, this.nodeFactory).Build())
            {
                MockChainNode node1 = chain.Nodes[0];
                MockChainNode node2 = chain.Nodes[1];
                this.SetupNodes(chain, node1, node2);

                // Compile file
                byte[] toSend = ContractCompiler.CompileFile("SmartContracts/StorageDemo.cs").Compilation;

                // Add the hash to all the nodes on the chain.
                chain.WhitelistCode(toSend);

                // Send create with value, and ensure balance is stored.
                BuildCreateContractTransactionResponse sendResponse = node1.SendCreateContractTransaction(toSend, 30);
                node1.WaitMempoolCount(1);
                chain.MineBlocks(1);

                // Check the balance exists at contract location.
                Assert.Equal((ulong)30 * 100_000_000, node1.GetContractBalance(sendResponse.NewContractAddress));
            }
        }
        public void Test_CatCreation()
        {
            using (MockChain chain = new MockChain(2))
            {
                MockChainNode sender   = chain.Nodes[0];
                MockChainNode receiver = chain.Nodes[1];

                sender.MineBlocks(10);

                SmartContractCompilationResult compilationResult = SmartContractCompiler.CompileFile("SmartContracts/ContractCreation.cs");
                Assert.True(compilationResult.Success);

                // Create contract and ensure code exists
                BuildCreateContractTransactionResponse response = sender.SendCreateContractTransaction(compilationResult.Compilation);
                receiver.WaitMempoolCount(1);
                receiver.MineBlocks(2);
                Assert.NotNull(receiver.GetCode(response.NewContractAddress));
                Assert.NotNull(sender.GetCode(response.NewContractAddress));

                // Call contract and ensure internal contract was created.
                BuildCallContractTransactionResponse callResponse = sender.SendCallContractTransaction("CreateCat", response.NewContractAddress, 0);
                receiver.WaitMempoolCount(1);
                receiver.MineBlocks(1);
                Assert.Equal(1, BitConverter.ToInt32(sender.GetStorageValue(response.NewContractAddress, "CatCounter")));
                uint160 lastCreatedCatAddress     = new uint160(sender.GetStorageValue(response.NewContractAddress, "LastCreatedCat"));
                uint160 expectedCreatedCatAddress = this.addressGenerator.GenerateAddress(callResponse.TransactionId, 0);
                Assert.Equal(expectedCreatedCatAddress, lastCreatedCatAddress);

                // Test that the contract address, event name, and logging values are available in the bloom, from internal create.
                var scBlockHeader = receiver.GetLastBlock().Header as SmartContractBlockHeader;
                Assert.True(scBlockHeader.LogsBloom.Test(lastCreatedCatAddress.ToBytes()));
                Assert.True(scBlockHeader.LogsBloom.Test(Encoding.UTF8.GetBytes("CatCreated")));
                Assert.True(scBlockHeader.LogsBloom.Test(BitConverter.GetBytes(0)));
                // And sanity test that a random value is not available in bloom.
                Assert.False(scBlockHeader.LogsBloom.Test(Encoding.UTF8.GetBytes("RandomValue")));
            }
        }
        public void Create_WithFunds()
        {
            using (MockChain chain = new MockChain(2))
            {
                MockChainNode sender   = chain.Nodes[0];
                MockChainNode receiver = chain.Nodes[1];

                // Mine some coins so we have balance
                int maturity = (int)chain.Network.Consensus.CoinbaseMaturity;
                sender.MineBlocks(maturity + 1);
                int spendable = GetSpendableBlocks(maturity + 1, maturity);
                Assert.Equal(Money.COIN * spendable * 50, (long)sender.WalletSpendableBalance);

                // Compile file
                SmartContractCompilationResult compilationResult = SmartContractCompiler.CompileFile("SmartContracts/StorageDemo.cs");
                Assert.True(compilationResult.Success);

                // Send create with value, and ensure balance is stored.
                BuildCreateContractTransactionResponse sendResponse = sender.SendCreateContractTransaction(compilationResult.Compilation, 30);
                sender.WaitMempoolCount(1);
                sender.MineBlocks(1);
                Assert.Equal((ulong)30 * 100_000_000, sender.GetContractBalance(sendResponse.NewContractAddress));
            }
        }
示例#18
0
 private void PayHalfPremine(IMockChain chain, MockChainNode from, MockChainNode to)
 {
     from.SendTransaction(to.MinerAddress.ScriptPubKey, new Money(from.CoreNode.FullNode.Network.Consensus.PremineReward.Satoshi / 2, MoneyUnit.Satoshi));
     from.WaitMempoolCount(1);
     chain.MineBlocks(1);
 }
示例#19
0
        public void SendAndReceiveSmartContractTransactionsUsingController()
        {
            using (PoWMockChain chain = new PoWMockChain(2))
            {
                MockChainNode sender = chain.Nodes[0];

                // Mine some coins so we have balance
                int maturity = (int)sender.CoreNode.FullNode.Network.Consensus.CoinbaseMaturity;
                sender.MineBlocks(maturity + 1);
                int spendable = GetSpendableBlocks(maturity + 1, maturity);
                Assert.Equal(Money.COIN * spendable * 50, (long)sender.WalletSpendableBalance);

                ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/StorageDemo.cs");
                Assert.True(compilationResult.Success);

                ulong gasLimit = SmartContractFormatLogic.GasLimitMaximum / 2;

                var response = sender.SendCreateContractTransaction(compilationResult.Compilation, 0, feeAmount: 0.001M,
                                                                    gasPrice: SmartContractMempoolValidator.MinGasPrice, gasLimit: gasLimit);
                sender.WaitMempoolCount(1);
                sender.MineBlocks(1);

                // Check receipt was stored and can be retrieved.
                var receiptResponse = sender.GetReceipt(response.TransactionId.ToString());
                Assert.True(receiptResponse.Success);
                Assert.Equal(response.NewContractAddress, receiptResponse.NewContractAddress);
                Assert.Null(receiptResponse.To);
                Assert.Equal(sender.MinerAddress.Address, receiptResponse.From);

                var storageRequestResult = sender.GetStorageValue(response.NewContractAddress, "TestSave");
                Assert.Equal("Hello, smart contract world!", Encoding.UTF8.GetString(storageRequestResult));

                var ownerRequestResult = sender.GetStorageValue(response.NewContractAddress, "Owner");
                Assert.NotEmpty(ownerRequestResult);

                var counterRequestResult = sender.GetStorageValue(response.NewContractAddress, "Counter");
                Assert.Equal(12345, BitConverter.ToInt32(counterRequestResult));

                var callResponse = sender.SendCallContractTransaction("Increment", response.NewContractAddress, 0,
                                                                      feeAmount: 0.001M,
                                                                      gasPrice: SmartContractMempoolValidator.MinGasPrice, gasLimit: gasLimit);

                sender.WaitMempoolCount(1);
                sender.MineBlocks(1);

                counterRequestResult = sender.GetStorageValue(response.NewContractAddress, "Counter");
                Assert.Equal(12346, BitConverter.ToInt32(counterRequestResult));

                // Check receipt was stored and can be retrieved.
                receiptResponse = sender.GetReceipt(callResponse.TransactionId.ToString());
                Assert.True(receiptResponse.Success);
                Assert.Null(receiptResponse.NewContractAddress);
                Assert.Equal(response.NewContractAddress, receiptResponse.To);
                Assert.Equal(sender.MinerAddress.Address, receiptResponse.From);

                // Test serialization
                // TODO: When refactoring integration tests, move this to the one place and test all types, from method param to storage to serialization.

                sender.SendCallContractTransaction(
                    "TestSerializer",
                    response.NewContractAddress,
                    0,
                    feeAmount: 0.001M,
                    gasPrice: SmartContractMempoolValidator.MinGasPrice,
                    gasLimit: gasLimit);

                sender.WaitMempoolCount(1);
                sender.MineBlocks(1);

                // Would have only saved if execution completed successfully
                counterRequestResult = sender.GetStorageValue(response.NewContractAddress, "Int32");
                Assert.Equal(12345, BitConverter.ToInt32(counterRequestResult));
            }
        }