public void VM_ExecuteContract_OutOfGas() { ContractCompilationResult compilationResult = ContractCompiler.Compile( @" using System; using Stratis.SmartContracts; public class Contract : SmartContract { public Contract(ISmartContractState state) : base(state) {} } "); Assert.True(compilationResult.Success); byte[] contractExecutionCode = compilationResult.Compilation; // Set up the state with an empty gasmeter so that out of gas occurs var contractState = Mock.Of <ISmartContractState>(s => s.Block == Mock.Of <IBlock>(b => b.Number == 1 && b.Coinbase == TestAddress) && s.Message == new Message(TestAddress, TestAddress, 0) && s.PersistentState == new PersistentState( new TestPersistenceStrategy(this.state), this.context.ContractPrimitiveSerializer, TestAddress.ToUint160(this.network)) && s.Serializer == this.context.ContractPrimitiveSerializer && s.GasMeter == new GasMeter((Gas)0) && s.ContractLogger == new ContractLogHolder(this.network) && s.InternalTransactionExecutor == Mock.Of <IInternalTransactionExecutor>() && s.InternalHashHelper == new InternalHashHelper() && s.GetBalance == new Func <ulong>(() => 0)); VmExecutionResult result = this.vm.Create(this.state, contractState, contractExecutionCode, null); Assert.False(result.IsSuccess); Assert.Equal(VmExecutionErrorKind.OutOfGas, result.Error.ErrorKind); }
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 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 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 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()); assembly.Value.SetObserver(new Observer(this.gasMeter, new MemoryMeter(10000))); 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 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_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 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 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 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 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 Persisting_Nothing_Null_And_Empty_Byte_Arrays_Are_The_Same() { // Demonstrates some potentially unusual behaviour when saving contract state. // Ensure fixture is funded. this.mockChain.MineBlocks(1); // Deploy contract ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/BehaviourTest.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(); // Call CheckData() and confirm that it succeeds BuildCallContractTransactionResponse response = this.node1.SendCallContractTransaction( nameof(BehaviourTest.DataIsByte0), 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); // Invoke PersistEmptyString. It should succeed response = this.node1.SendCallContractTransaction( nameof(BehaviourTest.PersistEmptyString), preResponse.NewContractAddress, 0); this.mockChain.WaitAllMempoolCount(1); this.mockChain.MineBlocks(1); lastBlock = this.node1.GetLastBlock(); // Blocks progressed Assert.NotEqual(currentHash, lastBlock.GetHash()); receipt = this.node1.GetReceipt(response.TransactionId.ToString()); Assert.True(receipt.Success); // The storage value should be null, but the contract only sees it as a byte[0] Assert.Null(this.node1.GetStorageValue(preResponse.NewContractAddress, nameof(BehaviourTest.Data))); // Now call CheckData() to confirm that it's a byte[0] response = this.node1.SendCallContractTransaction( nameof(BehaviourTest.DataIsByte0), preResponse.NewContractAddress, 0); this.mockChain.WaitAllMempoolCount(1); this.mockChain.MineBlocks(1); lastBlock = this.node1.GetLastBlock(); // Blocks progressed Assert.NotEqual(currentHash, lastBlock.GetHash()); receipt = this.node1.GetReceipt(response.TransactionId.ToString()); Assert.True(receipt.Success); // Now call PersistNull, which should fail if the null is not returned as byte[0] response = this.node1.SendCallContractTransaction( nameof(BehaviourTest.PersistNull), preResponse.NewContractAddress, 0); this.mockChain.WaitAllMempoolCount(1); this.mockChain.MineBlocks(1); lastBlock = this.node1.GetLastBlock(); receipt = this.node1.GetReceipt(response.TransactionId.ToString()); Assert.True(receipt.Success); // The storage value should be null Assert.Null(this.node1.GetStorageValue(preResponse.NewContractAddress, nameof(BehaviourTest.Data))); // Now call CheckData() to confirm that it's a byte[0] response = this.node1.SendCallContractTransaction( nameof(BehaviourTest.DataIsByte0), preResponse.NewContractAddress, 0); this.mockChain.WaitAllMempoolCount(1); this.mockChain.MineBlocks(1); lastBlock = this.node1.GetLastBlock(); // Blocks progressed Assert.NotEqual(currentHash, lastBlock.GetHash()); receipt = this.node1.GetReceipt(response.TransactionId.ToString()); Assert.True(receipt.Success); }
public void ContractTransaction_ExceptionInCall() { // Ensure fixture is funded. this.node1.MineBlocks(1); // Deploy contract ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/ExceptionInMethod.cs"); Assert.True(compilationResult.Success); BuildCreateContractTransactionResponse preResponse = this.node1.SendCreateContractTransaction(compilationResult.Compilation, 0); this.node1.WaitMempoolCount(1); this.node1.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("Method", preResponse.NewContractAddress, amount); this.node2.WaitMempoolCount(1); this.node2.MineBlocks(1); Block lastBlock = this.node1.GetLastBlock(); // Blocks progressed Assert.NotEqual(currentHash, lastBlock.GetHash()); // State wasn't persisted Assert.Null(this.node2.GetStorageValue(preResponse.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.ToAddress(this.mockChain.Network).Value); 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.Equal(preResponse.NewContractAddress, receipt.To); }
public void Local_Internal_Call_Should_Transfer_Value() { // Ref: https://github.com/stratisproject/StratisFullNode/pull/662#issuecomment-902379004 var localExecutor = this.mockChain.Nodes[0].CoreNode.FullNode.NodeService <ILocalExecutor>(); // Ensure fixture is funded. this.mockChain.MineBlocks(1); // Deploy contract 1 ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/ValueTransferTest.cs"); Assert.True(compilationResult.Success); BuildCreateContractTransactionResponse valueTransferContractResponse = this.node1.SendCreateContractTransaction(compilationResult.Compilation, 0); this.mockChain.WaitAllMempoolCount(1); this.mockChain.MineBlocks(1); Assert.NotNull(this.node1.GetCode(valueTransferContractResponse.NewContractAddress)); Assert.Equal(0UL, this.node1.GetContractBalance(valueTransferContractResponse.NewContractAddress)); ReceiptResponse receipt = this.node1.GetReceipt(valueTransferContractResponse.TransactionId.ToString()); Assert.True(receipt.Success); // Deploy contract 2 var compilationResult2 = ContractCompiler.CompileFile("SmartContracts/ValueTransferRecipient.cs"); Assert.True(compilationResult2.Success); var recipientResponse = this.node1.SendCreateContractTransaction(compilationResult2.Compilation, 0); this.mockChain.WaitAllMempoolCount(1); this.mockChain.MineBlocks(1); Assert.NotNull(this.node1.GetCode(recipientResponse.NewContractAddress)); Assert.Equal(0UL, this.node1.GetContractBalance(recipientResponse.NewContractAddress)); ReceiptResponse receipt2 = this.node1.GetReceipt(recipientResponse.TransactionId.ToString()); Assert.True(receipt2.Success); uint256 currentHash = this.node1.GetLastBlock().GetHash(); NBitcoin.Block lastBlock = this.node1.GetLastBlock(); // Create a log in a local call. var parameters = new object[] { recipientResponse.NewContractAddress.ToAddress(this.node1.CoreNode.FullNode.Network) }; var call = new ContractTxData(1, 100, (Gas)250000, valueTransferContractResponse.NewContractAddress.ToUint160(this.node1.CoreNode.FullNode.Network), nameof(ValueTransferTest.CanForwardValueCall), parameters); var internalTransferResult = localExecutor.Execute((ulong)this.node1.CoreNode.FullNode.ChainIndexer.Height, this.mockChain.Nodes[0].MinerAddress.Address.ToUint160(this.node1.CoreNode.FullNode.Network), 10, call); Assert.False(internalTransferResult.Revert); //Assert.NotEmpty(createLogResult.Logs); //RLPCollection collection = (RLPCollection)RLP.Decode(createLogResult.Logs[0].Data); //var loggedData = Encoding.UTF8.GetString(collection[0].RLPData); //Assert.Equal(nameof(LocalCallTests.CreateLog), loggedData); //// Create a transfer in a local call //call = new ContractTxData(1, 100, (Gas)250000, preResponse.NewContractAddress.ToUint160(this.node1.CoreNode.FullNode.Network), nameof(LocalCallTests.CreateTransfer)); //var createTransferResult = localExecutor.Execute((ulong)this.node1.CoreNode.FullNode.ChainIndexer.Height, this.mockChain.Nodes[0].MinerAddress.Address.ToUint160(this.node1.CoreNode.FullNode.Network), 0, call); ////Assert.NotEmpty(createTransferResult.InternalTransfers); ////Assert.Equal(Address.Zero.ToUint160(), createTransferResult.InternalTransfers[0].To); ////Assert.Equal(1UL, createTransferResult.InternalTransfers[0].Value); }
public void SmartContract_Compiler_FailsOnImplicitInvalidAssemblyReference() { ContractCompilationResult result = ContractCompiler.CompileFile("SmartContracts/InvalidImplicitAssembly.cs"); Assert.False(result.Success); }
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_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); }
public void GetHexStringForDemo() { ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/Auction.cs"); string example = compilationResult.Compilation.ToHexString(); }
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); }
private int OnExecute(CommandLineApplication app) { if (!this.InputFiles.Any()) { app.ShowHelp(); return(1); } Console.WriteLine(); Console.WriteLine("Smart Contract Validator"); Console.WriteLine(); var determinismValidator = new SctDeterminismValidator(); var formatValidator = new SmartContractFormatValidator(); var warningValidator = new SmartContractWarningValidator(); var reportData = new List <ValidationReportData>(); foreach (string file in this.InputFiles) { if (!File.Exists(file)) { Console.WriteLine($"{file} does not exist"); continue; } string source; Console.WriteLine($"Reading {file}"); using (var sr = new StreamReader(File.OpenRead(file))) { source = sr.ReadToEnd(); } Console.WriteLine($"Read {file} OK"); Console.WriteLine(); if (string.IsNullOrWhiteSpace(source)) { Console.WriteLine($"Empty file at {file}"); Console.WriteLine(); continue; } var validationData = new ValidationReportData { FileName = file, CompilationErrors = new List <CompilationError>(), DeterminismValidationErrors = new List <ValidationResult>(), FormatValidationErrors = new List <ValidationError>(), Warnings = new List <Warning>() }; reportData.Add(validationData); Console.WriteLine($"Compiling..."); ContractCompilationResult compilationResult = ContractCompiler.Compile(source); validationData.CompilationSuccess = compilationResult.Success; if (!compilationResult.Success) { Console.WriteLine("Compilation failed!"); Console.WriteLine(); validationData.CompilationErrors .AddRange(compilationResult .Diagnostics .Select(d => new CompilationError { Message = d.ToString() })); continue; } validationData.CompilationBytes = compilationResult.Compilation; Console.WriteLine($"Compilation OK"); Console.WriteLine(); byte[] compilation = compilationResult.Compilation; Console.WriteLine("Building ModuleDefinition"); IContractModuleDefinition moduleDefinition = ContractDecompiler.GetModuleDefinition(compilation, new DotNetCoreAssemblyResolver()).Value; Console.WriteLine("ModuleDefinition built successfully"); Console.WriteLine(); Console.WriteLine($"Validating file {file}..."); Console.WriteLine(); SmartContractValidationResult formatValidationResult = formatValidator.Validate(moduleDefinition.ModuleDefinition); validationData.FormatValid = formatValidationResult.IsValid; validationData .FormatValidationErrors .AddRange(formatValidationResult .Errors .Select(e => new ValidationError { Message = e.Message })); SmartContractValidationResult determinismValidationResult = determinismValidator.Validate(moduleDefinition); validationData.DeterminismValid = determinismValidationResult.IsValid; validationData .DeterminismValidationErrors .AddRange(determinismValidationResult.Errors); SmartContractValidationResult warningResult = warningValidator.Validate(moduleDefinition.ModuleDefinition); validationData .Warnings .AddRange(warningResult .Errors .Select(e => new Warning { Message = e.Message })); } List <IReportSection> reportStructure = new List <IReportSection>(); reportStructure.Add(new HeaderSection()); reportStructure.Add(new CompilationSection()); reportStructure.Add(new FormatSection()); reportStructure.Add(new DeterminismSection()); reportStructure.Add(new WarningsSection()); if (this.ShowBytes) { reportStructure.Add(new ByteCodeSection()); } reportStructure.Add(new FooterSection()); var renderer = new StreamTextRenderer(Console.Out); foreach (ValidationReportData data in reportData) { renderer.Render(reportStructure, data); } return(1); }
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 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 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 VM_ExecuteContract_CachedAssembly_WithExistingObserver() { ContractCompilationResult compilationResult = ContractCompiler.Compile( @" using System; using Stratis.SmartContracts; public class Contract : SmartContract { public Contract(ISmartContractState state) : base(state) {} public void Test() {} } "); Assert.True(compilationResult.Success); byte[] contractExecutionCode = compilationResult.Compilation; byte[] codeHash = HashHelper.Keccak256(contractExecutionCode); byte[] rewrittenCode; // Rewrite the assembly to have an observer. using (IContractModuleDefinition moduleDefinition = this.context.ModuleDefinitionReader.Read(contractExecutionCode).Value) { var rewriter = new ObserverInstanceRewriter(); moduleDefinition.Rewrite(rewriter); rewrittenCode = moduleDefinition.ToByteCode().Value; } var contractAssembly = new ContractAssembly(Assembly.Load(rewrittenCode)); // Cache the assembly. this.context.ContractCache.Store(new uint256(codeHash), new CachedAssemblyPackage(contractAssembly)); // Set an observer on the cached rewritten assembly. var initialObserver = new Observer(new GasMeter((Gas)(this.gasMeter.GasAvailable + 1000)), new MemoryMeter(100_000)); Assert.True(contractAssembly.SetObserver(initialObserver)); var callData = new MethodCall("Test"); // Run the execution with an empty gas meter, which means it should fail if the correct observer is used. var emptyGasMeter = new GasMeter((Gas)0); var executionContext = new ExecutionContext(new Observer(emptyGasMeter, new MemoryMeter(100_000))); VmExecutionResult result = this.vm.ExecuteMethod(this.contractState, executionContext, callData, contractExecutionCode, "Contract"); CachedAssemblyPackage cachedAssembly = this.context.ContractCache.Retrieve(new uint256(codeHash)); // Check that it's still cached. Assert.NotNull(cachedAssembly); // Check that the observer has been reset to the original. Assert.Same(initialObserver, cachedAssembly.Assembly.GetObserver()); Assert.False(result.IsSuccess); Assert.Equal(VmExecutionErrorKind.OutOfGas, result.Error.ErrorKind); }
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 Validate_Determinism_Exceptions() { // Note that NotFiniteNumberException is commented out - it causes an issue as it deals with floats string adjustedSource = TestString.Replace(ReplaceCodeString, @"var test = new AccessViolationException(); var test2 = new AggregateException(); var test4 = new ApplicationException(); var test5 = new ArgumentException(); var test6 = new ArgumentNullException(); var test7 = new ArgumentOutOfRangeException(); var test8 = new ArithmeticException(); var test9 = new ArrayTypeMismatchException(); var test10 = new BadImageFormatException(); var test13 = new DataMisalignedException(); var test14 = new DivideByZeroException(); var test15 = new DllNotFoundException(); var test16 = new DuplicateWaitObjectException(); var test17 = new EntryPointNotFoundException(); var test19 = new FieldAccessException(); var test20 = new FormatException(); var test21 = new IndexOutOfRangeException(); var test22 = new InsufficientExecutionStackException(); var test23 = new InsufficientMemoryException(); var test24 = new InvalidCastException(); var test25 = new InvalidOperationException(); var test26 = new InvalidProgramException(); var test27 = new InvalidTimeZoneException(); var test28 = new MemberAccessException(); var test29 = new MethodAccessException(); var test30 = new MissingFieldException(); var test31 = new MissingMemberException(); var test32 = new MissingMethodException(); var test33 = new MulticastNotSupportedException(); var test35 = new NotImplementedException(); var test36 = new NotSupportedException(); var test37 = new NullReferenceException(); var test38 = new ObjectDisposedException(""test""); var test39 = new OperationCanceledException(); var test40 = new OutOfMemoryException(); var test41 = new OverflowException(); var test42 = new PlatformNotSupportedException(); var test43 = new RankException(); var test44 = new StackOverflowException(); var test45 = new SystemException(); var test46 = new TimeoutException(); var test47 = new TimeZoneNotFoundException(); var test48 = new TypeAccessException(); var test49 = new TypeInitializationException(""test"", new Exception()); var test50 = new TypeLoadException(); var test51 = new TypeUnloadedException(); var test52 = new UnauthorizedAccessException();" ).Replace(ReplaceReferencesString, ""); ContractCompilationResult compilationResult = ContractCompiler.Compile(adjustedSource); Assert.True(compilationResult.Success); byte[] assemblyBytes = compilationResult.Compilation; IContractModuleDefinition moduleDefinition = ContractDecompiler.GetModuleDefinition(assemblyBytes).Value; SmartContractValidationResult result = this.validator.Validate(moduleDefinition.ModuleDefinition); Assert.False(result.IsValid); }
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 Validate_Determinism_AllowedMethodParams() { string adjustedSource = @"using System; using Stratis.SmartContracts; public class Test : SmartContract { public Test(ISmartContractState state) : base(state) {} public void Bool(bool param) { } public void Byte(byte param) { } public void ByteArray(byte[] param) { } public void Char(char param) { } public void SByte(sbyte param) { } public void String(string param) { } public void Int32(int param) { } public void UInt32(uint param) { } public void UInt64(ulong param) { } public void Int64(long param) { } public void Address1(Address param) { } }"; ContractCompilationResult compilationResult = ContractCompiler.Compile(adjustedSource); Assert.True(compilationResult.Success); byte[] assemblyBytes = compilationResult.Compilation; IContractModuleDefinition moduleDefinition = ContractDecompiler.GetModuleDefinition(assemblyBytes).Value; SmartContractValidationResult result = this.validator.Validate(moduleDefinition.ModuleDefinition); Assert.True(result.IsValid); }
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 ContractAssemblyTests() { this.compilation = ContractCompiler.CompileFile(this.Contract); this.loader = new ContractAssemblyLoader(); }