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); } }
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); } }
// 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); } }
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); } }
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); } }
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); } }
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)); } }
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)); } }
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); } }
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)); } }
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); }
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)); } }