public void EmptyMethodNameFails() { // Ensure fixture is funded. this.mockChain.MineBlocks(1); // Deploy contract to send to ContractCompilationResult receiveCompilationResult = ContractCompiler.CompileFile("SmartContracts/BasicReceive.cs"); Assert.True(receiveCompilationResult.Success); BuildCreateContractTransactionResponse receiveResponse = this.node1.SendCreateContractTransaction(receiveCompilationResult.Compilation, 0); this.mockChain.WaitAllMempoolCount(1); this.mockChain.MineBlocks(1); Assert.NotNull(this.node1.GetCode(receiveResponse.NewContractAddress)); decimal amount = 25; Money senderBalanceBefore = this.node1.WalletSpendableBalance; uint256 currentHash = this.node1.GetLastBlock().GetHash(); // Send to empty method name on contract string[] parameters = new string[] { string.Format("{0}#{1}", (int)MethodParameterDataType.Address, receiveResponse.NewContractAddress) }; BuildCallContractTransactionResponse response = this.node1.SendCallContractTransaction( "", receiveResponse.NewContractAddress, amount, parameters); this.mockChain.WaitAllMempoolCount(1); this.mockChain.MineBlocks(1); NBitcoin.Block lastBlock = this.node1.GetLastBlock(); // Receipt shows failure ReceiptResponse receipt = this.node1.GetReceipt(response.TransactionId.ToString()); Assert.False(receipt.Success); Assert.Equal(StateTransitionErrors.NoMethodName, receipt.Error); }
public void SmartContractsController_Builds_Transaction_With_Minimum_Inputs() { using (SmartContractNodeBuilder builder = SmartContractNodeBuilder.Create(this)) { CoreNode scSender = builder.CreateSmartContractPowNode().WithWallet().Start(); var maturity = (int)scSender.FullNode.Network.Consensus.CoinbaseMaturity; HdAddress addr = TestHelper.MineBlocks(scSender, maturity + 5).AddressUsed; int spendableBlocks = GetSpendableBlocks(maturity + 5, maturity); var total = scSender.FullNode.WalletManager().GetSpendableTransactionsInWallet(WalletName).Sum(s => s.Transaction.Amount); Assert.Equal(Money.COIN * spendableBlocks * 50, total); SmartContractsController senderSmartContractsController = scSender.FullNode.NodeController <SmartContractsController>(); SmartContractWalletController senderWalletController = scSender.FullNode.NodeController <SmartContractWalletController>(); ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/StorageDemo.cs"); Assert.True(compilationResult.Success); var buildRequest = new BuildCreateContractTransactionRequest { AccountName = AccountName, GasLimit = 10_000, GasPrice = 1, ContractCode = compilationResult.Compilation.ToHexString(), FeeAmount = "0.001", Password = Password, WalletName = WalletName, Sender = addr.Address }; JsonResult result = (JsonResult)senderSmartContractsController.BuildCreateSmartContractTransaction(buildRequest); var response = (BuildCreateContractTransactionResponse)result.Value; var transaction = scSender.FullNode.Network.CreateTransaction(response.Hex); Assert.Single(transaction.Inputs); } }
public void InternalTransfer_FromConstructor() { double amount = 25; uint256 currentHash = this.node1.GetLastBlock().GetHash(); // Deploy contract ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/TransferFromConstructor.cs"); Assert.True(compilationResult.Success); uint160 walletUint160 = new uint160(1); string address = walletUint160.ToBase58Address(this.mockChain.Network); string[] parameters = new string[] { string.Format("{0}#{1}", (int)MethodParameterDataType.Address, address) }; BuildCreateContractTransactionResponse response = this.node1.SendCreateContractTransaction(compilationResult.Compilation, amount, parameters); this.node2.WaitMempoolCount(1); this.node2.WaitForBlocksToBeMined(1); Assert.NotNull(this.node1.GetCode(response.NewContractAddress)); NBitcoin.Block lastBlock = this.node1.GetLastBlock(); // Blocks progressed Assert.NotEqual(currentHash, lastBlock.GetHash()); // Contract maintains half the balance Assert.Equal((ulong)new Money((long)amount, MoneyUnit.BTC) / 2, this.node1.GetContractBalance(response.NewContractAddress)); // Receipt is correct ReceiptResponse receipt = this.node1.GetReceipt(response.TransactionId.ToString()); Assert.Equal(response.TransactionId.ToString(), receipt.TransactionHash); Assert.Empty(receipt.Logs); // TODO: Could add logs to this test Assert.True(receipt.Success); Assert.True(receipt.GasUsed > GasPriceList.BaseCost); Assert.Equal(response.NewContractAddress, receipt.NewContractAddress); Assert.Equal(this.node1.MinerAddress.Address, receipt.From); Assert.Null(receipt.Error); Assert.Null(receipt.To); }
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 TestGasInjector_ContractMethodWithRecursion_GasInjectionSucceeds() { ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/Recursion.cs"); Assert.True(compilationResult.Success); byte[] originalAssemblyBytes = compilationResult.Compilation; var callData = new MethodCall(nameof(Recursion.DoRecursion)); IContractModuleDefinition module = this.moduleReader.Read(originalAssemblyBytes).Value; module.Rewrite(this.rewriter); CSharpFunctionalExtensions.Result <IContractAssembly> assembly = this.assemblyLoader.Load(module.ToByteCode()); IContract contract = Contract.CreateUninitialized(assembly.Value.GetType(module.ContractType.Name), this.state, null); IContractInvocationResult result = contract.Invoke(callData); Assert.True(result.IsSuccess); Assert.True(this.gasMeter.GasConsumed > 0); }
public void VM_ExecuteContract_ClearStorage() { ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/ClearStorage.cs"); Assert.True(compilationResult.Success); byte[] contractExecutionCode = compilationResult.Compilation; var callData = new MethodCall(nameof(ClearStorage.ClearKey), new object[] { }); uint160 contractAddress = this.contractState.Message.ContractAddress.ToUint160(); byte[] keyToClear = Encoding.UTF8.GetBytes(ClearStorage.KeyToClear); // Set a value to be cleared this.state.SetStorageValue(contractAddress, keyToClear, new byte[] { 1, 2, 3 }); VmExecutionResult result = this.vm.ExecuteMethod(this.contractState, callData, contractExecutionCode, nameof(ClearStorage)); Assert.Null(result.Error); Assert.Null(this.state.GetStorageValue(contractAddress, keyToClear)); }
public void VM_ExecuteContract_ClearStorage() { ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/ClearStorage.cs"); Assert.True(compilationResult.Success); byte[] contractExecutionCode = compilationResult.Compilation; byte[] codeHash = HashHelper.Keccak256(contractExecutionCode); var callData = new MethodCall(nameof(ClearStorage.ClearKey), new object[] { }); uint160 contractAddress = this.contractState.Message.ContractAddress.ToUint160(); byte[] keyToClear = Encoding.UTF8.GetBytes(ClearStorage.KeyToClear); // Set a value to be cleared this.state.SetStorageValue(contractAddress, keyToClear, new byte[] { 1, 2, 3 }); var executionContext = new ExecutionContext(new Observer(this.gasMeter, new MemoryMeter(100_000))); VmExecutionResult result = this.vm.ExecuteMethod(this.contractState, executionContext, callData, contractExecutionCode, nameof(ClearStorage)); CachedAssemblyPackage cachedAssembly = this.context.ContractCache.Retrieve(new uint256(codeHash)); // Check that it's been cached for a successful call. Assert.NotNull(cachedAssembly); // Check that the observer has been reset. Assert.Null(cachedAssembly.Assembly.GetObserver()); Assert.Null(result.Error); Assert.Null(this.state.GetStorageValue(contractAddress, keyToClear)); }
public void TestGasInjector_OutOfGasFails() { ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/OutOfGasTest.cs"); Assert.True(compilationResult.Success); byte[] originalAssemblyBytes = compilationResult.Compilation; var callData = new MethodCall("UseAllGas"); IContractModuleDefinition module = this.moduleReader.Read(originalAssemblyBytes).Value; module.Rewrite(this.rewriter); CSharpFunctionalExtensions.Result <IContractAssembly> assembly = this.assemblyLoader.Load(module.ToByteCode()); IContract contract = Contract.CreateUninitialized(assembly.Value.GetType(module.ContractType.Name), this.state, null); // Because our contract contains an infinite loop, we want to kill our test after // some amount of time without achieving a result. 3 seconds is an arbitrarily high enough timeout // for the method body to have finished execution while minimising the amount of time we spend // running tests // If you're running with the debugger on this will obviously be a source of failures IContractInvocationResult result = TimeoutHelper.RunCodeWithTimeout(5, () => { // Need to set this here as the timeout helper will run this in a new thread and observer is thread static within the assembly. assembly.Value.SetObserver(new Observer(this.gasMeter, new MemoryMeter(ReflectionVirtualMachine.MemoryUnitLimit))); return(contract.Invoke(callData)); }); Assert.False(result.IsSuccess); Assert.Equal((RuntimeObserver.Gas) 0, this.gasMeter.GasAvailable); Assert.Equal(this.gasMeter.GasLimit, this.gasMeter.GasConsumed); Assert.Equal(this.gasMeter.GasLimit, this.gasMeter.GasConsumed); }
public void VM_CreateContract_WithParameters() { ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/Auction.cs"); Assert.True(compilationResult.Success); byte[] contractExecutionCode = compilationResult.Compilation; byte[] codeHash = HashHelper.Keccak256(contractExecutionCode); var methodParameters = new object[] { (ulong)5 }; var executionContext = new ExecutionContext(new Observer(this.gasMeter, new MemoryMeter(100_000))); VmExecutionResult result = this.vm.Create(this.state, this.contractState, executionContext, contractExecutionCode, methodParameters); CachedAssemblyPackage cachedAssembly = this.context.ContractCache.Retrieve(new uint256(codeHash)); // Check that it's been cached. Assert.NotNull(cachedAssembly); // Check that the observer has been reset. Assert.Null(cachedAssembly.Assembly.GetObserver()); Assert.True(result.IsSuccess); Assert.Null(result.Error); }
public void PersistentState_Clear_State_Should_Be_Empty_In_Same_Tx() { // Ensure fixture is funded. this.mockChain.MineBlocks(1); // Deploy contract ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/ClearDataContract.cs"); Assert.True(compilationResult.Success); BuildCreateContractTransactionResponse preResponse = this.node1.SendCreateContractTransaction(compilationResult.Compilation, 0); this.mockChain.WaitAllMempoolCount(1); this.mockChain.MineBlocks(1); Assert.NotNull(this.node1.GetCode(preResponse.NewContractAddress)); uint256 currentHash = this.node1.GetLastBlock().GetHash(); // Clear the data and check that it's empty BuildCallContractTransactionResponse response = this.node1.SendCallContractTransaction( nameof(ClearDataContract.ClearDataAndCheck), preResponse.NewContractAddress, 0); this.mockChain.WaitAllMempoolCount(1); this.mockChain.MineBlocks(1); NBitcoin.Block lastBlock = this.node1.GetLastBlock(); // Blocks progressed Assert.NotEqual(currentHash, lastBlock.GetHash()); ReceiptResponse receipt = this.node1.GetReceipt(response.TransactionId.ToString()); Assert.True(receipt.Success); Assert.Equal(true.ToString(), receipt.ReturnValue); }
public void ExternalTransfer_Create_WithValueTransfer() { // Ensure fixture is funded. this.mockChain.MineBlocks(1); ulong amount = 25; // Deploy contract ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/ReceiveFundsTest.cs"); Assert.True(compilationResult.Success); BuildCreateContractTransactionResponse response = this.node1.SendCreateContractTransaction(compilationResult.Compilation, amount); this.mockChain.WaitAllMempoolCount(1); this.mockChain.MineBlocks(1); Assert.NotNull(this.node1.GetCode(response.NewContractAddress)); uint160 contractAddress = this.addressGenerator.GenerateAddress(response.TransactionId, 0); // Stored balance in PersistentState should be only that which was sent byte[] saved = this.node1.GetStorageValue(contractAddress.ToBase58Address(this.node1.CoreNode.FullNode.Network), "Balance"); ulong savedUlong = BitConverter.ToUInt64(saved); Assert.True((new Money(amount, MoneyUnit.BTC) == new Money(savedUlong, MoneyUnit.Satoshi))); }
public void InternalTransfer_Nested_Create_Balance_Correct() { // Ensure fixture is funded. this.mockChain.MineBlocks(1); decimal amount = 25; // Deploy contract ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/BalanceTest.cs"); Assert.True(compilationResult.Success); BuildCreateContractTransactionResponse response = this.node1.SendCreateContractTransaction(compilationResult.Compilation, amount); this.mockChain.WaitAllMempoolCount(1); this.mockChain.MineBlocks(1); Assert.NotNull(this.node1.GetCode(response.NewContractAddress)); uint160 internalContract = this.addressGenerator.GenerateAddress(response.TransactionId, 1); // Stored balance in PersistentState should be only that which was sent (10) byte[] saved = this.node1.GetStorageValue(internalContract.ToBase58Address(this.node1.CoreNode.FullNode.Network), "Balance"); ulong savedUlong = BitConverter.ToUInt64(saved); Assert.Equal((ulong)10, savedUlong); }
public void SendAndReceiveSmartContractTransactionsOnPosNetwork() { using (NodeBuilder builder = NodeBuilder.Create(this)) { CoreNode scSender = builder.CreateSmartContractPosNode(); CoreNode scReceiver = builder.CreateSmartContractPosNode(); builder.StartAll(); scSender.NotInIBD(); scReceiver.NotInIBD(); scSender.FullNode.WalletManager().CreateWallet(Password, WalletName, Passphrase); scReceiver.FullNode.WalletManager().CreateWallet(Password, WalletName, Passphrase); var maturity = (int)scSender.FullNode.Network.Consensus.CoinbaseMaturity; HdAddress senderAddress = TestHelper.MineBlocks(scSender, WalletName, Password, AccountName, maturity + 5).AddressUsed; // Wait for block repo for block sync to work. TestHelper.WaitLoop(() => TestHelper.IsNodeSynced(scSender)); // The mining should add coins to the wallet. var total = scSender.FullNode.WalletManager().GetSpendableTransactionsInWallet(WalletName).Sum(s => s.Transaction.Amount); Assert.Equal(Money.COIN * 6 * 50, total); // Create a token contract ulong gasPrice = 1; int vmVersion = 1; Gas gasLimit = (Gas)5000; ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/TransferTestPos.cs"); Assert.True(compilationResult.Success); var contractCarrier = ContractCarrier.CreateContract(vmVersion, compilationResult.Compilation, gasPrice, gasLimit); var contractCreateScript = new Script(contractCarrier.Serialize()); var txBuildContext = new TransactionBuildContext(scSender.FullNode.Network) { AccountReference = new WalletAccountReference(WalletName, AccountName), ChangeAddress = senderAddress, MinConfirmations = maturity, FeeType = FeeType.High, WalletPassword = Password, Recipients = new[] { new Recipient { Amount = 0, ScriptPubKey = contractCreateScript } }.ToList() }; // Build the transfer contract transaction var transferContractTransaction = BuildTransferContractTransaction(scSender, txBuildContext); // Add the smart contract transaction to the mempool to be mined. scSender.AddToStratisMempool(transferContractTransaction); // Ensure the smart contract transaction is in the mempool. TestHelper.WaitLoop(() => scSender.CreateRPCClient().GetRawMempool().Length > 0); // Mine the token transaction and wait for it sync scSender.GenerateStratisWithMiner(1); TestHelper.WaitLoop(() => TestHelper.IsNodeSynced(scSender)); // Sync to the receiver node scSender.CreateRPCClient().AddNode(scReceiver.Endpoint, true); TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(scReceiver, scSender)); // Ensure that boths nodes has the contract IStateRepositoryRoot senderState = scSender.FullNode.NodeService <IStateRepositoryRoot>(); IStateRepositoryRoot receiverState = scReceiver.FullNode.NodeService <IStateRepositoryRoot>(); IAddressGenerator addressGenerator = scSender.FullNode.NodeService <IAddressGenerator>(); uint160 tokenContractAddress = addressGenerator.GenerateAddress(transferContractTransaction.GetHash(), 0); Assert.NotNull(senderState.GetCode(tokenContractAddress)); Assert.NotNull(receiverState.GetCode(tokenContractAddress)); scSender.FullNode.MempoolManager().Clear(); // Create a transfer token contract compilationResult = ContractCompiler.CompileFile("SmartContracts/TransferTestPos.cs"); Assert.True(compilationResult.Success); contractCarrier = ContractCarrier.CreateContract(vmVersion, compilationResult.Compilation, gasPrice, gasLimit); contractCreateScript = new Script(contractCarrier.Serialize()); txBuildContext = new TransactionBuildContext(scSender.FullNode.Network) { AccountReference = new WalletAccountReference(WalletName, AccountName), ChangeAddress = senderAddress, MinConfirmations = maturity, FeeType = FeeType.High, WalletPassword = Password, Recipients = new[] { new Recipient { Amount = 0, ScriptPubKey = contractCreateScript } }.ToList() }; // Build the transfer contract transaction transferContractTransaction = BuildTransferContractTransaction(scSender, txBuildContext); // Add the smart contract transaction to the mempool to be mined. scSender.AddToStratisMempool(transferContractTransaction); // Wait for the token transaction to be picked up by the mempool TestHelper.WaitLoop(() => scSender.CreateRPCClient().GetRawMempool().Length > 0); scSender.GenerateStratisWithMiner(1); // Ensure the node is synced TestHelper.WaitLoop(() => TestHelper.IsNodeSynced(scSender)); // Ensure both nodes are synced with each other TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(scReceiver, scSender)); tokenContractAddress = addressGenerator.GenerateAddress(transferContractTransaction.GetHash(), 0); // nonce is 0 for user contract creation. Assert.NotNull(senderState.GetCode(tokenContractAddress)); Assert.NotNull(receiverState.GetCode(tokenContractAddress)); scSender.FullNode.MempoolManager().Clear(); // Create a call contract transaction which will transfer funds contractCarrier = ContractCarrier.CallContract(1, tokenContractAddress, "Test", gasPrice, gasLimit); Script contractCallScript = new Script(contractCarrier.Serialize()); txBuildContext = new TransactionBuildContext(scSender.FullNode.Network) { AccountReference = new WalletAccountReference(WalletName, AccountName), ChangeAddress = senderAddress, MinConfirmations = maturity, FeeType = FeeType.High, WalletPassword = Password, Recipients = new[] { new Recipient { Amount = 1000, ScriptPubKey = contractCallScript } }.ToList() }; // Build the transfer contract transaction var callContractTransaction = BuildTransferContractTransaction(scSender, txBuildContext); // Add the smart contract transaction to the mempool to be mined. scSender.AddToStratisMempool(callContractTransaction); // Wait for the token transaction to be picked up by the mempool TestHelper.WaitLoop(() => scSender.CreateRPCClient().GetRawMempool().Length > 0); scSender.GenerateStratisWithMiner(1); // Ensure the nodes are synced TestHelper.WaitLoop(() => TestHelper.IsNodeSynced(scSender)); TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(scReceiver, scSender)); // The balance should now reflect the transfer Assert.Equal((ulong)900, senderState.GetCurrentBalance(tokenContractAddress)); } }
public void InternalTransfer_Create_WithValueTransfer() { // Ensure fixture is funded. this.mockChain.MineBlocks(1); // Deploy contract ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/CreationTransfer.cs"); Assert.True(compilationResult.Success); BuildCreateContractTransactionResponse preResponse = this.node1.SendCreateContractTransaction(compilationResult.Compilation, 0); this.mockChain.WaitAllMempoolCount(1); this.mockChain.MineBlocks(1); Assert.NotNull(this.node1.GetCode(preResponse.NewContractAddress)); decimal amount = 25; Money senderBalanceBefore = this.node1.WalletSpendableBalance; uint256 currentHash = this.node1.GetLastBlock().GetHash(); // Send amount to contract, which will send to new address of contract it creates BuildCallContractTransactionResponse response = this.node1.SendCallContractTransaction( nameof(CreationTransfer.CreateAnotherContract), preResponse.NewContractAddress, amount); this.mockChain.WaitAllMempoolCount(1); this.mockChain.MineBlocks(1); NBitcoin.Block lastBlock = this.node1.GetLastBlock(); // Blocks progressed Assert.NotEqual(currentHash, lastBlock.GetHash()); // Get created contract address - TODO FIX uint160 createdAddress = this.addressGenerator.GenerateAddress(response.TransactionId, 0); // Block contains a condensing transaction Assert.Equal(3, lastBlock.Transactions.Count); Transaction condensingTransaction = lastBlock.Transactions[2]; Assert.Single(condensingTransaction.Outputs); // Entire balance was forwarded, byte[] toBytes = condensingTransaction.Outputs[0].ScriptPubKey.ToBytes(); Assert.Equal((byte)ScOpcodeType.OP_INTERNALCONTRACTTRANSFER, toBytes[0]); uint160 toAddress = new uint160(toBytes.Skip(1).ToArray()); Assert.Equal(createdAddress, toAddress); Assert.Equal(new Money((long)amount, MoneyUnit.BTC), condensingTransaction.Outputs[0].Value); // Contract doesn't maintain any balance Assert.Equal((ulong)0, this.node1.GetContractBalance(preResponse.NewContractAddress)); // Created contract received full amount Assert.Equal((ulong)new Money((ulong)amount, MoneyUnit.BTC), this.node1.GetContractBalance(createdAddress.ToBase58Address(this.node1.CoreNode.FullNode.Network))); // Receipt is correct ReceiptResponse receipt = this.node1.GetReceipt(response.TransactionId.ToString()); Assert.Equal(lastBlock.GetHash().ToString(), receipt.BlockHash); Assert.Equal(response.TransactionId.ToString(), receipt.TransactionHash); Assert.Empty(receipt.Logs); // TODO: Could add logs to this test Assert.True(receipt.Success); Assert.True(receipt.GasUsed > GasPriceList.BaseCost); Assert.Null(receipt.NewContractAddress); Assert.Equal(this.node1.MinerAddress.Address, receipt.From); Assert.Null(receipt.Error); Assert.Equal(preResponse.NewContractAddress, receipt.To); }
public void InternalTransfer_ToWalletAddress() { // Ensure fixture is funded. this.mockChain.MineBlocks(1); // Deploy contract ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/BasicTransfer.cs"); Assert.True(compilationResult.Success); BuildCreateContractTransactionResponse preResponse = this.node1.SendCreateContractTransaction(compilationResult.Compilation, 0); this.mockChain.WaitAllMempoolCount(1); this.mockChain.MineBlocks(1); Assert.NotNull(this.node1.GetCode(preResponse.NewContractAddress)); decimal amount = 25; Money senderBalanceBefore = this.node1.WalletSpendableBalance; uint256 currentHash = this.node1.GetLastBlock().GetHash(); // Send amount to contract, which will send to wallet address (address without code) uint160 walletUint160 = new uint160(1); string address = walletUint160.ToBase58Address(this.node1.CoreNode.FullNode.Network); string[] parameters = new string[] { string.Format("{0}#{1}", (int)MethodParameterDataType.Address, address) }; BuildCallContractTransactionResponse response = this.node1.SendCallContractTransaction( nameof(BasicTransfer.SendToAddress), preResponse.NewContractAddress, amount, parameters); this.mockChain.WaitAllMempoolCount(1); this.mockChain.MineBlocks(1); NBitcoin.Block lastBlock = this.node1.GetLastBlock(); // Blocks progressed Assert.NotEqual(currentHash, lastBlock.GetHash()); // Block contains a condensing transaction Assert.Equal(3, lastBlock.Transactions.Count); Transaction condensingTransaction = lastBlock.Transactions[2]; Assert.Single(condensingTransaction.Outputs); // Entire balance was forwarded, uint160 transferReceiver = this.senderRetriever.GetAddressFromScript(condensingTransaction.Outputs[0].ScriptPubKey).Sender; Assert.Equal(walletUint160, transferReceiver); Assert.Equal(new Money((long)amount, MoneyUnit.BTC), condensingTransaction.Outputs[0].Value); // Contract doesn't maintain any balance Assert.Equal((ulong)0, this.node1.GetContractBalance(preResponse.NewContractAddress)); // Receipt is correct ReceiptResponse receipt = this.node1.GetReceipt(response.TransactionId.ToString()); Assert.Equal(lastBlock.GetHash().ToString(), receipt.BlockHash); Assert.Equal(response.TransactionId.ToString(), receipt.TransactionHash); Assert.Empty(receipt.Logs); // TODO: Could add logs to this test Assert.True(receipt.Success); Assert.True(receipt.GasUsed > GasPriceList.BaseCost); Assert.Null(receipt.NewContractAddress); Assert.Equal(this.node1.MinerAddress.Address, receipt.From); Assert.Null(receipt.Error); Assert.Equal(preResponse.NewContractAddress, receipt.To); }
public void InternalTransfer_BetweenContracts() { // Ensure fixture is funded. this.mockChain.MineBlocks(1); // Deploy contract to send to ContractCompilationResult receiveCompilationResult = ContractCompiler.CompileFile("SmartContracts/NestedCallsReceiver.cs"); Assert.True(receiveCompilationResult.Success); BuildCreateContractTransactionResponse receiveResponse = this.node1.SendCreateContractTransaction(receiveCompilationResult.Compilation, 0); this.mockChain.WaitAllMempoolCount(1); this.mockChain.MineBlocks(1); Assert.NotNull(this.node1.GetCode(receiveResponse.NewContractAddress)); // Deploy contract to send from ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/NestedCallsStarter.cs"); Assert.True(compilationResult.Success); BuildCreateContractTransactionResponse preResponse = this.node1.SendCreateContractTransaction(compilationResult.Compilation, 0); this.mockChain.WaitAllMempoolCount(1); this.mockChain.MineBlocks(1); Assert.NotNull(this.node1.GetCode(preResponse.NewContractAddress)); decimal amount = 25; Money senderBalanceBefore = this.node1.WalletSpendableBalance; uint256 currentHash = this.node1.GetLastBlock().GetHash(); string[] parameters = new string[] { string.Format("{0}#{1}", (int)MethodParameterDataType.Address, receiveResponse.NewContractAddress) }; BuildCallContractTransactionResponse response = this.node1.SendCallContractTransaction(nameof(NestedCallsStarter.Start), preResponse.NewContractAddress, amount, parameters); this.mockChain.WaitAllMempoolCount(1); this.mockChain.MineBlocks(1); NBitcoin.Block lastBlock = this.node1.GetLastBlock(); // Blocks progressed Assert.NotEqual(currentHash, lastBlock.GetHash()); // Storage set correctly Assert.Equal(BitConverter.GetBytes(NestedCallsStarter.Return), this.node1.GetStorageValue(preResponse.NewContractAddress, NestedCallsStarter.Key)); // Block contains a condensing transaction Assert.Equal(3, lastBlock.Transactions.Count); Transaction condensingTransaction = lastBlock.Transactions[2]; Assert.Equal(2, condensingTransaction.Outputs.Count); // 1 output which is starting contract byte[] toBytes = condensingTransaction.Outputs[0].ScriptPubKey.ToBytes(); Assert.Equal((byte)ScOpcodeType.OP_INTERNALCONTRACTTRANSFER, toBytes[0]); uint160 toAddress = new uint160(toBytes.Skip(1).ToArray()); Assert.Equal(preResponse.NewContractAddress, toAddress.ToBase58Address(this.node1.CoreNode.FullNode.Network)); // Received 1/2 the sent funds + 1/2 of those funds Money transferAmount1 = new Money((long)amount, MoneyUnit.BTC) / 2; Money transferAmount2 = new Money((long)amount, MoneyUnit.BTC) / 4; Assert.Equal(transferAmount1 + transferAmount2, condensingTransaction.Outputs[0].Value); Assert.Equal((ulong)(transferAmount1 + transferAmount2), this.node1.GetContractBalance(preResponse.NewContractAddress)); // 1 output to other deployed contract toBytes = condensingTransaction.Outputs[1].ScriptPubKey.ToBytes(); Assert.Equal((byte)ScOpcodeType.OP_INTERNALCONTRACTTRANSFER, toBytes[0]); toAddress = new uint160(toBytes.Skip(1).ToArray()); Assert.Equal(receiveResponse.NewContractAddress, toAddress.ToBase58Address(this.node1.CoreNode.FullNode.Network)); // Received 1/2 the sent funds, but sent 1/2 of those funds back Assert.Equal(new Money((long)amount, MoneyUnit.BTC) - (transferAmount1 + transferAmount2), condensingTransaction.Outputs[1].Value); Assert.Equal((ulong)(new Money((long)amount, MoneyUnit.BTC) - (transferAmount1 + transferAmount2)), this.node1.GetContractBalance(receiveResponse.NewContractAddress)); }
public void InternalTransfer_FromConstructor() { // Ensure fixture is funded. this.mockChain.MineBlocks(1); decimal amount = 25; Money senderBalanceBefore = this.node1.WalletSpendableBalance; uint256 currentHash = this.node1.GetLastBlock().GetHash(); // Deploy contract ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/TransferFromConstructor.cs"); Assert.True(compilationResult.Success); uint160 walletUint160 = new uint160(1); string address = walletUint160.ToBase58Address(this.node1.CoreNode.FullNode.Network); string[] parameters = new string[] { string.Format("{0}#{1}", (int)MethodParameterDataType.Address, address) }; BuildCreateContractTransactionResponse response = this.node1.SendCreateContractTransaction(compilationResult.Compilation, amount, parameters); this.mockChain.WaitAllMempoolCount(1); this.mockChain.MineBlocks(1); Assert.NotNull(this.node1.GetCode(response.NewContractAddress)); NBitcoin.Block lastBlock = this.node1.GetLastBlock(); // Blocks progressed Assert.NotEqual(currentHash, lastBlock.GetHash()); // Block contains a condensing transaction Assert.Equal(3, lastBlock.Transactions.Count); Transaction condensingTransaction = lastBlock.Transactions[2]; Assert.Equal(2, condensingTransaction.Outputs.Count); // 1 output which is contract maintaining its balance byte[] toBytes = condensingTransaction.Outputs[0].ScriptPubKey.ToBytes(); Assert.Equal((byte)ScOpcodeType.OP_INTERNALCONTRACTTRANSFER, toBytes[0]); uint160 toAddress = new uint160(toBytes.Skip(1).ToArray()); Assert.Equal(response.NewContractAddress, toAddress.ToBase58Address(this.node1.CoreNode.FullNode.Network)); Assert.Equal(new Money((long)amount, MoneyUnit.BTC) / 2, condensingTransaction.Outputs[1].Value); // 1 output to address sent in params uint160 transferReceiver = this.senderRetriever.GetAddressFromScript(condensingTransaction.Outputs[1].ScriptPubKey).Sender; Assert.Equal(walletUint160, transferReceiver); Assert.Equal(new Money((long)amount, MoneyUnit.BTC) / 2, condensingTransaction.Outputs[1].Value); // Contract maintains half the balance Assert.Equal((ulong)new Money((long)amount, MoneyUnit.BTC) / 2, this.node1.GetContractBalance(response.NewContractAddress)); // Receipt is correct ReceiptResponse receipt = this.node1.GetReceipt(response.TransactionId.ToString()); Assert.Equal(lastBlock.GetHash().ToString(), receipt.BlockHash); Assert.Equal(response.TransactionId.ToString(), receipt.TransactionHash); Assert.Empty(receipt.Logs); // TODO: Could add logs to this test Assert.True(receipt.Success); Assert.True(receipt.GasUsed > GasPriceList.BaseCost); Assert.Equal(response.NewContractAddress, receipt.NewContractAddress); Assert.Equal(this.node1.MinerAddress.Address, receipt.From); Assert.Null(receipt.Error); Assert.Null(receipt.To); }
public void SendAndReceiveLocalSmartContractPropertyCallTransactionsUsingController() { using (SmartContractNodeBuilder builder = SmartContractNodeBuilder.Create(this)) { CoreNode scSender = builder.CreateSmartContractPowNode().WithWallet().Start(); CoreNode scReceiver = builder.CreateSmartContractPowNode().WithWallet().Start(); int maturity = (int)scReceiver.FullNode.Network.Consensus.CoinbaseMaturity; HdAddress addr = TestHelper.MineBlocks(scSender, maturity + 5).AddressUsed; int spendable = GetSpendableBlocks(maturity + 5, maturity); var total = scSender.FullNode.WalletManager().GetSpendableTransactionsInWallet(WalletName).Sum(s => s.Transaction.Amount); Assert.Equal(Money.COIN * spendable * 50, total); SmartContractsController senderSmartContractsController = scSender.FullNode.NodeService <SmartContractsController>(); SmartContractWalletController senderWalletController = scSender.FullNode.NodeService <SmartContractWalletController>(); ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/StorageDemo.cs"); Assert.True(compilationResult.Success); Gas gasLimit = (Gas)(SmartContractFormatRule.GasLimitMaximum / 2); var buildRequest = new BuildCreateContractTransactionRequest { AccountName = AccountName, GasLimit = gasLimit, GasPrice = SmartContractMempoolValidator.MinGasPrice, ContractCode = compilationResult.Compilation.ToHexString(), FeeAmount = "0.001", Password = Password, WalletName = WalletName, Sender = addr.Address }; JsonResult result = (JsonResult)senderSmartContractsController.BuildCreateSmartContractTransaction(buildRequest); var response = (BuildCreateContractTransactionResponse)result.Value; TestHelper.Connect(scSender, scReceiver); SmartContractSharedSteps.SendTransaction(scSender, scReceiver, senderWalletController, response.Hex); TestHelper.MineBlocks(scReceiver, 2); TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(scReceiver, scSender)); // Make a call request where the MethodName is the name of a property var callRequest = new BuildCallContractTransactionRequest { AccountName = AccountName, GasLimit = gasLimit, GasPrice = SmartContractMempoolValidator.MinGasPrice, Amount = "0", MethodName = "Counter", ContractAddress = response.NewContractAddress, FeeAmount = "0.001", Password = Password, WalletName = WalletName, Sender = addr.Address }; result = (JsonResult)senderSmartContractsController.LocalCallSmartContractTransaction(callRequest); var callResponse = (ILocalExecutionResult)result.Value; // Check that the locally executed transaction returns the correct results Assert.Equal(12345, callResponse.Return); Assert.False(callResponse.Revert); Assert.True(callResponse.GasConsumed > 0); Assert.Null(callResponse.ErrorMessage); Assert.NotNull(callResponse.InternalTransfers); TestHelper.MineBlocks(scReceiver, 2); TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(scReceiver, scSender)); } }
public void SendAndReceiveSmartContractTransactions() { NetworkRegistration.Register(new SmartContractsRegTest()); using (SmartContractNodeBuilder builder = SmartContractNodeBuilder.Create(this)) { CoreNode scSender = builder.CreateSmartContractPowNode().WithWallet().Start(); CoreNode scReceiver = builder.CreateSmartContractPowNode().WithWallet().Start(); var callDataSerializer = new CallDataSerializer(new ContractPrimitiveSerializer(scSender.FullNode.Network)); var maturity = (int)scSender.FullNode.Network.Consensus.CoinbaseMaturity; HdAddress senderAddress = TestHelper.MineBlocks(scSender, maturity + 5).AddressUsed; // The mining should add coins to the wallet. int spendableBlocks = GetSpendableBlocks(maturity + 5, maturity); var total = scSender.FullNode.WalletManager().GetSpendableTransactionsInWallet(WalletName).Sum(s => s.Transaction.Amount); Assert.Equal(Money.COIN * spendableBlocks * 50, total); // Create a token contract. ulong gasPrice = SmartContractMempoolValidator.MinGasPrice; int vmVersion = 1; Gas gasLimit = (Gas)(SmartContractFormatRule.GasLimitMaximum / 2); ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/TransferTest.cs"); Assert.True(compilationResult.Success); var contractTxData = new ContractTxData(vmVersion, gasPrice, gasLimit, compilationResult.Compilation); var contractCreateScript = new Script(callDataSerializer.Serialize(contractTxData)); var txBuildContext = new TransactionBuildContext(scSender.FullNode.Network) { AccountReference = new WalletAccountReference(WalletName, AccountName), MinConfirmations = maturity, TransactionFee = new Money(1, MoneyUnit.BTC), FeeType = FeeType.High, WalletPassword = Password, Recipients = new[] { new Recipient { Amount = 0, ScriptPubKey = contractCreateScript } }.ToList() }; Transaction transferContractTransaction = (scSender.FullNode.NodeService <IWalletTransactionHandler>() as SmartContractWalletTransactionHandler).BuildTransaction(txBuildContext); // Broadcast the token transaction to the network. scSender.FullNode.NodeService <IBroadcasterManager>().BroadcastTransactionAsync(transferContractTransaction); // Wait for the token transaction to be picked up by the mempool. TestHelper.WaitLoop(() => scSender.CreateRPCClient().GetRawMempool().Length > 0); // Mine the token transaction and wait for it to sync. TestHelper.MineBlocks(scSender, 1); // Sync to the receiver node. TestHelper.ConnectAndSync(scSender, scReceiver); // Ensure that both nodes have the contract. IStateRepositoryRoot senderState = scSender.FullNode.NodeService <IStateRepositoryRoot>(); IStateRepositoryRoot receiverState = scReceiver.FullNode.NodeService <IStateRepositoryRoot>(); IAddressGenerator addressGenerator = scSender.FullNode.NodeService <IAddressGenerator>(); uint160 tokenContractAddress = addressGenerator.GenerateAddress(transferContractTransaction.GetHash(), 0); Assert.NotNull(senderState.GetCode(tokenContractAddress)); Assert.NotNull(receiverState.GetCode(tokenContractAddress)); scSender.FullNode.MempoolManager().Clear(); // Create a transfer token contract. compilationResult = ContractCompiler.CompileFile("SmartContracts/TransferTest.cs"); Assert.True(compilationResult.Success); contractTxData = new ContractTxData(vmVersion, gasPrice, gasLimit, compilationResult.Compilation); contractCreateScript = new Script(callDataSerializer.Serialize(contractTxData)); txBuildContext = new TransactionBuildContext(scSender.FullNode.Network) { AccountReference = new WalletAccountReference(WalletName, AccountName), MinConfirmations = maturity, TransactionFee = new Money(1, MoneyUnit.BTC), FeeType = FeeType.High, WalletPassword = Password, Recipients = new[] { new Recipient { Amount = 0, ScriptPubKey = contractCreateScript } }.ToList() }; // Broadcast the token transaction to the network. transferContractTransaction = (scSender.FullNode.NodeService <IWalletTransactionHandler>() as SmartContractWalletTransactionHandler).BuildTransaction(txBuildContext); scSender.FullNode.NodeService <IBroadcasterManager>().BroadcastTransactionAsync(transferContractTransaction); // Wait for the token transaction to be picked up by the mempool. TestHelper.WaitLoop(() => scSender.CreateRPCClient().GetRawMempool().Length > 0); TestHelper.MineBlocks(scSender, 1); // Ensure both nodes are synced with each other. TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(scReceiver, scSender)); // Ensure that both nodes have the contract. senderState = scSender.FullNode.NodeService <IStateRepositoryRoot>(); receiverState = scReceiver.FullNode.NodeService <IStateRepositoryRoot>(); tokenContractAddress = addressGenerator.GenerateAddress(transferContractTransaction.GetHash(), 0); Assert.NotNull(senderState.GetCode(tokenContractAddress)); Assert.NotNull(receiverState.GetCode(tokenContractAddress)); scSender.FullNode.MempoolManager().Clear(); // Create a call contract transaction which will transfer funds. contractTxData = new ContractTxData(1, gasPrice, gasLimit, tokenContractAddress, "Test"); Script contractCallScript = new Script(callDataSerializer.Serialize(contractTxData)); txBuildContext = new TransactionBuildContext(scSender.FullNode.Network) { AccountReference = new WalletAccountReference(WalletName, AccountName), MinConfirmations = maturity, TransactionFee = new Money(1, MoneyUnit.BTC), FeeType = FeeType.High, WalletPassword = Password, Recipients = new[] { new Recipient { Amount = 1000, ScriptPubKey = contractCallScript } }.ToList() }; // Broadcast the token transaction to the network. transferContractTransaction = (scSender.FullNode.NodeService <IWalletTransactionHandler>() as SmartContractWalletTransactionHandler).BuildTransaction(txBuildContext); scSender.FullNode.NodeService <IBroadcasterManager>().BroadcastTransactionAsync(transferContractTransaction); TestHelper.WaitLoop(() => scSender.CreateRPCClient().GetRawMempool().Length > 0); // Mine the transaction. TestHelper.MineBlocks(scSender, 1); // Ensure the nodes are synced TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(scReceiver, scSender)); // The balance should now reflect the transfer. Assert.Equal((ulong)900, senderState.GetCurrentBalance(tokenContractAddress)); } }
public void SendAndReceiveSmartContractTransactionsUsingController() { using (SmartContractNodeBuilder builder = SmartContractNodeBuilder.Create(this)) { CoreNode scSender = builder.CreateSmartContractPowNode().WithWallet().Start(); CoreNode scReceiver = builder.CreateSmartContractPowNode().WithWallet().Start(); int maturity = (int)scReceiver.FullNode.Network.Consensus.CoinbaseMaturity; HdAddress addr = TestHelper.MineBlocks(scSender, maturity + 5).AddressUsed; int spendable = GetSpendableBlocks(maturity + 5, maturity); var total = scSender.FullNode.WalletManager().GetSpendableTransactionsInWallet(WalletName).Sum(s => s.Transaction.Amount); Assert.Equal(Money.COIN * spendable * 50, total); SmartContractsController senderSmartContractsController = scSender.FullNode.NodeService <SmartContractsController>(); SmartContractWalletController senderWalletController = scSender.FullNode.NodeService <SmartContractWalletController>(); ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/StorageDemo.cs"); Assert.True(compilationResult.Success); Gas gasLimit = (Gas)(SmartContractFormatRule.GasLimitMaximum / 2); var buildRequest = new BuildCreateContractTransactionRequest { AccountName = AccountName, GasLimit = gasLimit, GasPrice = SmartContractMempoolValidator.MinGasPrice, ContractCode = compilationResult.Compilation.ToHexString(), FeeAmount = "0.001", Password = Password, WalletName = WalletName, Sender = addr.Address }; JsonResult result = (JsonResult)senderSmartContractsController.BuildCreateSmartContractTransaction(buildRequest); var response = (BuildCreateContractTransactionResponse)result.Value; TestHelper.Connect(scSender, scReceiver); SmartContractSharedSteps.SendTransaction(scSender, scReceiver, senderWalletController, response.Hex); TestHelper.MineBlocks(scReceiver, 2); TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(scReceiver, scSender)); // Check receipt was stored and can be retrieved. var receiptResponse = (ReceiptResponse)((JsonResult)senderSmartContractsController.GetReceipt(response.TransactionId.ToString())).Value; Assert.True(receiptResponse.Success); Assert.Equal(response.NewContractAddress, receiptResponse.NewContractAddress); Assert.Null(receiptResponse.To); Assert.Equal(addr.Address, receiptResponse.From); string storageRequestResult = (string)((JsonResult)senderSmartContractsController.GetStorage(new GetStorageRequest { ContractAddress = response.NewContractAddress.ToString(), StorageKey = "TestSave", DataType = MethodParameterDataType.String })).Value; Assert.Equal("Hello, smart contract world!", storageRequestResult); string ownerRequestResult = (string)((JsonResult)senderSmartContractsController.GetStorage(new GetStorageRequest { ContractAddress = response.NewContractAddress.ToString(), StorageKey = "Owner", DataType = MethodParameterDataType.Address })).Value; Assert.NotEmpty(ownerRequestResult); string counterRequestResult = (string)((JsonResult)senderSmartContractsController.GetStorage(new GetStorageRequest { ContractAddress = response.NewContractAddress.ToString(), StorageKey = "Counter", DataType = MethodParameterDataType.Int })).Value; Assert.Equal("12345", counterRequestResult); var callRequest = new BuildCallContractTransactionRequest { AccountName = AccountName, GasLimit = gasLimit, GasPrice = SmartContractMempoolValidator.MinGasPrice, Amount = "0", MethodName = "Increment", ContractAddress = response.NewContractAddress, FeeAmount = "0.001", Password = Password, WalletName = WalletName, Sender = addr.Address }; result = (JsonResult)senderSmartContractsController.BuildCallSmartContractTransaction(callRequest); var callResponse = (BuildCallContractTransactionResponse)result.Value; SmartContractSharedSteps.SendTransaction(scSender, scReceiver, senderWalletController, callResponse.Hex); TestHelper.MineBlocks(scReceiver, 2); TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(scReceiver, scSender)); counterRequestResult = (string)((JsonResult)senderSmartContractsController.GetStorage(new GetStorageRequest { ContractAddress = response.NewContractAddress.ToString(), StorageKey = "Counter", DataType = MethodParameterDataType.Int })).Value; Assert.Equal("12346", counterRequestResult); // Check receipt was stored and can be retrieved. receiptResponse = (ReceiptResponse)((JsonResult)senderSmartContractsController.GetReceipt(callResponse.TransactionId.ToString())).Value; Assert.True(receiptResponse.Success); Assert.Null(receiptResponse.NewContractAddress); Assert.Equal(response.NewContractAddress, receiptResponse.To); Assert.Equal(addr.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. var serializationRequest = new BuildCallContractTransactionRequest { AccountName = AccountName, GasLimit = gasLimit, GasPrice = SmartContractMempoolValidator.MinGasPrice, Amount = "0", MethodName = "TestSerializer", ContractAddress = response.NewContractAddress, FeeAmount = "0.001", Password = Password, WalletName = WalletName, Sender = addr.Address }; result = (JsonResult)senderSmartContractsController.BuildCallSmartContractTransaction(serializationRequest); var serializationResponse = (BuildCallContractTransactionResponse)result.Value; SmartContractSharedSteps.SendTransaction(scSender, scReceiver, senderWalletController, serializationResponse.Hex); TestHelper.MineBlocks(scReceiver, 2); TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(scReceiver, scSender)); // Would have only saved if execution completed successfully counterRequestResult = (string)((JsonResult)senderSmartContractsController.GetStorage(new GetStorageRequest { ContractAddress = response.NewContractAddress.ToString(), StorageKey = "Int32", DataType = MethodParameterDataType.Int })).Value; Assert.Equal("12345", counterRequestResult); } }
public void ReorgedCoinbaseUtxoRemovedFromMempool() { var node1 = this.mockChain.Nodes[0]; var node2 = this.mockChain.Nodes[1]; var node3 = this.mockChain.Nodes[2]; int startingHeight = node1.CoreNode.FullNode.ChainIndexer.Height; // Nodes are syncing together... this.mockChain.MineBlocks(1); // Node 1 loses connection to the others foreach (var peer in node1.CoreNode.FullNode.ConnectionManager.ConnectedPeers.ToList()) { peer.Disconnect("For Testing"); } TestBase.WaitLoop(() => !node1.CoreNode.FullNode.ConnectionManager.ConnectedPeers.Any()); // Node 2 sends contract tx and creates its own chain with node 3 ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/Auction.cs"); Assert.True(compilationResult.Success); BuildCreateContractTransactionResponse response = node2.SendCreateContractTransaction(compilationResult.Compilation, 0, gasLimit: SmartContractFormatLogic.GasLimitMaximum); node3.WaitMempoolCount(1); node3.CoreNode.MineBlocksAsync(2).GetAwaiter().GetResult(); TestBase.WaitLoop(() => node2.CoreNode.FullNode.ChainIndexer.Height == startingHeight + 3); // Node gets a refund utxo in the coinbase var unspents = node2.SpendableTransactions.ToList(); Assert.True(unspents[1].Transaction.IsCoinBase); // Refund utxo is used to build a new transaction BuildCreateContractTransactionResponse response2 = node2.SendCreateContractTransaction(compilationResult.Compilation, 0, gasLimit: 15000uL, outpoints: new List <OutpointRequest> { new OutpointRequest { Index = unspents[1].Transaction.Index, TransactionId = unspents[1].Transaction.Id.ToString() } }); Transaction tx = node1.CoreNode.FullNode.Network.CreateTransaction(response2.Hex); Assert.Equal(unspents[1].Transaction.Id, tx.Inputs[0].PrevOut.Hash); node2.WaitMempoolCount(1); node3.WaitMempoolCount(1); // Other node mines far ahead node1.CoreNode.MineBlocksAsync(5).GetAwaiter().GetResult(); Assert.True(node2.CoreNode.FullNode.ChainIndexer.Height == startingHeight + 3); Assert.True(node3.CoreNode.FullNode.ChainIndexer.Height == startingHeight + 3); Assert.True(node1.CoreNode.FullNode.ChainIndexer.Height == startingHeight + 6); // Reconnect nodes. TestHelper.Connect(node1.CoreNode, node2.CoreNode); TestHelper.Connect(node1.CoreNode, node3.CoreNode); // 2 and 3 will reorg to 1's chain. TestBase.WaitLoop(() => node2.CoreNode.FullNode.ChainIndexer.Height == startingHeight + 6); TestBase.WaitLoop(() => node3.CoreNode.FullNode.ChainIndexer.Height == startingHeight + 6); // Lets give some time to the nodes to try and sort themselves out. Thread.Sleep(5_000); // Tx funded by the refund should no longer be valid on 2 or 3. It shouldn't be in the mempool. List <TxMempoolInfo> node2MempoolInfo = node2.CoreNode.FullNode.MempoolManager().InfoAll().ToList(); foreach (var mempoolInfo in node2MempoolInfo) { Assert.NotEqual(response2.TransactionId, mempoolInfo.Trx.GetHash()); } }
public void CreateContract_OneOfEachParameterType() { // Ensure fixture is funded. this.mockChain.MineBlocks(1); decimal amount = 25; uint256 currentHash = this.node1.GetLastBlock().GetHash(); ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/CreateWithAllParameters.cs"); Assert.True(compilationResult.Success); const char testChar = 'c'; string testAddressBase58 = new uint160("0x0000000000000000000000000000000000000001").ToBase58Address(this.node1.CoreNode.FullNode.Network); Address testAddress = testAddressBase58.ToAddress(this.node1.CoreNode.FullNode.Network); const bool testBool = true; const int testInt = Int32.MaxValue; const long testLong = Int64.MaxValue; const uint testUint = UInt32.MaxValue; const ulong testUlong = UInt64.MaxValue; const string testString = "The quick brown fox jumps over the lazy dog"; byte[] testBytes = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09 }; string[] parameters = new string[] { string.Format("{0}#{1}", (int)MethodParameterDataType.Char, testChar), string.Format("{0}#{1}", (int)MethodParameterDataType.Address, testAddressBase58), string.Format("{0}#{1}", (int)MethodParameterDataType.Bool, testBool), string.Format("{0}#{1}", (int)MethodParameterDataType.Int, testInt), string.Format("{0}#{1}", (int)MethodParameterDataType.Long, testLong), string.Format("{0}#{1}", (int)MethodParameterDataType.UInt, testUint), string.Format("{0}#{1}", (int)MethodParameterDataType.ULong, testUlong), string.Format("{0}#{1}", (int)MethodParameterDataType.String, testString), string.Format("{0}#{1}", (int)MethodParameterDataType.ByteArray, testBytes.ToHexString()), }; BuildCreateContractTransactionResponse response = this.node1.SendCreateContractTransaction(compilationResult.Compilation, amount, parameters); this.mockChain.WaitAllMempoolCount(1); this.mockChain.MineBlocks(1); NBitcoin.Block lastBlock = this.node1.GetLastBlock(); // Blocks progressed Assert.NotEqual(currentHash, lastBlock.GetHash()); // Contract was created Assert.NotNull(this.node1.GetCode(response.NewContractAddress)); // Block doesn't contain any extra transactions Assert.Equal(2, lastBlock.Transactions.Count); // Contract keeps balance Assert.Equal((ulong)new Money((ulong)amount, MoneyUnit.BTC), this.node1.GetContractBalance(response.NewContractAddress)); // All values were stored Assert.Equal(this.serializer.Serialize(testChar), this.node1.GetStorageValue(response.NewContractAddress, "char")); Assert.Equal(this.serializer.Serialize(testAddress), this.node1.GetStorageValue(response.NewContractAddress, "Address")); Assert.Equal(this.serializer.Serialize(testBool), this.node1.GetStorageValue(response.NewContractAddress, "bool")); Assert.Equal(this.serializer.Serialize(testInt), this.node1.GetStorageValue(response.NewContractAddress, "int")); Assert.Equal(this.serializer.Serialize(testLong), this.node1.GetStorageValue(response.NewContractAddress, "long")); Assert.Equal(this.serializer.Serialize(testUint), this.node1.GetStorageValue(response.NewContractAddress, "uint")); Assert.Equal(this.serializer.Serialize(testUlong), this.node1.GetStorageValue(response.NewContractAddress, "ulong")); Assert.Equal(this.serializer.Serialize(testString), this.node1.GetStorageValue(response.NewContractAddress, "string")); Assert.Equal(testBytes, this.node1.GetStorageValue(response.NewContractAddress, "bytes")); // Test that the contract address, event name, and logging values are available in the bloom. var scBlockHeader = lastBlock.Header as ISmartContractBlockHeader; Assert.True(scBlockHeader.LogsBloom.Test(response.NewContractAddress.ToUint160(this.node1.CoreNode.FullNode.Network).ToBytes())); Assert.True(scBlockHeader.LogsBloom.Test(Encoding.UTF8.GetBytes("Log"))); Assert.True(scBlockHeader.LogsBloom.Test(this.serializer.Serialize(testChar))); Assert.True(scBlockHeader.LogsBloom.Test(this.serializer.Serialize(testAddress))); Assert.True(scBlockHeader.LogsBloom.Test(this.serializer.Serialize(testBool))); Assert.True(scBlockHeader.LogsBloom.Test(this.serializer.Serialize(testInt))); Assert.True(scBlockHeader.LogsBloom.Test(this.serializer.Serialize(testLong))); Assert.True(scBlockHeader.LogsBloom.Test(this.serializer.Serialize(testUint))); Assert.True(scBlockHeader.LogsBloom.Test(this.serializer.Serialize(testUlong))); Assert.True(scBlockHeader.LogsBloom.Test(this.serializer.Serialize(testString))); Assert.True(scBlockHeader.LogsBloom.Test(this.serializer.Serialize(testBytes))); // And sanity test that random fields aren't contained in bloom. Assert.False(scBlockHeader.LogsBloom.Test(Encoding.UTF8.GetBytes("RandomValue"))); Assert.False(scBlockHeader.LogsBloom.Test(BitConverter.GetBytes(123))); // Receipt is correct ReceiptResponse receipt = this.node1.GetReceipt(response.TransactionId.ToString()); Assert.Equal(lastBlock.GetHash().ToString(), receipt.BlockHash); Assert.Equal(response.TransactionId.ToString(), receipt.TransactionHash); Assert.True(receipt.Success); Assert.Single(receipt.Logs); Assert.True(receipt.GasUsed > GasPriceList.BaseCost); Assert.Equal(response.NewContractAddress, receipt.NewContractAddress); Assert.Equal(this.node1.MinerAddress.Address, receipt.From); Assert.Null(receipt.To); Assert.Null(receipt.Error); }
public void SerializeArrays_ForEachMethodParamType() { // Ensure fixture is funded. this.mockChain.MineBlocks(1); decimal amount = 25; uint256 currentHash = this.node1.GetLastBlock().GetHash(); ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/CreateWithAllArrays.cs"); Assert.True(compilationResult.Success); char[] chars = new char[] { 'a', '9' }; Address[] addresses = new Address[] { this.node1.MinerAddress.Address.ToAddress(this.node1.CoreNode.FullNode.Network), "mipcBbFg9gMiCh81Kj8tqqdgoZub1ZJRfn".ToAddress(this.node1.CoreNode.FullNode.Network) }; bool[] bools = new bool[] { false, true, false }; int[] ints = new int[] { 1, -123, int.MaxValue }; long[] longs = new long[] { 1, -123, long.MaxValue }; uint[] uints = new uint[] { 1, 123, uint.MaxValue }; ulong[] ulongs = new ulong[] { 1, 123, ulong.MaxValue }; string[] strings = new string[] { "Test", "", "The quick brown fox jumps over the lazy dog" }; // TODO: Ensure Assert checks "" equality in contract when null bug fixed string[] parameters = new string[] { string.Format("{0}#{1}", (int)MethodParameterDataType.ByteArray, this.serializer.Serialize(chars).ToHexString()), string.Format("{0}#{1}", (int)MethodParameterDataType.ByteArray, this.serializer.Serialize(addresses).ToHexString()), string.Format("{0}#{1}", (int)MethodParameterDataType.ByteArray, this.serializer.Serialize(bools).ToHexString()), string.Format("{0}#{1}", (int)MethodParameterDataType.ByteArray, this.serializer.Serialize(ints).ToHexString()), string.Format("{0}#{1}", (int)MethodParameterDataType.ByteArray, this.serializer.Serialize(longs).ToHexString()), string.Format("{0}#{1}", (int)MethodParameterDataType.ByteArray, this.serializer.Serialize(uints).ToHexString()), string.Format("{0}#{1}", (int)MethodParameterDataType.ByteArray, this.serializer.Serialize(ulongs).ToHexString()), string.Format("{0}#{1}", (int)MethodParameterDataType.ByteArray, this.serializer.Serialize(strings).ToHexString()) }; BuildCreateContractTransactionResponse response = this.node1.SendCreateContractTransaction(compilationResult.Compilation, amount, parameters); this.mockChain.WaitAllMempoolCount(1); this.mockChain.MineBlocks(1); NBitcoin.Block lastBlock = this.node1.GetLastBlock(); // Blocks progressed Assert.NotEqual(currentHash, lastBlock.GetHash()); // Contract was created Assert.NotNull(this.node1.GetCode(response.NewContractAddress)); // Block doesn't contain any extra transactions Assert.Equal(2, lastBlock.Transactions.Count); // Contract keeps balance Assert.Equal((ulong)new Money((ulong)amount, MoneyUnit.BTC), this.node1.GetContractBalance(response.NewContractAddress)); // All values were stored Assert.Equal(this.serializer.Serialize(chars), this.node1.GetStorageValue(response.NewContractAddress, "chars")); Assert.Equal(this.serializer.Serialize(addresses), this.node1.GetStorageValue(response.NewContractAddress, "addresses")); Assert.Equal(this.serializer.Serialize(bools), this.node1.GetStorageValue(response.NewContractAddress, "bools")); Assert.Equal(this.serializer.Serialize(ints), this.node1.GetStorageValue(response.NewContractAddress, "ints")); Assert.Equal(this.serializer.Serialize(longs), this.node1.GetStorageValue(response.NewContractAddress, "longs")); Assert.Equal(this.serializer.Serialize(uints), this.node1.GetStorageValue(response.NewContractAddress, "uints")); Assert.Equal(this.serializer.Serialize(ulongs), this.node1.GetStorageValue(response.NewContractAddress, "ulongs")); Assert.Equal(this.serializer.Serialize(strings), this.node1.GetStorageValue(response.NewContractAddress, "strings")); // Receipt is correct ReceiptResponse receipt = this.node1.GetReceipt(response.TransactionId.ToString()); Assert.Equal(lastBlock.GetHash().ToString(), receipt.BlockHash); Assert.Equal(response.TransactionId.ToString(), receipt.TransactionHash); Assert.True(receipt.Success); Assert.Empty(receipt.Logs); Assert.True(receipt.GasUsed > GasPriceList.BaseCost); Assert.Equal(response.NewContractAddress, receipt.NewContractAddress); Assert.Equal(this.node1.MinerAddress.Address, receipt.From); Assert.Null(receipt.To); Assert.Null(receipt.Error); }
public void Internal_CallContract_SerializeEachParameterType() { // Ensure fixture is funded. this.mockChain.MineBlocks(1); // Deploy contract to send to ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/CallWithAllParameters.cs"); Assert.True(compilationResult.Success); BuildCreateContractTransactionResponse preResponse = this.node1.SendCreateContractTransaction(compilationResult.Compilation, 0); this.mockChain.WaitAllMempoolCount(1); this.mockChain.MineBlocks(1); Assert.NotNull(this.node1.GetCode(preResponse.NewContractAddress)); decimal amount = 25; uint256 currentHash = this.node1.GetLastBlock().GetHash(); const char testChar = 'c'; string testAddressBase58 = new uint160("0x0000000000000000000000000000000000000001").ToBase58Address(this.node1.CoreNode.FullNode.Network); const bool testBool = true; const int testInt = Int32.MaxValue; const long testLong = Int64.MaxValue; const uint testUint = UInt32.MaxValue; const ulong testUlong = UInt64.MaxValue; const string testString = "The quick brown fox jumps over the lazy dog"; string[] parameters = new string[] { string.Format("{0}#{1}", (int)MethodParameterDataType.Char, testChar), string.Format("{0}#{1}", (int)MethodParameterDataType.Address, testAddressBase58), string.Format("{0}#{1}", (int)MethodParameterDataType.Bool, testBool), string.Format("{0}#{1}", (int)MethodParameterDataType.Int, testInt), string.Format("{0}#{1}", (int)MethodParameterDataType.Long, testLong), string.Format("{0}#{1}", (int)MethodParameterDataType.UInt, testUint), string.Format("{0}#{1}", (int)MethodParameterDataType.ULong, testUlong), string.Format("{0}#{1}", (int)MethodParameterDataType.String, testString), string.Format("{0}#{1}", (int)MethodParameterDataType.Address, preResponse.NewContractAddress) // sendTo }; compilationResult = ContractCompiler.CompileFile("SmartContracts/ForwardParameters.cs"); BuildCreateContractTransactionResponse response = this.node1.SendCreateContractTransaction(compilationResult.Compilation, amount, parameters); this.mockChain.WaitAllMempoolCount(1); this.mockChain.MineBlocks(1); NBitcoin.Block lastBlock = this.node1.GetLastBlock(); // Blocks progressed Assert.NotEqual(currentHash, lastBlock.GetHash()); // Block contains extra transaction forwarding balance Assert.Equal(3, lastBlock.Transactions.Count); // Contract called internally gets balance Assert.Equal((ulong)new Money((ulong)amount, MoneyUnit.BTC), this.node1.GetContractBalance(preResponse.NewContractAddress)); // Receipt is correct ReceiptResponse receipt = this.node1.GetReceipt(response.TransactionId.ToString()); Assert.Equal(lastBlock.GetHash().ToString(), receipt.BlockHash); Assert.Equal(response.TransactionId.ToString(), receipt.TransactionHash); Assert.True(receipt.Success); Assert.Empty(receipt.Logs); Assert.True(receipt.GasUsed > GasPriceList.BaseCost); Assert.Equal(response.NewContractAddress, receipt.NewContractAddress); Assert.Equal(this.node1.MinerAddress.Address, receipt.From); Assert.Null(receipt.To); Assert.Null(receipt.Error); }
public void GetHexStringForDemo() { ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/Auction.cs"); string example = compilationResult.Compilation.ToHexString(); }
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)); } }
public ContractAssemblyTests() { this.compilation = ContractCompiler.CompileFile(this.Contract); this.loader = new ContractAssemblyLoader(); }
public void InternalTransfer_ToContractAddress() { // Ensure fixture is funded. this.mockChain.MineBlocks(1); // Deploy contract to send to ContractCompilationResult receiveCompilationResult = ContractCompiler.CompileFile("SmartContracts/BasicReceive.cs"); Assert.True(receiveCompilationResult.Success); BuildCreateContractTransactionResponse receiveResponse = this.node1.SendCreateContractTransaction(receiveCompilationResult.Compilation, 0); this.mockChain.WaitAllMempoolCount(1); this.mockChain.MineBlocks(1); Assert.NotNull(this.node1.GetCode(receiveResponse.NewContractAddress)); // Deploy contract to send from ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/BasicTransfer.cs"); Assert.True(compilationResult.Success); BuildCreateContractTransactionResponse preResponse = this.node1.SendCreateContractTransaction(compilationResult.Compilation, 0); this.mockChain.WaitAllMempoolCount(1); this.mockChain.MineBlocks(1); Assert.NotNull(this.node1.GetCode(preResponse.NewContractAddress)); decimal amount = 25; Money senderBalanceBefore = this.node1.WalletSpendableBalance; uint256 currentHash = this.node1.GetLastBlock().GetHash(); // Send amount to contract, which will send to contract address string[] parameters = new string[] { string.Format("{0}#{1}", (int)MethodParameterDataType.Address, receiveResponse.NewContractAddress) }; BuildCallContractTransactionResponse response = this.node1.SendCallContractTransaction( nameof(BasicTransfer.SendToAddress), preResponse.NewContractAddress, amount, parameters); this.mockChain.WaitAllMempoolCount(1); this.mockChain.MineBlocks(1); NBitcoin.Block lastBlock = this.node1.GetLastBlock(); // Blocks progressed Assert.NotEqual(currentHash, lastBlock.GetHash()); // Contract doesn't maintain any balance Assert.Equal((ulong)0, this.node1.GetContractBalance(preResponse.NewContractAddress)); // Receiver contract now has balance Assert.Equal((ulong)new Money((int)amount, MoneyUnit.BTC), this.node1.GetContractBalance(receiveResponse.NewContractAddress)); // Receiver contract stored to state Assert.Equal(new byte[] { 1 }, this.node1.GetStorageValue(receiveResponse.NewContractAddress, BasicReceive.ReceiveKey)); // Log was stored - bloom filter should be non-zero Assert.NotEqual(new Bloom(), ((ISmartContractBlockHeader)lastBlock.Header).LogsBloom); // Block contains a condensing transaction Assert.Equal(3, lastBlock.Transactions.Count); Transaction condensingTransaction = lastBlock.Transactions[2]; Assert.Single(condensingTransaction.Outputs); // Entire balance was forwarded byte[] toBytes = condensingTransaction.Outputs[0].ScriptPubKey.ToBytes(); Assert.Equal((byte)ScOpcodeType.OP_INTERNALCONTRACTTRANSFER, toBytes[0]); uint160 toAddress = new uint160(toBytes.Skip(1).ToArray()); Assert.Equal(receiveResponse.NewContractAddress, toAddress.ToBase58Address(this.node1.CoreNode.FullNode.Network)); Assert.Equal(new Money((long)amount, MoneyUnit.BTC), condensingTransaction.Outputs[0].Value); // Receipt is correct ReceiptResponse receipt = this.node1.GetReceipt(response.TransactionId.ToString()); Assert.Equal(lastBlock.GetHash().ToString(), receipt.BlockHash); Assert.Equal(response.TransactionId.ToString(), receipt.TransactionHash); Assert.Single(receipt.Logs); Assert.Equal(receiveResponse.NewContractAddress, receipt.Logs[0].Address); Assert.True(receipt.Success); Assert.True(receipt.GasUsed > GasPriceList.BaseCost); Assert.Null(receipt.NewContractAddress); Assert.Equal(this.node1.MinerAddress.Address, receipt.From); Assert.Null(receipt.Error); Assert.Equal(preResponse.NewContractAddress, receipt.To); }
public void InternalTransfer_ToContractAddress() { // Deploy contract to send to ContractCompilationResult receiveCompilationResult = ContractCompiler.CompileFile("SmartContracts/BasicReceive.cs"); Assert.True(receiveCompilationResult.Success); BuildCreateContractTransactionResponse receiveResponse = this.node1.SendCreateContractTransaction(receiveCompilationResult.Compilation, 0); this.node1.WaitMempoolCount(1); this.node1.WaitForBlocksToBeMined(1); Assert.NotNull(this.node1.GetCode(receiveResponse.NewContractAddress)); // Deploy contract to send from ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/BasicTransfer.cs"); Assert.True(compilationResult.Success); BuildCreateContractTransactionResponse preResponse = this.node1.SendCreateContractTransaction(compilationResult.Compilation, 0); this.node1.WaitMempoolCount(1); this.node1.WaitForBlocksToBeMined(1); Assert.NotNull(this.node1.GetCode(preResponse.NewContractAddress)); double amount = 25; uint256 currentHash = this.node1.GetLastBlock().GetHash(); // Send amount to contract, which will send to contract address string[] parameters = new string[] { string.Format("{0}#{1}", (int)MethodParameterDataType.Address, receiveResponse.NewContractAddress.ToAddress(this.mockChain.Network)) }; BuildCallContractTransactionResponse response = this.node1.SendCallContractTransaction( nameof(BasicTransfer.SendToAddress), preResponse.NewContractAddress, amount, parameters); this.node2.WaitMempoolCount(1); this.node2.WaitForBlocksToBeMined(1); NBitcoin.Block lastBlock = this.node1.GetLastBlock(); // Blocks progressed Assert.NotEqual(currentHash, lastBlock.GetHash()); // Contract doesn't maintain any balance Assert.Equal((ulong)0, this.node1.GetContractBalance(preResponse.NewContractAddress)); // Receiver contract now has balance Assert.Equal((ulong)new Money((int)amount, MoneyUnit.BTC), this.node1.GetContractBalance(receiveResponse.NewContractAddress)); // Receiver contract stored to state Assert.Equal(new byte[] { 1 }, this.node1.GetStorageValue(receiveResponse.NewContractAddress, BasicReceive.ReceiveKey)); // Receipt is correct ReceiptResponse receipt = this.node1.GetReceipt(response.TransactionId.ToString()); Assert.Equal(response.TransactionId.ToString(), receipt.TransactionHash); Assert.Single(receipt.Logs); Assert.Equal(receiveResponse.NewContractAddress, receipt.Logs[0].Address); Assert.True(receipt.Success); Assert.True(receipt.GasUsed > GasPriceList.BaseCost); Assert.Null(receipt.NewContractAddress); Assert.Equal(this.node1.MinerAddress.Address, receipt.From); Assert.Null(receipt.Error); Assert.Equal(preResponse.NewContractAddress, receipt.To); }