public void SendAndReceiveSmartContractTransactionsUsingController() { using (NodeBuilder builder = NodeBuilder.Create(this)) { CoreNode scSender = builder.CreateSmartContractPowNode(); CoreNode scReceiver = builder.CreateSmartContractPowNode(); builder.StartAll(); scSender.NotInIBD(); scReceiver.NotInIBD(); scSender.FullNode.Network.Consensus.CoinbaseMaturity = 1L; scReceiver.FullNode.Network.Consensus.CoinbaseMaturity = 1L; int maturity = (int)scReceiver.FullNode.Network.Consensus.CoinbaseMaturity; scSender.FullNode.WalletManager().CreateWallet(Password, WalletName, Passphrase); scReceiver.FullNode.WalletManager().CreateWallet(Password, WalletName, Passphrase); HdAddress addr = scSender.FullNode.WalletManager().GetUnusedAddress(new WalletAccountReference(WalletName, AccountName)); Features.Wallet.Wallet wallet = scSender.FullNode.WalletManager().GetWalletByName(WalletName); Key key = wallet.GetExtendedPrivateKeyForAddress(Password, addr).PrivateKey; scSender.SetDummyMinerSecret(new BitcoinSecret(key, scSender.FullNode.Network)); scReceiver.SetDummyMinerSecret(new BitcoinSecret(key, scReceiver.FullNode.Network)); scSender.GenerateStratisWithMiner(2); TestHelper.WaitLoop(() => TestHelper.IsNodeSynced(scSender)); var total = scSender.FullNode.WalletManager().GetSpendableTransactionsInWallet(WalletName).Sum(s => s.Transaction.Amount); Assert.Equal(Money.COIN * (maturity + 1) * 50, total); SmartContractsController senderSmartContractsController = scSender.FullNode.NodeService <SmartContractsController>(); SmartContractWalletController senderWalletController = scSender.FullNode.NodeService <SmartContractWalletController>(); SmartContractCompilationResult compilationResult = SmartContractCompiler.CompileFile("SmartContracts/StorageDemo.cs"); Assert.True(compilationResult.Success); var buildRequest = new BuildCreateContractTransactionRequest { AccountName = AccountName, GasLimit = "10000", GasPrice = "1", ContractCode = compilationResult.Compilation.ToHexString(), FeeAmount = "0.001", Password = Password, WalletName = WalletName, Sender = addr.Address }; JsonResult result = (JsonResult)senderSmartContractsController.BuildCreateSmartContractTransaction(buildRequest); var response = (BuildCreateContractTransactionResponse)result.Value; scSender.CreateRPCClient().AddNode(scReceiver.Endpoint, true); SmartContractSharedSteps.SendTransactionAndMine(scSender, scReceiver, senderWalletController, response.Hex); // Check wallet history is updating correctly. result = (JsonResult)senderWalletController.GetHistory(new WalletHistoryRequest { AccountName = AccountName, WalletName = WalletName }); var walletHistoryModel = (WalletHistoryModel)result.Value; Assert.Single(walletHistoryModel.AccountsHistoryModel.First().TransactionsHistory.Where(x => x.Type == TransactionItemType.Send)); // 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 = SmartContractDataType.String })).Value; Assert.Equal("Hello, smart contract world!", storageRequestResult); string ownerRequestResult = (string)((JsonResult)senderSmartContractsController.GetStorage(new GetStorageRequest { ContractAddress = response.NewContractAddress.ToString(), StorageKey = "Owner", DataType = SmartContractDataType.Address })).Value; Assert.NotEmpty(ownerRequestResult); string counterRequestResult = (string)((JsonResult)senderSmartContractsController.GetStorage(new GetStorageRequest { ContractAddress = response.NewContractAddress.ToString(), StorageKey = "Counter", DataType = SmartContractDataType.Int })).Value; Assert.Equal("12345", counterRequestResult); var callRequest = new BuildCallContractTransactionRequest { AccountName = AccountName, GasLimit = "10000", GasPrice = "1", 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.SendTransactionAndMine(scSender, scReceiver, senderWalletController, callResponse.Hex); counterRequestResult = (string)((JsonResult)senderSmartContractsController.GetStorage(new GetStorageRequest { ContractAddress = response.NewContractAddress.ToString(), StorageKey = "Counter", DataType = SmartContractDataType.Int })).Value; Assert.Equal("12346", counterRequestResult); // Check wallet history again result = (JsonResult)senderWalletController.GetHistory(new WalletHistoryRequest { AccountName = AccountName, WalletName = WalletName }); walletHistoryModel = (WalletHistoryModel)result.Value; Assert.Equal(2, walletHistoryModel.AccountsHistoryModel.First().TransactionsHistory.Where(x => x.Type == TransactionItemType.Send).Count()); } }
public void GetHexStringForDemo() { SmartContractCompilationResult compilationResult = SmartContractCompiler.CompileFile("SmartContracts/Auction.cs"); string example = compilationResult.Compilation.ToHexString(); }
public void SendAndReceiveSmartContractTransactions() { using (NodeBuilder builder = NodeBuilder.Create(this)) { CoreNode scSender = builder.CreateSmartContractPowNode(); CoreNode scReceiver = builder.CreateSmartContractPowNode(); builder.StartAll(); scSender.NotInIBD(); scReceiver.NotInIBD(); scSender.FullNode.WalletManager().CreateWallet(Password, WalletName, Passphrase); scReceiver.FullNode.WalletManager().CreateWallet(Password, WalletName, Passphrase); HdAddress addr = scSender.FullNode.WalletManager().GetUnusedAddress(new WalletAccountReference(WalletName, AccountName)); Features.Wallet.Wallet wallet = scSender.FullNode.WalletManager().GetWalletByName(WalletName); Key key = wallet.GetExtendedPrivateKeyForAddress(Password, addr).PrivateKey; scSender.SetDummyMinerSecret(new BitcoinSecret(key, scSender.FullNode.Network)); var maturity = (int)scSender.FullNode.Network.Consensus.CoinbaseMaturity; scSender.GenerateStratisWithMiner(maturity + 5); // 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)2000; SmartContractCompilationResult compilationResult = SmartContractCompiler.CompileFile("SmartContracts/TransferTest.cs"); Assert.True(compilationResult.Success); var contractCarrier = SmartContractCarrier.CreateContract(vmVersion, compilationResult.Compilation, gasPrice, gasLimit); var contractCreateScript = new Script(contractCarrier.Serialize()); var txBuildContext = new TransactionBuildContext(scSender.FullNode.Network) { AccountReference = new WalletAccountReference(WalletName, AccountName), MinConfirmations = maturity, 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. 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 both nodes have the contract. ContractStateRepositoryRoot senderState = scSender.FullNode.NodeService <ContractStateRepositoryRoot>(); ContractStateRepositoryRoot receiverState = scReceiver.FullNode.NodeService <ContractStateRepositoryRoot>(); 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 = SmartContractCompiler.CompileFile("SmartContracts/TransferTest.cs"); Assert.True(compilationResult.Success); contractCarrier = SmartContractCarrier.CreateContract(vmVersion, compilationResult.Compilation, gasPrice, gasLimit); contractCreateScript = new Script(contractCarrier.Serialize()); txBuildContext = new TransactionBuildContext(scSender.FullNode.Network) { AccountReference = new WalletAccountReference(WalletName, AccountName), MinConfirmations = maturity, 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); 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)); // Ensure that both nodes have the contract. senderState = scSender.FullNode.NodeService <ContractStateRepositoryRoot>(); receiverState = scReceiver.FullNode.NodeService <ContractStateRepositoryRoot>(); 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. contractCarrier = SmartContractCarrier.CallContract(1, tokenContractAddress, "Test", gasPrice, gasLimit); Script contractCallScript = new Script(contractCarrier.Serialize()); txBuildContext = new TransactionBuildContext(scSender.FullNode.Network) { AccountReference = new WalletAccountReference(WalletName, AccountName), MinConfirmations = maturity, 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. 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 ContractAssemblyTests() { this.compilation = SmartContractCompiler.CompileFile(Contract); this.loader = new ContractAssemblyLoader(); }
public void SendAndReceiveSmartContractTransactionsUsingController() { using (NodeBuilder builder = NodeBuilder.Create(this)) { CoreNode scSender = builder.CreateSmartContractPowNode(); CoreNode scReceiver = builder.CreateSmartContractPowNode(); builder.StartAll(); scSender.NotInIBD(); scReceiver.NotInIBD(); int maturity = (int)scReceiver.FullNode.Network.Consensus.CoinbaseMaturity; scSender.FullNode.WalletManager().CreateWallet(Password, WalletName, Passphrase); scReceiver.FullNode.WalletManager().CreateWallet(Password, WalletName, Passphrase); HdAddress addr = TestHelper.MineBlocks(scSender, WalletName, Password, AccountName, maturity + 5).AddressUsed; TestHelper.WaitLoop(() => TestHelper.IsNodeSynced(scSender)); 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>(); SmartContractCompilationResult compilationResult = SmartContractCompiler.CompileFile("SmartContracts/StorageDemo.cs"); Assert.True(compilationResult.Success); var buildRequest = new BuildCreateContractTransactionRequest { AccountName = AccountName, GasLimit = "10000", GasPrice = "1", ContractCode = compilationResult.Compilation.ToHexString(), FeeAmount = "0.001", Password = Password, WalletName = WalletName, Sender = addr.Address }; JsonResult result = (JsonResult)senderSmartContractsController.BuildCreateSmartContractTransaction(buildRequest); var response = (BuildCreateContractTransactionResponse)result.Value; scSender.CreateRPCClient().AddNode(scReceiver.Endpoint, true); SmartContractSharedSteps.SendTransaction(scSender, scReceiver, senderWalletController, response.Hex); TestHelper.MineBlocks(scReceiver, WalletName, Password, AccountName, 2); TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(scReceiver, scSender)); // Check wallet history is updating correctly. result = (JsonResult)senderWalletController.GetHistory(new WalletHistoryRequest { AccountName = AccountName, WalletName = WalletName }); var walletHistoryModel = (WalletHistoryModel)result.Value; Assert.Single(walletHistoryModel.AccountsHistoryModel.First().TransactionsHistory.Where(x => x.Type == TransactionItemType.Send)); // 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 = SmartContractDataType.String })).Value; Assert.Equal("Hello, smart contract world!", storageRequestResult); string ownerRequestResult = (string)((JsonResult)senderSmartContractsController.GetStorage(new GetStorageRequest { ContractAddress = response.NewContractAddress.ToString(), StorageKey = "Owner", DataType = SmartContractDataType.Address })).Value; Assert.NotEmpty(ownerRequestResult); string counterRequestResult = (string)((JsonResult)senderSmartContractsController.GetStorage(new GetStorageRequest { ContractAddress = response.NewContractAddress.ToString(), StorageKey = "Counter", DataType = SmartContractDataType.Int })).Value; Assert.Equal("12345", counterRequestResult); var callRequest = new BuildCallContractTransactionRequest { AccountName = AccountName, GasLimit = "10000", GasPrice = "1", 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, WalletName, Password, AccountName, 2); TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(scReceiver, scSender)); counterRequestResult = (string)((JsonResult)senderSmartContractsController.GetStorage(new GetStorageRequest { ContractAddress = response.NewContractAddress.ToString(), StorageKey = "Counter", DataType = SmartContractDataType.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); // Check wallet history again result = (JsonResult)senderWalletController.GetHistory(new WalletHistoryRequest { AccountName = AccountName, WalletName = WalletName }); walletHistoryModel = (WalletHistoryModel)result.Value; Assert.Equal(2, walletHistoryModel.AccountsHistoryModel.First().TransactionsHistory.Where(x => x.Type == TransactionItemType.Send).Count()); // 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 = "10000", GasPrice = "1", 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, WalletName, Password, AccountName, 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 = SmartContractDataType.Int })).Value; Assert.Equal("12345", counterRequestResult); } }
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..."); SmartContractCompilationResult compilationResult = SmartContractCompiler.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 = SmartContractDecompiler.GetModuleDefinition(compilation, new DotNetCoreAssemblyResolver()); 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 AuctionTest() { using (NodeBuilder builder = NodeBuilder.Create(this)) { CoreNode scSender = builder.CreateSmartContractNode(); CoreNode scReceiver = builder.CreateSmartContractNode(); builder.StartAll(); scSender.NotInIBD(); scReceiver.NotInIBD(); scSender.FullNode.WalletManager().CreateWallet(Password, WalletName); scReceiver.FullNode.WalletManager().CreateWallet(Password, WalletName); HdAddress addr = scSender.FullNode.WalletManager().GetUnusedAddress(new WalletAccountReference(WalletName, AccountName)); Features.Wallet.Wallet wallet = scSender.FullNode.WalletManager().GetWalletByName(WalletName); Key key = wallet.GetExtendedPrivateKeyForAddress(Password, addr).PrivateKey; scSender.SetDummyMinerSecret(new BitcoinSecret(key, scSender.FullNode.Network)); scReceiver.SetDummyMinerSecret(new BitcoinSecret(key, scReceiver.FullNode.Network)); var maturity = (int)scSender.FullNode.Network.Consensus.CoinbaseMaturity; scSender.GenerateStratisWithMiner(maturity + 5); TestHelper.WaitLoop(() => TestHelper.IsNodeSynced(scSender)); var total = scSender.FullNode.WalletManager().GetSpendableTransactionsInWallet(WalletName).Sum(s => s.Transaction.Amount); Assert.Equal(Money.COIN * (maturity + 5) * 50, total); SmartContractsController senderSmartContractsController = scSender.FullNode.NodeService <SmartContractsController>(); WalletController senderWalletController = scSender.FullNode.NodeService <WalletController>(); SmartContractCompilationResult compilationResult = SmartContractCompiler.CompileFile("SmartContracts/Auction.cs"); Assert.True(compilationResult.Success); var buildRequest = new BuildCreateContractTransactionRequest { AccountName = AccountName, GasLimit = "10000", GasPrice = "1", ContractCode = compilationResult.Compilation.ToHexString(), FeeAmount = "0.001", Password = Password, WalletName = WalletName, Sender = addr.Address, Parameters = new string[] { "10#20" } }; JsonResult result = (JsonResult)senderSmartContractsController.BuildCreateSmartContractTransaction(buildRequest); var response = (BuildCreateContractTransactionResponse)result.Value; scSender.CreateRPCClient().AddNode(scReceiver.Endpoint, true); SmartContractSharedSteps.SendTransactionAndMine(scSender, scReceiver, senderWalletController, response.Hex); // Contract deployed. ContractStateRepositoryRoot senderState = scSender.FullNode.NodeService <ContractStateRepositoryRoot>(); string contractAddress = response.NewContractAddress.ToString(); uint160 contractAddressUint160 = new Address(contractAddress).ToUint160(scSender.FullNode.Network); Assert.NotNull(senderState.GetCode(contractAddressUint160)); var callRequest = new BuildCallContractTransactionRequest { AccountName = AccountName, GasLimit = "10000", GasPrice = "1", Amount = "2", MethodName = "Bid", ContractAddress = response.NewContractAddress, FeeAmount = "0.001", Password = Password, WalletName = WalletName, Sender = addr.Address }; result = (JsonResult)senderSmartContractsController.BuildCallSmartContractTransaction(callRequest); var callResponse = (BuildCallContractTransactionResponse)result.Value; SmartContractSharedSteps.SendTransactionAndMine(scSender, scReceiver, senderWalletController, callResponse.Hex); // Here, test that Sender and HighestBidder are the same. var ownerBytes = senderState.GetStorageValue(contractAddressUint160, Encoding.UTF8.GetBytes("Owner")); var highestBidderBytes = senderState.GetStorageValue(contractAddressUint160, Encoding.UTF8.GetBytes("HighestBidder")); Assert.Equal(new uint160(ownerBytes), new uint160(highestBidderBytes)); var hasEndedBytes = senderState.GetStorageValue(contractAddressUint160, Encoding.UTF8.GetBytes("HasEnded")); var endBlockBytes = senderState.GetStorageValue(contractAddressUint160, Encoding.UTF8.GetBytes("EndBlock")); bool hasEnded = BitConverter.ToBoolean(hasEndedBytes, 0); ulong endBlock = BitConverter.ToUInt64(endBlockBytes, 0); // Wait 20 blocks to end auction scReceiver.GenerateStratisWithMiner(20); TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(scReceiver, scSender)); var endAuctionRequest = new BuildCallContractTransactionRequest { AccountName = AccountName, GasLimit = "10000", GasPrice = "1", Amount = "0", MethodName = "AuctionEnd", ContractAddress = response.NewContractAddress, FeeAmount = "0.001", Password = Password, WalletName = WalletName, Sender = addr.Address }; var endAuctionResult = (JsonResult)senderSmartContractsController.BuildCallSmartContractTransaction(endAuctionRequest); var endAuctionResponse = (BuildCallContractTransactionResponse)endAuctionResult.Value; SmartContractSharedSteps.SendTransactionAndMine(scSender, scReceiver, senderWalletController, endAuctionResponse.Hex); // Check that transaction did in fact go through with condensing tx as well var blockStoreCache = scSender.FullNode.NodeService <IBlockStoreCache>(); var secondLastBlock = blockStoreCache.GetBlockAsync(scSender.FullNode.Chain.Tip.Previous.HashBlock).Result; Assert.Equal(3, secondLastBlock.Transactions.Count); } }
public void SmartContract_Compiler_FailsOnImplicitInvalidAssemblyReference() { SmartContractCompilationResult result = SmartContractCompiler.CompileFile("SmartContracts/InvalidImplicitAssembly.cs"); Assert.False(result.Success); }
public void Execute_InterContractCall_InfiniteLoop_AllGasConsumed() { // Create contract 1 //Get the contract execution code------------------------ SmartContractCompilationResult compilationResult = SmartContractCompiler.CompileFile("SmartContracts/InfiniteLoop.cs"); Assert.True(compilationResult.Success); byte[] contractExecutionCode = compilationResult.Compilation; //------------------------------------------------------- // Add contract creation code to transaction------------- var carrier = SmartContractCarrier.CreateContract(1, contractExecutionCode, 1, (Gas)3500); var transaction = new Transaction(); TxOut txOut = transaction.AddOutput(0, new Script(carrier.Serialize())); txOut.Value = 100; //------------------------------------------------------- //Deserialize the contract from the transaction---------- //and get the module definition ISmartContractTransactionContext transactionContext = new SmartContractTransactionContext(BlockHeight, CoinbaseAddress, MempoolFee, SenderAddress, transaction); var executor = new Executor(this.loggerFactory, this.serializer, this.state, this.refundProcessor, this.transferProcessor, this.vm); ISmartContractExecutionResult result = executor.Execute(transactionContext); uint160 address1 = result.NewContractAddress; //------------------------------------------------------- // Create contract 2 //Get the contract execution code------------------------ compilationResult = SmartContractCompiler.CompileFile("SmartContracts/CallInfiniteLoopContract.cs"); Assert.True(compilationResult.Success); contractExecutionCode = compilationResult.Compilation; //------------------------------------------------------- //Call smart contract and add to transaction------------- carrier = SmartContractCarrier.CreateContract(1, contractExecutionCode, 1, (Gas)3500); transaction = new Transaction(); txOut = transaction.AddOutput(0, new Script(carrier.Serialize())); txOut.Value = 100; //------------------------------------------------------- //Deserialize the contract from the transaction---------- //and get the module definition //------------------------------------------------------- transactionContext = new SmartContractTransactionContext(BlockHeight, CoinbaseAddress, MempoolFee, SenderAddress, transaction); result = executor.Execute(transactionContext); uint160 address2 = result.NewContractAddress; // Invoke infinite loop var gasLimit = (Gas)1000000; string[] parameters = { string.Format("{0}#{1}", (int)SmartContractCarrierDataType.String, address1.ToAddress(this.network).Value), }; carrier = SmartContractCarrier.CallContract(1, address2, "CallInfiniteLoop", 1, gasLimit, parameters); transaction = new Transaction(); txOut = transaction.AddOutput(0, new Script(carrier.Serialize())); txOut.Value = 100; transactionContext = new SmartContractTransactionContext(BlockHeight, CoinbaseAddress, MempoolFee, SenderAddress, transaction); var callExecutor = new Executor(this.loggerFactory, this.serializer, this.state, this.refundProcessor, this.transferProcessor, this.vm); // Because our contract contains an infinite loop, we want to kill our test after // some amount of time without achieving a result. 3 seconds is an arbitrarily high enough timeout // for the method body to have finished execution while minimising the amount of time we spend // running tests // If you're running with the debugger on this will obviously be a source of failures result = RunWithTimeout(3, () => callExecutor.Execute(transactionContext)); Assert.IsType <OutOfGasException>(result.Exception); Assert.Equal(gasLimit, result.GasConsumed); }
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) { } }"; SmartContractCompilationResult compilationResult = SmartContractCompiler.Compile(adjustedSource); Assert.True(compilationResult.Success); byte[] assemblyBytes = compilationResult.Compilation; SmartContractDecompilation decomp = SmartContractDecompiler.GetModuleDefinition(assemblyBytes); SmartContractValidationResult result = this.validator.Validate(decomp); Assert.True(result.IsValid); }
public void Validate_Determinism_SimpleContract() { var adjustedSource = @" using System; using Stratis.SmartContracts; public class Token : SmartContract { public Token(ISmartContractState state): base(state) { Owner = Message.Sender; Balances = PersistentState.GetUInt64Mapping(""Balances""); } public Address Owner { get { return PersistentState.GetAddress(""Owner""); } private set { PersistentState.SetAddress(""Owner"", value); } } public ISmartContractMapping<ulong> Balances { get; } public bool Mint(Address receiver, ulong amount) { if (Message.Sender != Owner) throw new Exception(""Sender of this message is not the owner. "" + Owner.ToString() +"" vs "" + Message.Sender.ToString()); amount = amount + Block.Number; Balances[receiver.ToString()] += amount; return true; } public bool Send(Address receiver, ulong amount) { if (Balances.Get(Message.Sender.ToString()) < amount) throw new Exception(""Sender doesn't have high enough balance""); Balances[receiver.ToString()] += amount; Balances[Message.Sender.ToString()] -= amount; return true; } public void GasTest() { ulong test = 1; while (true) { test++; test--; } } } "; SmartContractCompilationResult compilationResult = SmartContractCompiler.Compile(adjustedSource); Assert.True(compilationResult.Success); byte[] assemblyBytes = compilationResult.Compilation; SmartContractDecompilation decomp = SmartContractDecompiler.GetModuleDefinition(assemblyBytes); SmartContractValidationResult result = this.validator.Validate(decomp); Assert.True(result.IsValid); }
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, ""); SmartContractCompilationResult compilationResult = SmartContractCompiler.Compile(adjustedSource); Assert.True(compilationResult.Success); byte[] assemblyBytes = compilationResult.Compilation; SmartContractDecompilation decomp = SmartContractDecompiler.GetModuleDefinition(assemblyBytes); SmartContractValidationResult result = this.validator.Validate(decomp); Assert.True(result.IsValid); }
public void VM_ExecuteContract_WithoutParameters() { //Get the contract execution code------------------------ SmartContractCompilationResult compilationResult = SmartContractCompiler.CompileFile("SmartContracts/StorageTest.cs"); Assert.True(compilationResult.Success); byte[] contractExecutionCode = compilationResult.Compilation; //------------------------------------------------------- //Call smart contract and add to transaction------------- var carrier = SmartContractCarrier.CallContract(1, new uint160(1), "StoreData", 1, (Gas)500000); var transactionCall = new Transaction(); transactionCall.AddInput(new TxIn()); TxOut callTxOut = transactionCall.AddOutput(0, new Script(carrier.Serialize())); //------------------------------------------------------- //Deserialize the contract from the transaction---------- var deserializedCall = SmartContractCarrier.Deserialize(transactionCall); //------------------------------------------------------- var repository = new ContractStateRepositoryRoot(new NoDeleteSource <byte[], byte[]>(new MemoryDictionarySource())); IContractStateRepository stateRepository = repository.StartTracking(); var gasMeter = new GasMeter(deserializedCall.CallData.GasLimit); var persistenceStrategy = new MeteredPersistenceStrategy(repository, gasMeter, this.keyEncodingStrategy); var persistentState = new PersistentState(persistenceStrategy, deserializedCall.CallData.ContractAddress, this.network); var internalTxExecutorFactory = new InternalTransactionExecutorFactory(this.keyEncodingStrategy, this.loggerFactory, this.network); var vm = new ReflectionVirtualMachine(internalTxExecutorFactory, this.loggerFactory); var sender = deserializedCall.Sender?.ToString() ?? TestAddress.ToString(); var context = new SmartContractExecutionContext( new Block(1, new Address("2")), new Message( new Address(deserializedCall.CallData.ContractAddress.ToString()), new Address(sender), deserializedCall.Value, deserializedCall.CallData.GasLimit ), TestAddress.ToUint160(this.network), deserializedCall.CallData.GasPrice ); var result = vm.ExecuteMethod( contractExecutionCode, "StoreData", context, gasMeter, persistentState, repository); stateRepository.Commit(); Assert.Equal(Encoding.UTF8.GetBytes("TestValue"), stateRepository.GetStorageValue(deserializedCall.CallData.ContractAddress, Encoding.UTF8.GetBytes("TestKey"))); Assert.Equal(Encoding.UTF8.GetBytes("TestValue"), repository.GetStorageValue(deserializedCall.CallData.ContractAddress, Encoding.UTF8.GetBytes("TestKey"))); }
public void VM_CreateContract_WithParameters() { //Get the contract execution code------------------------ SmartContractCompilationResult compilationResult = SmartContractCompiler.CompileFile("SmartContracts/Auction.cs"); Assert.True(compilationResult.Success); byte[] contractExecutionCode = compilationResult.Compilation; //------------------------------------------------------- // //Call smart contract and add to transaction------------- string[] methodParameters = new string[] { string.Format("{0}#{1}", (int)SmartContractCarrierDataType.ULong, 5), }; var carrier = SmartContractCarrier.CreateContract(1, contractExecutionCode, 1, (Gas)500000, methodParameters); var transactionCall = new Transaction(); transactionCall.AddInput(new TxIn()); TxOut callTxOut = transactionCall.AddOutput(0, new Script(carrier.Serialize())); //------------------------------------------------------- //Deserialize the contract from the transaction---------- var deserializedCall = SmartContractCarrier.Deserialize(transactionCall); //------------------------------------------------------- var repository = new ContractStateRepositoryRoot(new NoDeleteSource <byte[], byte[]>(new MemoryDictionarySource())); IContractStateRepository track = repository.StartTracking(); var gasMeter = new GasMeter(deserializedCall.CallData.GasLimit); var persistenceStrategy = new MeteredPersistenceStrategy(repository, gasMeter, new BasicKeyEncodingStrategy()); var persistentState = new PersistentState(persistenceStrategy, TestAddress.ToUint160(this.network), this.network); var internalTxExecutorFactory = new InternalTransactionExecutorFactory(this.keyEncodingStrategy, this.loggerFactory, this.network); var vm = new ReflectionVirtualMachine(internalTxExecutorFactory, this.loggerFactory); var context = new SmartContractExecutionContext( new Block(1, TestAddress), new Message( TestAddress, TestAddress, deserializedCall.Value, deserializedCall.CallData.GasLimit ), TestAddress.ToUint160(this.network), deserializedCall.CallData.GasPrice, deserializedCall.MethodParameters ); var result = vm.Create( contractExecutionCode, context, gasMeter, persistentState, repository); track.Commit(); Assert.Equal(6, BitConverter.ToInt16(track.GetStorageValue(context.Message.ContractAddress.ToUint160(this.network), Encoding.UTF8.GetBytes("EndBlock")), 0)); Assert.Equal(TestAddress.ToUint160(this.network).ToBytes(), track.GetStorageValue(context.Message.ContractAddress.ToUint160(this.network), Encoding.UTF8.GetBytes("Owner"))); }
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; SmartContractCompilationResult compilationResult = SmartContractCompiler.CompileFile("SmartContracts/TransferTestPos.cs"); Assert.True(compilationResult.Success); var contractCarrier = SmartContractCarrier.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 IContractStateRoot senderState = scSender.FullNode.NodeService <IContractStateRoot>(); IContractStateRoot receiverState = scReceiver.FullNode.NodeService <IContractStateRoot>(); 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 = SmartContractCompiler.CompileFile("SmartContracts/TransferTestPos.cs"); Assert.True(compilationResult.Success); contractCarrier = SmartContractCarrier.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 = SmartContractCarrier.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 Validate_Determinism_SimpleContract() { var adjustedSource = @" using System; using Stratis.SmartContracts; public class Token : SmartContract { public Token(ISmartContractState state): base(state) { Owner = Message.Sender; } public Address Owner { get { return PersistentState.GetAddress(""Owner""); } private set { PersistentState.SetAddress(""Owner"", value); } } public ISmartContractMapping<ulong> Balances { get => PersistentState.GetUInt64Mapping(""Balances""); } public void Hash() { var hash = this.Keccak256(new byte[] {1, 2, 3}); } public bool Mint(Address receiver, ulong amount) { Assert(Message.Sender == Owner); amount = amount + Block.Number; Balances[receiver] += amount; return true; } public bool Send(Address receiver, ulong amount) { Assert(Balances.Get(Message.Sender) < amount); Balances[receiver] += amount; Balances[Message.Sender] -= amount; return true; } public void GasTest() { ulong test = 1; while (true) { test++; test--; } } } "; SmartContractCompilationResult compilationResult = SmartContractCompiler.Compile(adjustedSource); Assert.True(compilationResult.Success); byte[] assemblyBytes = compilationResult.Compilation; IContractModuleDefinition moduleDefinition = SmartContractDecompiler.GetModuleDefinition(assemblyBytes); SmartContractValidationResult result = this.validator.Validate(moduleDefinition.ModuleDefinition); Assert.True(result.IsValid); }