public void InternalTransfer_CreateMultipleContracts_FromConstructor_NonceIncreases() { // Ensure fixture is funded. this.mockChain.MineBlocks(1); decimal amount = 25; // Deploy contract ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/NonceTest.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)); // Check that there is code for nonces 1 and 3 (not 2, contract deployment should have failed). uint160 successAddress1 = this.addressGenerator.GenerateAddress(response.TransactionId, 1); uint160 failAddress = this.addressGenerator.GenerateAddress(response.TransactionId, 2); uint160 successAddress2 = this.addressGenerator.GenerateAddress(response.TransactionId, 3); Assert.NotNull(this.node1.GetCode(successAddress1.ToBase58Address(this.node1.CoreNode.FullNode.Network))); Assert.Null(this.node1.GetCode(failAddress.ToBase58Address(this.node1.CoreNode.FullNode.Network))); Assert.NotNull(this.node1.GetCode(successAddress2.ToBase58Address(this.node1.CoreNode.FullNode.Network))); Assert.Equal((ulong)1, this.node1.GetContractBalance(successAddress1.ToBase58Address(this.node1.CoreNode.FullNode.Network))); Assert.Equal((ulong)0, this.node1.GetContractBalance(failAddress.ToBase58Address(this.node1.CoreNode.FullNode.Network))); Assert.Equal((ulong)1, this.node1.GetContractBalance(successAddress2.ToBase58Address(this.node1.CoreNode.FullNode.Network))); }
public void External_Call_Balance_Correct() { // Ensure fixture is funded. this.mockChain.MineBlocks(1); // Deploy contract ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/ReceiveFundsTest.cs"); Assert.True(compilationResult.Success); BuildCreateContractTransactionResponse response = this.node1.SendCreateContractTransaction(compilationResult.Compilation, 0); this.mockChain.WaitAllMempoolCount(1); this.mockChain.MineBlocks(1); Assert.NotNull(this.node1.GetCode(response.NewContractAddress)); uint160 contractAddress = this.addressGenerator.GenerateAddress(response.TransactionId, 0); ulong amount = 25; BuildCallContractTransactionResponse callResponse = this.node1.SendCallContractTransaction( nameof(ReceiveFundsTest.MethodReceiveFunds), response.NewContractAddress, amount); this.mockChain.WaitAllMempoolCount(1); this.mockChain.MineBlocks(1); // 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 ExternalTransfer_ReceiveHandler_WithValue() { // Deploy contract ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/ReceiveFundsTest.cs"); Assert.True(compilationResult.Success); BuildCreateContractTransactionResponse response = this.node1.SendCreateContractTransaction(compilationResult.Compilation, 0); this.node2.WaitMempoolCount(1); this.node2.WaitForBlocksToBeMined(1); Assert.NotNull(this.node1.GetCode(response.NewContractAddress)); uint160 contractAddress = this.addressGenerator.GenerateAddress(response.TransactionId, 0); ulong amount = 123; BuildCallContractTransactionResponse callResponse = this.node1.SendCallContractTransaction( MethodCall.ReceiveHandlerName, response.NewContractAddress, amount); this.node2.WaitMempoolCount(1); this.node2.WaitForBlocksToBeMined(1); // Stored balance in PersistentState should be only that which was sent byte[] saved = this.node1.GetStorageValue(contractAddress.ToBase58Address(this.mockChain.Network), "ReceiveBalance"); ulong savedUlong = BitConverter.ToUInt64(saved); Assert.True((new Money(amount, MoneyUnit.BTC) == new Money(savedUlong, MoneyUnit.Satoshi))); }
public void Transfers_Summed_Correctly() { uint160 contractAddress = new uint160(1); uint160 receiverAddress = new uint160(2); uint160 thirdAddress = new uint160(3); // Has balance var stateMock = new Mock <IStateRepository>(); stateMock.Setup(x => x.GetAccountState(contractAddress)).Returns(new AccountState { CodeHash = new byte[32], StateRoot = new byte[32], TypeName = "Mock", UnspentHash = new byte[32] }); stateMock.Setup(x => x.GetUnspent(contractAddress)).Returns(new ContractUnspentOutput { Hash = new uint256(1), Nvout = 1, Value = 100 }); // no tx value var txContextMock = new Mock <IContractTransactionContext>(); txContextMock.SetupGet(p => p.TxOutValue).Returns(0); // several transfers var transferInfos = new List <TransferInfo> { new TransferInfo(contractAddress, receiverAddress, 75), new TransferInfo(receiverAddress, contractAddress, 20), new TransferInfo(receiverAddress, thirdAddress, 5) }; // End result should be Contract: 45, Receiver: 50, ThirdAddress: 5 // Condensing tx generated. 1 input. 3 outputs with consolidated balances. Transaction internalTransaction = this.transferProcessor.Process(stateMock.Object, contractAddress, txContextMock.Object, transferInfos, false); Assert.NotNull(internalTransaction); Assert.Single(internalTransaction.Inputs); Assert.Equal(3, internalTransaction.Outputs.Count); Assert.Equal(new uint256(1), internalTransaction.Inputs[0].PrevOut.Hash); Assert.Equal((uint)1, internalTransaction.Inputs[0].PrevOut.N); string output1Address = PayToPubkeyHashTemplate.Instance.ExtractScriptPubKeyParameters(internalTransaction.Outputs[0].ScriptPubKey).GetAddress(this.network).ToString(); Assert.Equal(receiverAddress.ToBase58Address(this.network), output1Address); Assert.Equal(50, internalTransaction.Outputs[0].Value); Assert.True(internalTransaction.Outputs[1].ScriptPubKey.IsSmartContractInternalCall()); Assert.Equal(45, internalTransaction.Outputs[1].Value); string output3Address = PayToPubkeyHashTemplate.Instance.ExtractScriptPubKeyParameters(internalTransaction.Outputs[2].ScriptPubKey).GetAddress(this.network).ToString(); Assert.Equal(thirdAddress.ToBase58Address(this.network), output3Address); Assert.Equal(5, internalTransaction.Outputs[2].Value); // Ensure db updated stateMock.Verify(x => x.SetUnspent(contractAddress, It.Is <ContractUnspentOutput>(unspent => unspent.Value == 45)), Times.Once); }
public void Test_CatCreation() { using (PoWMockChain chain = new PoWMockChain(2)) { MockChainNode sender = chain.Nodes[0]; MockChainNode receiver = chain.Nodes[1]; sender.MineBlocks(1); ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/ContractCreation.cs"); Assert.True(compilationResult.Success); // Create contract and ensure code exists BuildCreateContractTransactionResponse response = sender.SendCreateContractTransaction(compilationResult.Compilation, 0); 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"))); // Do a create that should transfer all funds sent now. decimal amount = 20; BuildCallContractTransactionResponse callResponse2 = sender.SendCallContractTransaction("CreateCatWithFunds", response.NewContractAddress, amount); receiver.WaitMempoolCount(1); receiver.MineBlocks(1); // Check created contract has expected balance. lastCreatedCatAddress = new uint160(sender.GetStorageValue(response.NewContractAddress, "LastCreatedCat")); Assert.Equal(amount * Money.COIN, sender.GetContractBalance(lastCreatedCatAddress.ToBase58Address(sender.CoreNode.FullNode.Network))); // Check block has 3 transactions. Coinbase, our tx, and then a condensing tx. var block = receiver.GetLastBlock(); Assert.Equal(3, block.Transactions.Count); // Condensing tx has 1 input and 1 output - FROM: real tx. TO: new contract address. Assert.Single(block.Transactions[2].Inputs); Assert.Single(block.Transactions[2].Outputs); Assert.Equal(block.Transactions[1].GetHash(), block.Transactions[2].Inputs[0].PrevOut.Hash); // References tx above. Assert.Equal(amount * Money.COIN, (ulong)block.Transactions[2].Outputs[0].Value); Assert.True(block.Transactions[2].Inputs[0].ScriptSig.IsSmartContractSpend()); Assert.True(block.Transactions[2].Outputs[0].ScriptPubKey.IsSmartContractInternalCall()); } }
public void HasBalance_TxValue1_TransferValue1() { uint160 contractAddress = new uint160(1); uint160 receiverAddress = new uint160(2); // Has balance var stateMock = new Mock <IStateRepository>(); stateMock.Setup(x => x.GetAccountState(contractAddress)).Returns(new AccountState { CodeHash = new byte[32], StateRoot = new byte[32], TypeName = "Mock", UnspentHash = new byte[32] }); stateMock.Setup(x => x.GetUnspent(contractAddress)).Returns(new ContractUnspentOutput { Hash = new uint256(1), Nvout = 1, Value = 100 }); // no tx value var txContextMock = new Mock <IContractTransactionContext>(); txContextMock.SetupGet(p => p.TxOutValue).Returns(100); txContextMock.SetupGet(p => p.TransactionHash).Returns(new uint256(123)); txContextMock.SetupGet(p => p.Nvout).Returns(1); txContextMock.SetupGet(p => p.Time).Returns(12345); // transfer 75 var transferInfos = new List <TransferInfo> { new TransferInfo(contractAddress, receiverAddress, 75) }; // Condensing tx generated. 2 inputs from currently stored utxo and current tx. 2 outputs for each receiver and contract. Transaction internalTransaction = this.transferProcessor.Process(stateMock.Object, contractAddress, txContextMock.Object, transferInfos, false); Assert.NotNull(internalTransaction); Assert.Equal(txContextMock.Object.Time, internalTransaction.Time); Assert.Equal(2, internalTransaction.Inputs.Count); Assert.Equal(2, internalTransaction.Outputs.Count); Assert.Equal(new uint256(123), internalTransaction.Inputs[0].PrevOut.Hash); Assert.Equal((uint)1, internalTransaction.Inputs[0].PrevOut.N); Assert.Equal(new uint256(1), internalTransaction.Inputs[1].PrevOut.Hash); Assert.Equal((uint)1, internalTransaction.Inputs[1].PrevOut.N); Assert.True(internalTransaction.Outputs[0].ScriptPubKey.IsSmartContractInternalCall()); Assert.Equal(125, internalTransaction.Outputs[0].Value); string output2Address = PayToPubkeyHashTemplate.Instance.ExtractScriptPubKeyParameters(internalTransaction.Outputs[1].ScriptPubKey).GetAddress(this.network).ToString(); Assert.Equal(receiverAddress.ToBase58Address(this.network), output2Address); Assert.Equal(75, internalTransaction.Outputs[1].Value); // Ensure db updated stateMock.Verify(x => x.SetUnspent(contractAddress, It.Is <ContractUnspentOutput>(unspent => unspent.Value == 125)), Times.Once); }
public void ContractTransaction_EmptyModule_Failure() { // Ensure fixture is funded. this.node1.MineBlocks(1); double amount = 25; Money senderBalanceBefore = this.node1.WalletSpendableBalance; uint256 currentHash = this.node1.GetLastBlock().GetHash(); // Create transaction with empty module var module = ModuleDefinition.CreateModule("SmartContract", ModuleKind.Dll); byte[] emptyModule; using (var ms = new MemoryStream()) { module.Write(ms); emptyModule = ms.ToArray(); } Assert.Single(module.Types); Assert.Equal("<Module>", module.Types[0].Name); BuildCreateContractTransactionResponse response = this.node1.SendCreateContractTransaction(emptyModule, amount); this.node2.WaitMempoolCount(1); this.node2.MineBlocks(1); NBitcoin.Block lastBlock = this.node1.GetLastBlock(); // Blocks progressed Assert.NotEqual(currentHash, lastBlock.GetHash()); // Contract wasn't created Assert.Null(this.node2.GetCode(response.NewContractAddress)); // Block contains a refund transaction Assert.Equal(3, lastBlock.Transactions.Count); Transaction refundTransaction = lastBlock.Transactions[2]; uint160 refundReceiver = this.senderRetriever.GetAddressFromScript(refundTransaction.Outputs[0].ScriptPubKey).Sender; Assert.Equal(this.node1.MinerAddress.Address, refundReceiver.ToBase58Address(this.mockChain.Network)); Assert.Equal(new Money((long)amount, MoneyUnit.BTC), refundTransaction.Outputs[0].Value); Money fee = lastBlock.Transactions[0].Outputs[0].Value - new Money(50, MoneyUnit.BTC); // Amount was refunded to wallet, minus fee Assert.Equal(senderBalanceBefore - this.node1.WalletSpendableBalance, fee); // 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); Assert.False(receipt.Success); Assert.Equal(GasPriceList.CreateCost, receipt.GasUsed); Assert.Null(receipt.NewContractAddress); Assert.Equal(this.node1.MinerAddress.Address, receipt.From); Assert.Null(receipt.To); }
public void ContractTransaction_ExceptionInCreate() { // Ensure fixture is funded. this.node1.MineBlocks(1); double amount = 25; Money senderBalanceBefore = this.node1.WalletSpendableBalance; uint256 currentHash = this.node1.GetLastBlock().GetHash(); ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/ExceptionInConstructor.cs"); Assert.True(compilationResult.Success); BuildCreateContractTransactionResponse response = this.node1.SendCreateContractTransaction(compilationResult.Compilation, amount); this.node2.WaitMempoolCount(1); this.node2.MineBlocks(1); NBitcoin.Block lastBlock = this.node1.GetLastBlock(); // Blocks progressed Assert.NotEqual(currentHash, lastBlock.GetHash()); // Contract wasn't created Assert.Null(this.node2.GetCode(response.NewContractAddress)); // State wasn't persisted Assert.Null(this.node2.GetStorageValue(response.NewContractAddress, "Test")); // Logs weren't persisted Assert.Equal(new Bloom(), ((SmartContractBlockHeader)lastBlock.Header).LogsBloom); // Block contains a refund transaction Assert.Equal(3, lastBlock.Transactions.Count); Transaction refundTransaction = lastBlock.Transactions[2]; Assert.Single(refundTransaction.Outputs); // No transfers persisted uint160 refundReceiver = this.senderRetriever.GetAddressFromScript(refundTransaction.Outputs[0].ScriptPubKey).Sender; Assert.Equal(this.node1.MinerAddress.Address, refundReceiver.ToBase58Address(this.mockChain.Network)); Assert.Equal(new Money((long)amount, MoneyUnit.BTC), refundTransaction.Outputs[0].Value); Money fee = lastBlock.Transactions[0].Outputs[0].Value - new Money(50, MoneyUnit.BTC); // Amount was refunded to wallet, minus fee Assert.Equal(senderBalanceBefore - this.node1.WalletSpendableBalance, fee); // 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); Assert.False(receipt.Success); Assert.True(receipt.GasUsed > GasPriceList.BaseCost); Assert.Null(receipt.NewContractAddress); Assert.Equal(this.node1.MinerAddress.Address, receipt.From); Assert.StartsWith("System.IndexOutOfRangeException", receipt.Error); Assert.Null(receipt.To); }
public void ContractTransaction_Create_IncorrectParameters() { // Ensure fixture is funded. this.node1.MineBlocks(1); double amount = 25; Money senderBalanceBefore = this.node1.WalletSpendableBalance; uint256 currentHash = this.node1.GetLastBlock().GetHash(); ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/BasicParameters.cs"); Assert.True(compilationResult.Success); string[] parameters = new string[] { string.Format("{0}#{1}", (int)MethodParameterDataType.ULong, UInt64.MaxValue) }; BuildCreateContractTransactionResponse response = this.node1.SendCreateContractTransaction(compilationResult.Compilation, amount, parameters); this.node2.WaitMempoolCount(1); this.node2.MineBlocks(1); NBitcoin.Block lastBlock = this.node1.GetLastBlock(); // Blocks progressed Assert.NotEqual(currentHash, lastBlock.GetHash()); // Contract wasn't created Assert.Null(this.node2.GetCode(response.NewContractAddress)); // State wasn't persisted Assert.Null(this.node2.GetStorageValue(response.NewContractAddress, "Created")); // Logs weren't persisted Assert.Equal(new Bloom(), ((SmartContractBlockHeader)lastBlock.Header).LogsBloom); // Block contains a refund transaction Assert.Equal(3, lastBlock.Transactions.Count); Transaction refundTransaction = lastBlock.Transactions[2]; Assert.Single(refundTransaction.Outputs); // No transfers persisted uint160 refundReceiver = this.senderRetriever.GetAddressFromScript(refundTransaction.Outputs[0].ScriptPubKey).Sender; Assert.Equal(this.node1.MinerAddress.Address, refundReceiver.ToBase58Address(this.mockChain.Network)); Assert.Equal(new Money((long)amount, MoneyUnit.BTC), refundTransaction.Outputs[0].Value); Money fee = lastBlock.Transactions[0].Outputs[0].Value - new Money(50, MoneyUnit.BTC); // Amount was refunded to wallet, minus fee Assert.Equal(senderBalanceBefore - this.node1.WalletSpendableBalance, fee); // 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); Assert.False(receipt.Success); Assert.Equal(GasPriceList.CreateCost, receipt.GasUsed); Assert.Null(receipt.NewContractAddress); Assert.Equal(this.node1.MinerAddress.Address, receipt.From); Assert.StartsWith(ContractInvocationErrors.MethodDoesNotExist, receipt.Error); // The error for constructor not found vs method does not exist could be different in future. Assert.Null(receipt.To); }
public void ContractTransaction_CallPrivateMethod() { // Ensure fixture is funded. this.mockChain.MineBlocks(1); // Deploy contract ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/PrivateMethod.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)); double amount = 25; Money senderBalanceBefore = this.node1.WalletSpendableBalance; uint256 currentHash = this.node1.GetLastBlock().GetHash(); BuildCallContractTransactionResponse response = this.node1.SendCallContractTransaction("CallMe", preResponse.NewContractAddress, amount); this.mockChain.WaitAllMempoolCount(1); this.mockChain.MineBlocks(1); NBitcoin.Block lastBlock = this.node1.GetLastBlock(); // Blocks progressed Assert.NotEqual(currentHash, lastBlock.GetHash()); // State wasn't persisted Assert.Null(this.node2.GetStorageValue(preResponse.NewContractAddress, "Called")); // Logs weren't persisted Assert.Equal(new Bloom(), ((ISmartContractBlockHeader)lastBlock.Header).LogsBloom); // Block contains a refund transaction Assert.Equal(3, lastBlock.Transactions.Count); Transaction refundTransaction = lastBlock.Transactions[2]; Assert.Single(refundTransaction.Outputs); // No transfers persisted uint160 refundReceiver = this.senderRetriever.GetAddressFromScript(refundTransaction.Outputs[0].ScriptPubKey).Sender; Assert.Equal(this.node1.MinerAddress.Address, refundReceiver.ToBase58Address(this.node1.CoreNode.FullNode.Network)); Assert.Equal(new Money((long)amount, MoneyUnit.BTC), refundTransaction.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.Empty(receipt.Logs); Assert.False(receipt.Success); Assert.Equal(GasPriceList.BaseCost, receipt.GasUsed); Assert.Null(receipt.NewContractAddress); Assert.Equal(this.node1.MinerAddress.Address, receipt.From); Assert.Equal(ContractInvocationErrors.MethodDoesNotExist, receipt.Error); Assert.Equal(preResponse.NewContractAddress, receipt.To); }
public void ContractTransaction_RecursiveContractCall_OutOfGas() { // Ensure fixture is funded. this.node1.MineBlocks(1); // Deploy contract ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/RecursiveLoopCall.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; ulong gasLimit = SmartContractFormatRule.GasLimitMaximum; Money senderBalanceBefore = this.node1.WalletSpendableBalance; uint256 currentHash = this.node1.GetLastBlock().GetHash(); BuildCallContractTransactionResponse response = this.node1.SendCallContractTransaction(nameof(RecursiveLoopCall.Call), preResponse.NewContractAddress, amount, gasLimit: gasLimit); this.node2.WaitMempoolCount(1); this.node2.WaitForBlocksToBeMined(1); NBitcoin.Block lastBlock = this.node1.GetLastBlock(); // Blocks progressed Assert.NotEqual(currentHash, lastBlock.GetHash()); // Block contains a refund transaction Assert.Equal(3, lastBlock.Transactions.Count); Transaction refundTransaction = lastBlock.Transactions[2]; Assert.Single(refundTransaction.Outputs); // No transfers persisted uint160 refundReceiver = this.senderRetriever.GetAddressFromScript(refundTransaction.Outputs[0].ScriptPubKey).Sender; Assert.Equal(this.node1.MinerAddress.Address, refundReceiver.ToBase58Address(this.mockChain.Network)); Assert.Equal(new Money((long)amount, MoneyUnit.BTC), refundTransaction.Outputs[0].Value); Money fee = lastBlock.Transactions[0].Outputs[0].Value - new Money(50, MoneyUnit.BTC); // Amount was refunded to wallet, minus fee Assert.Equal(senderBalanceBefore - this.node1.WalletSpendableBalance, fee); // 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); Assert.False(receipt.Success); Assert.True(receipt.GasUsed > (gasLimit - GasPriceList.BaseCost)); // The amount spent should be within 1 BaseCost of being used up. Assert.Null(receipt.NewContractAddress); Assert.Equal(this.node1.MinerAddress.Address, receipt.From); Assert.StartsWith("Stratis.SmartContracts.SmartContractAssertException", receipt.Error); Assert.Equal(preResponse.NewContractAddress, receipt.To); }
public void NoBalance_TxValue1_TransferValue1() { uint160 contractAddress = new uint160(1); uint160 receiverAddress = new uint160(2); // No balance var stateMock = new Mock <IStateRepository>(); stateMock.Setup(x => x.GetAccountState(contractAddress)).Returns(new AccountState { CodeHash = new byte[32], StateRoot = new byte[32], TypeName = "Mock", UnspentHash = new byte[32] }); stateMock.Setup(x => x.GetUnspent(contractAddress)).Returns <ContractUnspentOutput>(null); // tx value 100 var txContextMock = new Mock <IContractTransactionContext>(); txContextMock.SetupGet(p => p.TxOutValue).Returns(100); txContextMock.SetupGet(p => p.TransactionHash).Returns(new uint256(123)); txContextMock.SetupGet(p => p.Nvout).Returns(1); txContextMock.SetupGet(p => p.Time).Returns(12345); // transfer 75 var transferInfos = new List <TransferInfo> { new TransferInfo(contractAddress, receiverAddress, 75) }; // Condensing tx generated. 1 input from tx and 2 outputs - 1 for each contract and receiver Transaction internalTransaction = this.transferProcessor.Process(stateMock.Object, contractAddress, txContextMock.Object, transferInfos, false); Assert.NotNull(internalTransaction); if (internalTransaction is IPosTransactionWithTime posTx) { Assert.Equal(txContextMock.Object.Time, posTx.Time); } Assert.Single(internalTransaction.Inputs); Assert.Equal(2, internalTransaction.Outputs.Count); Assert.Equal(txContextMock.Object.TransactionHash, internalTransaction.Inputs[0].PrevOut.Hash); Assert.Equal(txContextMock.Object.Nvout, internalTransaction.Inputs[0].PrevOut.N); string output1Address = PayToPubkeyHashTemplate.Instance.ExtractScriptPubKeyParameters(internalTransaction.Outputs[0].ScriptPubKey).GetAddress(this.network).ToString(); Assert.Equal(receiverAddress.ToBase58Address(this.network), output1Address); Assert.Equal(75, internalTransaction.Outputs[0].Value); // Note outputs are in descending order by value. Assert.True(internalTransaction.Outputs[1].ScriptPubKey.IsSmartContractInternalCall()); Assert.Equal(25, internalTransaction.Outputs[1].Value); // Ensure db updated stateMock.Verify(x => x.SetUnspent(contractAddress, It.Is <ContractUnspentOutput>(unspent => unspent.Value == 25)), Times.Once); }
public void Address_Json_Outputs_As_Base58String() { uint160 testUint160 = new uint160(123); Address testAddress = testUint160.ToAddress(); string expectedString = testUint160.ToBase58Address(this.network); string jsonOutput = JsonConvert.SerializeObject(testAddress, new JsonSerializerSettings { ContractResolver = this.resolver }); Assert.Equal(expectedString, jsonOutput.Replace("\"", "")); }
public void ContractTransaction_ValidationFailure() { // Ensure fixture is funded. this.node1.MineBlocks(1); double amount = 25; Money senderBalanceBefore = this.node1.WalletSpendableBalance; uint256 currentHash = this.node1.GetLastBlock().GetHash(); // Create transaction with non-deterministic bytecode. ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/NonDeterministicContract.cs"); Assert.True(compilationResult.Success); BuildCreateContractTransactionResponse response = this.node1.SendCreateContractTransaction(compilationResult.Compilation, amount); this.node2.WaitMempoolCount(1); this.node2.MineBlocks(1); NBitcoin.Block lastBlock = this.node1.GetLastBlock(); // Blocks progressed Assert.NotEqual(currentHash, lastBlock.GetHash()); // Contract wasn't created Assert.Null(this.node2.GetCode(response.NewContractAddress)); // Block contains a refund transaction Assert.Equal(3, lastBlock.Transactions.Count); Transaction refundTransaction = lastBlock.Transactions[2]; uint160 refundReceiver = this.senderRetriever.GetAddressFromScript(refundTransaction.Outputs[0].ScriptPubKey).Sender; Assert.Equal(this.node1.MinerAddress.Address, refundReceiver.ToBase58Address(this.node1.CoreNode.FullNode.Network)); Assert.Equal(new Money((long)amount, MoneyUnit.BTC), refundTransaction.Outputs[0].Value); Money fee = lastBlock.Transactions[0].Outputs[0].Value - new Money(50, MoneyUnit.BTC); // Amount was refunded to wallet, minus fee Assert.Equal(senderBalanceBefore - this.node1.WalletSpendableBalance, fee); // 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); Assert.False(receipt.Success); Assert.Equal(GasPriceList.CreateCost, receipt.GasUsed); Assert.Null(receipt.NewContractAddress); Assert.Equal(this.node1.MinerAddress.Address, receipt.From); Assert.Null(receipt.To); }
public void ContractTransaction_InvalidByteCode() { // Ensure fixture is funded. this.node1.MineBlocks(1); double amount = 25; Money senderBalanceBefore = this.node1.WalletSpendableBalance; uint256 currentHash = this.node1.GetLastBlock().GetHash(); // Create transaction with random bytecode. var random = new Random(); byte[] bytes = new byte[100]; random.NextBytes(bytes); BuildCreateContractTransactionResponse response = this.node1.SendCreateContractTransaction(bytes, amount); this.node2.WaitMempoolCount(1); this.node2.MineBlocks(1); NBitcoin.Block lastBlock = this.node1.GetLastBlock(); // Blocks progressed Assert.NotEqual(currentHash, lastBlock.GetHash()); // Contract wasn't created Assert.Null(this.node1.GetCode(response.NewContractAddress)); // Block contains a refund transaction Assert.Equal(3, lastBlock.Transactions.Count); Transaction refundTransaction = lastBlock.Transactions[2]; uint160 refundReceiver = this.senderRetriever.GetAddressFromScript(refundTransaction.Outputs[0].ScriptPubKey).Sender; Assert.Equal(this.node1.MinerAddress.Address, refundReceiver.ToBase58Address(this.mockChain.Network)); Assert.Equal(new Money((long)amount, MoneyUnit.BTC), refundTransaction.Outputs[0].Value); Money fee = lastBlock.Transactions[0].Outputs[0].Value - new Money(50, MoneyUnit.BTC); // Amount was refunded to wallet, minus fee Assert.Equal(senderBalanceBefore - this.node1.WalletSpendableBalance, fee); // 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); Assert.False(receipt.Success); Assert.Equal(GasPriceList.CreateCost, receipt.GasUsed); Assert.Null(receipt.NewContractAddress); Assert.Equal(this.node1.MinerAddress.Address, receipt.From); Assert.Null(receipt.To); }
public void ContractTransaction_MemoryLimit() { // Deploy contract ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/MemoryConsumingContract.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(); string[] parameters = new string[] { string.Format("{0}#{1}", (int)MethodParameterDataType.Int, 100001) }; BuildCallContractTransactionResponse response = this.node1.SendCallContractTransaction("UseTooMuchMemory", 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 refund transaction Assert.Equal(3, lastBlock.Transactions.Count); Transaction refundTransaction = lastBlock.Transactions[2]; Assert.Single(refundTransaction.Outputs); // No transfers persisted uint160 refundReceiver = this.senderRetriever.GetAddressFromScript(refundTransaction.Outputs[0].ScriptPubKey).Sender; Assert.Equal(this.node1.MinerAddress.Address, refundReceiver.ToBase58Address(this.node1.CoreNode.FullNode.Network)); Assert.Equal(new Money((long)amount, MoneyUnit.BTC), refundTransaction.Outputs[0].Value); Money fee = lastBlock.Transactions[0].Outputs[0].Value - new Money(50, MoneyUnit.BTC); // 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); Assert.False(receipt.Success); Assert.True(GasPriceList.BaseCost < receipt.GasUsed); Assert.Null(receipt.NewContractAddress); Assert.Equal(this.node1.MinerAddress.Address, receipt.From); Assert.StartsWith($"{typeof(MemoryConsumptionException).FullName}", receipt.Error); Assert.Equal(preResponse.NewContractAddress, receipt.To); }
public void Internal_Nested_Transfer_Balance_Correct() { // Ensure fixture is funded. this.mockChain.MineBlocks(1); decimal 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)); // Deploy second contract BuildCreateContractTransactionResponse response2 = this.node1.SendCreateContractTransaction(compilationResult.Compilation, 0); this.mockChain.WaitAllMempoolCount(1); this.mockChain.MineBlocks(1); Assert.NotNull(this.node1.GetCode(response2.NewContractAddress)); uint160 contract2Address = this.addressGenerator.GenerateAddress(response2.TransactionId, 0); ulong transferredAmount = 123; string[] parameters = new string[] { string.Format("{0}#{1}", (int)MethodParameterDataType.Address, response2.NewContractAddress), string.Format("{0}#{1}", (int)MethodParameterDataType.ULong, transferredAmount) }; // Invoke method on contract1 that calls contract2 and check that balance is correct BuildCallContractTransactionResponse callResponse = this.node1.SendCallContractTransaction( nameof(ReceiveFundsTest.TransferFunds), response.NewContractAddress, 0, parameters); this.mockChain.WaitAllMempoolCount(1); this.mockChain.MineBlocks(1); // Stored balance in PersistentState should be only that which was sent byte[] saved = this.node1.GetStorageValue(contract2Address.ToBase58Address(this.node1.CoreNode.FullNode.Network), "ReceiveBalance"); ulong savedUlong = BitConverter.ToUInt64(saved); Assert.Equal(transferredAmount, savedUlong); }
public void ContractTransaction_MethodDoesntExist() { // Deploy contract ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/EmptyContract.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; Money senderBalanceBefore = this.node1.WalletSpendableBalance; uint256 currentHash = this.node1.GetLastBlock().GetHash(); BuildCallContractTransactionResponse response = this.node1.SendCallContractTransaction("MethodThatDoesntExist", preResponse.NewContractAddress, amount); this.node2.WaitMempoolCount(1); this.node2.WaitForBlocksToBeMined(1); NBitcoin.Block lastBlock = this.node1.GetLastBlock(); // Blocks progressed Assert.NotEqual(currentHash, lastBlock.GetHash()); // Block contains a refund transaction Assert.Equal(3, lastBlock.Transactions.Count); Transaction refundTransaction = lastBlock.Transactions[2]; Assert.Single(refundTransaction.Outputs); // No transfers persisted uint160 refundReceiver = this.senderRetriever.GetAddressFromScript(refundTransaction.Outputs[0].ScriptPubKey).Sender; Assert.Equal(this.node1.MinerAddress.Address, refundReceiver.ToBase58Address(this.mockChain.Network)); Assert.Equal(new Money((long)amount, MoneyUnit.BTC), refundTransaction.Outputs[0].Value); Money fee = lastBlock.Transactions[0].Outputs[0].Value - new Money(50, MoneyUnit.BTC); // 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); Assert.False(receipt.Success); Assert.Equal(GasPriceList.BaseCost, receipt.GasUsed); Assert.Null(receipt.NewContractAddress); Assert.Equal(this.node1.MinerAddress.Address, receipt.From); Assert.Equal(ContractInvocationErrors.MethodDoesNotExist, receipt.Error); Assert.Equal(preResponse.NewContractAddress, receipt.To); }
public void ContractTransaction_AddressDoesntExist() { // Ensure fixture is funded. this.node1.MineBlocks(1); double amount = 25; Money senderBalanceBefore = this.node1.WalletSpendableBalance; uint256 currentHash = this.node1.GetLastBlock().GetHash(); // Send call to non-existent address string nonExistentAddress = new uint160(0).ToBase58Address(this.mockChain.Network); Assert.Null(this.node1.GetCode(nonExistentAddress)); BuildCallContractTransactionResponse response = this.node1.SendCallContractTransaction("Method", nonExistentAddress, amount); this.node2.WaitMempoolCount(1); this.node2.MineBlocks(1); NBitcoin.Block lastBlock = this.node1.GetLastBlock(); // Blocks progressed Assert.NotEqual(currentHash, lastBlock.GetHash()); // Block contains a refund transaction Assert.Equal(3, lastBlock.Transactions.Count); Transaction refundTransaction = lastBlock.Transactions[2]; Assert.Single(refundTransaction.Outputs); // No transfers uint160 refundReceiver = this.senderRetriever.GetAddressFromScript(refundTransaction.Outputs[0].ScriptPubKey).Sender; Assert.Equal(this.node1.MinerAddress.Address, refundReceiver.ToBase58Address(this.mockChain.Network)); Assert.Equal(new Money((long)amount, MoneyUnit.BTC), refundTransaction.Outputs[0].Value); Money fee = lastBlock.Transactions[0].Outputs[0].Value - new Money(50, MoneyUnit.BTC); // Amount was refunded to wallet, minus fee Assert.Equal(senderBalanceBefore - this.node1.WalletSpendableBalance, fee); // 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); Assert.False(receipt.Success); Assert.Equal(GasPriceList.BaseCost, receipt.GasUsed); Assert.Null(receipt.NewContractAddress); Assert.Equal(this.node1.MinerAddress.Address, receipt.From); Assert.Equal(StateTransitionErrors.NoCode, receipt.Error); Assert.Equal(nonExistentAddress, receipt.To); }
public void InternalTransfer_BetweenContracts_FromConstructor() { // Ensure fixture is funded. this.mockChain.MineBlocks(1); decimal amount = 25; // Deploy contract ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/MultipleNestedCalls.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)); NBitcoin.Block lastBlock = this.node1.GetLastBlock(); // Storage from nested call succeeded Assert.NotNull(this.node1.GetStorageValue(response.NewContractAddress, "Caller")); // 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[0].Value); Assert.Equal((ulong)new Money((long)amount, MoneyUnit.BTC) / 2, this.node1.GetContractBalance(response.NewContractAddress)); // 1 output to other deployed contract uint160 internalContract = this.addressGenerator.GenerateAddress(response.TransactionId, 1); toBytes = condensingTransaction.Outputs[1].ScriptPubKey.ToBytes(); Assert.Equal((byte)ScOpcodeType.OP_INTERNALCONTRACTTRANSFER, toBytes[0]); toAddress = new uint160(toBytes.Skip(1).ToArray()); Assert.Equal(internalContract, toAddress); Assert.Equal(new Money((long)amount, MoneyUnit.BTC) / 2, condensingTransaction.Outputs[1].Value); Assert.Equal((ulong)new Money((long)amount, MoneyUnit.BTC) / 2, this.node1.GetContractBalance(internalContract.ToBase58Address(this.node1.CoreNode.FullNode.Network))); }
public void ContractTransaction_RecursiveContractCreate_OutOfGas() { // Ensure fixture is funded. this.mockChain.MineBlocks(1); decimal amount = 25; ulong gasLimit = SmartContractFormatLogic.GasLimitMaximum; uint256 currentHash = this.node1.GetLastBlock().GetHash(); ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/RecursiveLoopCreate.cs"); Assert.True(compilationResult.Success); BuildCreateContractTransactionResponse response = this.node1.SendCreateContractTransaction(compilationResult.Compilation, amount, gasLimit: gasLimit); this.mockChain.WaitAllMempoolCount(1); this.mockChain.MineBlocks(1); NBitcoin.Block lastBlock = this.node1.GetLastBlock(); // Blocks progressed Assert.NotEqual(currentHash, lastBlock.GetHash()); // Contract was not created Assert.Null(this.node2.GetCode(response.NewContractAddress)); // Block contains a refund transaction Assert.Equal(3, lastBlock.Transactions.Count); Transaction refundTransaction = lastBlock.Transactions[2]; uint160 refundReceiver = this.senderRetriever.GetAddressFromScript(refundTransaction.Outputs[0].ScriptPubKey).Sender; Assert.Equal(this.node1.MinerAddress.Address, refundReceiver.ToBase58Address(this.node1.CoreNode.FullNode.Network)); Assert.Equal(new Money((long)amount, MoneyUnit.BTC), refundTransaction.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.Empty(receipt.Logs); Assert.False(receipt.Success); Assert.True(receipt.GasUsed > (gasLimit - GasPriceList.BaseCost)); // The amount spent should be within 1 BaseCost of being used up. Assert.Null(receipt.NewContractAddress); Assert.Equal(this.node1.MinerAddress.Address, receipt.From); Assert.Null(receipt.To); }
public void Internal_Nested_Call_Transfer_To_Self_Balance_Correct() { // 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 contract1Address = this.addressGenerator.GenerateAddress(response.TransactionId, 0); ulong transferredAmount = 123; string[] parameters = new string[] { string.Format("{0}#{1}", (int)MethodParameterDataType.Address, response.NewContractAddress), string.Format("{0}#{1}", (int)MethodParameterDataType.ULong, transferredAmount) }; // Invoke call which sends 123 to self. Balance should remain the same. BuildCallContractTransactionResponse callResponse = this.node1.SendCallContractTransaction( nameof(ReceiveFundsTest.TransferFunds), response.NewContractAddress, 0, parameters); this.mockChain.WaitAllMempoolCount(1); this.mockChain.MineBlocks(1); // Stored balance in PersistentState should be only that which was sent byte[] saved = this.node1.GetStorageValue(contract1Address.ToBase58Address(this.node1.CoreNode.FullNode.Network), "ReceiveBalance"); ulong savedUlong = BitConverter.ToUInt64(saved); // Balance should be the same as the initial amount Assert.True((new Money(amount, MoneyUnit.BTC) == new Money(savedUlong, MoneyUnit.Satoshi))); }
public void InternalTransfer_ToWalletAddress() { // Deploy contract 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; // Send amount to contract, which will send to wallet address (address without code) uint160 walletUint160 = new uint160(1); string address = walletUint160.ToBase58Address(this.mockChain.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.node2.WaitMempoolCount(1); this.node2.WaitForBlocksToBeMined(1); // 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(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 LocalExecutionResult_Outputs_With_Address() { uint160 testUint160 = new uint160(123); Address testAddress = testUint160.ToAddress(); string expectedString = testUint160.ToBase58Address(this.network); var execResult = new LocalExecutionResult { ErrorMessage = new ContractErrorMessage("Error message"), GasConsumed = (RuntimeObserver.Gas) 69, Return = testAddress }; string jsonOutput = JsonConvert.SerializeObject(execResult, new JsonSerializerSettings { ContractResolver = this.resolver }); Assert.Contains($"\"return\":\"{expectedString}\"", jsonOutput); }
public void InternalTransfer_Nested_Create_Balance_Correct() { double amount = 25; // Deploy contract ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/BalanceTest.cs"); Assert.True(compilationResult.Success); BuildCreateContractTransactionResponse response = this.node1.SendCreateContractTransaction(compilationResult.Compilation, amount); this.node2.WaitMempoolCount(1); this.node2.WaitForBlocksToBeMined(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.mockChain.Network), "Balance"); ulong savedUlong = BitConverter.ToUInt64(saved); Assert.Equal((ulong)10, savedUlong); }
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 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_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_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_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); }