public IActionResult BuildAndSendCallSmartContractTransaction([FromBody] BuildCallContractTransactionRequest request) { if (!this.ModelState.IsValid) { return(ModelStateErrors.BuildErrorResponse(this.ModelState)); } BuildCallContractTransactionResponse response = BuildCallTx(request); if (!response.Success) { return(Json(response)); } Transaction transaction = this.network.CreateTransaction(response.Hex); this.walletManager.ProcessTransaction(transaction, null, null, false); this.broadcasterManager.BroadcastTransactionAsync(transaction).GetAwaiter().GetResult(); return(Json(response)); }
public void CallRequest_AddressValidation() { var request = new BuildCallContractTransactionRequest { AccountName = "account 0", Amount = "2", ContractAddress = "Test", MethodName = "Test", FeeAmount = "0.02", GasLimit = SmartContractFormatLogic.GasLimitCallMinimum, GasPrice = SmartContractFormatLogic.GasPriceMaximum, Parameters = new string[0], Password = "******", WalletName = "Jordan", Sender = "Test" }; IList <ValidationResult> results = Validate(request); Assert.Equal(2, results.Count); Assert.Equal("Invalid address", results[0].ErrorMessage); // Note that the IsBitcoinAddress doesn't currently bind to the member. Assert.Equal("Invalid address", results[1].ErrorMessage); }
public void CallRequest_RangeValidation() { var request = new BuildCallContractTransactionRequest { AccountName = "account 0", Amount = "2", ContractAddress = "moRRQqumoxYxFysoNuoJg5E1S99WvrNZRX", MethodName = "MethodName", FeeAmount = "0.02", GasLimit = SmartContractFormatLogic.GasLimitCallMinimum - 1, // Too low GasPrice = SmartContractFormatLogic.GasPriceMaximum + 1, // Too high Parameters = new string[0], Password = "******", WalletName = "Jordan", Sender = "moRRQqumoxYxFysoNuoJg5E1S99WvrNZRX" }; IList <ValidationResult> results = Validate(request); Assert.Equal(2, results.Count); Assert.Contains(results, x => x.MemberNames.First() == nameof(BuildCallContractTransactionRequest.GasLimit)); Assert.Contains(results, x => x.MemberNames.First() == nameof(BuildCallContractTransactionRequest.GasPrice)); request.GasLimit = SmartContractFormatLogic.GasLimitMaximum + 1; request.GasPrice = SmartContractMempoolValidator.MinGasPrice - 1; results = Validate(request); Assert.Equal(2, results.Count); Assert.Contains(results, x => x.MemberNames.First() == nameof(BuildCallContractTransactionRequest.GasLimit)); Assert.Contains(results, x => x.MemberNames.First() == nameof(BuildCallContractTransactionRequest.GasPrice)); request.GasLimit = SmartContractFormatLogic.GasLimitMaximum; request.GasPrice = SmartContractMempoolValidator.MinGasPrice; results = Validate(request); Assert.Empty(results); }
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 BuildCallContractTransactionResponse BuildCallTx(BuildCallContractTransactionRequest request) { AddressBalance addressBalance = this.walletManager.GetAddressBalance(request.Sender); if (addressBalance.AmountConfirmed == 0 && addressBalance.AmountUnconfirmed == 0) { return(BuildCallContractTransactionResponse.Failed(SenderNoBalanceError)); } var selectedInputs = new List <OutPoint>(); selectedInputs = this.walletManager.GetSpendableInputsForAddress(request.WalletName, request.Sender); uint160 addressNumeric = request.ContractAddress.ToUint160(this.network); ContractTxData txData; if (request.Parameters != null && request.Parameters.Any()) { try { object[] methodParameters = this.methodParameterStringSerializer.Deserialize(request.Parameters); txData = new ContractTxData(ReflectionVirtualMachine.VmVersion, (Gas)request.GasPrice, (Gas)request.GasLimit, addressNumeric, request.MethodName, methodParameters); } catch (MethodParameterStringSerializerException exception) { return(BuildCallContractTransactionResponse.Failed(exception.Message)); } } else { txData = new ContractTxData(ReflectionVirtualMachine.VmVersion, (Gas)request.GasPrice, (Gas)request.GasLimit, addressNumeric, request.MethodName); } HdAddress senderAddress = null; if (!string.IsNullOrWhiteSpace(request.Sender)) { Features.Wallet.Wallet wallet = this.walletManager.GetWallet(request.WalletName); HdAccount account = wallet.GetAccountByCoinType(request.AccountName, this.coinType); if (account == null) { return(BuildCallContractTransactionResponse.Failed($"No account with the name '{request.AccountName}' could be found.")); } senderAddress = account.GetCombinedAddresses().FirstOrDefault(x => x.Address == request.Sender); } ulong totalFee = (request.GasPrice * request.GasLimit) + Money.Parse(request.FeeAmount); var context = new TransactionBuildContext(this.network) { AccountReference = new WalletAccountReference(request.WalletName, request.AccountName), TransactionFee = totalFee, ChangeAddress = senderAddress, SelectedInputs = selectedInputs, MinConfirmations = MinConfirmationsAllChecks, WalletPassword = request.Password, Recipients = new[] { new Recipient { Amount = request.Amount, ScriptPubKey = new Script(this.callDataSerializer.Serialize(txData)) } }.ToList() }; try { Transaction transaction = this.walletTransactionHandler.BuildTransaction(context); return(BuildCallContractTransactionResponse.Succeeded(request.MethodName, transaction, context.TransactionFee)); } catch (Exception exception) { return(BuildCallContractTransactionResponse.Failed(exception.Message)); } }
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.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>(); 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); var receiptStorage = scReceiver.FullNode.NodeService <ISmartContractReceiptStorage>(); Assert.NotNull(receiptStorage.GetReceipt(response.TransactionId)); // 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)); 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()); // Check receipts var receiptResponse = (JsonResult)senderSmartContractsController.GetReceipt(callResponse.TransactionId.ToString()); var receiptModel = (ReceiptModel)receiptResponse.Value; Assert.True(receiptModel.Successful); } }
public async Task <IActionResult> BuildAndSendCallSmartContractTransactionAsync([FromBody] BuildCallContractTransactionRequest request) { if (!this.ModelState.IsValid) { return(ModelStateErrors.BuildErrorResponse(this.ModelState)); } if (!this.connectionManager.ConnectedPeers.Any()) { this.logger.LogTrace("(-)[NO_CONNECTED_PEERS]"); return(ErrorHelpers.BuildErrorResponse(HttpStatusCode.Forbidden, "Can't send transaction as the node requires at least one connection.", string.Empty)); } BuildCallContractTransactionResponse response = this.smartContractTransactionService.BuildCallTx(request); if (!response.Success) { return(this.Json(response)); } Transaction transaction = this.network.CreateTransaction(response.Hex); await this.broadcasterManager.BroadcastTransactionAsync(transaction); // Check if transaction was actually added to a mempool. TransactionBroadcastEntry transactionBroadCastEntry = this.broadcasterManager.GetTransaction(transaction.GetHash()); if (transactionBroadCastEntry?.TransactionBroadcastState == Features.Wallet.Broadcasting.TransactionBroadcastState.CantBroadcast) { this.logger.LogError("Exception occurred: {0}", transactionBroadCastEntry.ErrorMessage); return(ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, transactionBroadCastEntry.ErrorMessage, "Transaction Exception")); } response.Message = $"Your CALL method {request.MethodName} transaction was successfully built and sent. Check the receipt using the transaction ID once it has been included in a new block."; return(this.Json(response)); }
private BuildCallContractTransactionResponse BuildCallTx(BuildCallContractTransactionRequest request) { this.logger.LogTrace(request.ToString()); AddressBalance addressBalance = this.walletManager.GetAddressBalance(request.Sender); if (addressBalance.AmountConfirmed == 0) { return(BuildCallContractTransactionResponse.Failed($"The 'Sender' address you're trying to spend from doesn't have a confirmed balance. Current unconfirmed balance: {addressBalance.AmountUnconfirmed}. Please check the 'Sender' address.")); } var selectedInputs = new List <OutPoint>(); selectedInputs = this.walletManager.GetSpendableTransactionsInWallet(request.WalletName, MinConfirmationsAllChecks).Where(x => x.Address.Address == request.Sender).Select(x => x.ToOutPoint()).ToList(); ulong gasPrice = ulong.Parse(request.GasPrice); ulong gasLimit = ulong.Parse(request.GasLimit); uint160 addressNumeric = new Address(request.ContractAddress).ToUint160(this.network); SmartContractCarrier carrier; if (request.Parameters != null && request.Parameters.Any()) { carrier = SmartContractCarrier.CallContract(ReflectionVirtualMachine.VmVersion, addressNumeric, request.MethodName, gasPrice, new Gas(gasLimit), request.Parameters); } else { carrier = SmartContractCarrier.CallContract(ReflectionVirtualMachine.VmVersion, addressNumeric, request.MethodName, gasPrice, new Gas(gasLimit)); } HdAddress senderAddress = null; if (!string.IsNullOrWhiteSpace(request.Sender)) { Features.Wallet.Wallet wallet = this.walletManager.GetWallet(request.WalletName); HdAccount account = wallet.GetAccountByCoinType(request.AccountName, this.coinType); senderAddress = account.GetCombinedAddresses().FirstOrDefault(x => x.Address == request.Sender); } ulong totalFee = (gasPrice * gasLimit) + Money.Parse(request.FeeAmount); var context = new TransactionBuildContext(this.network) { AccountReference = new WalletAccountReference(request.WalletName, request.AccountName), TransactionFee = totalFee, ChangeAddress = senderAddress, SelectedInputs = selectedInputs, MinConfirmations = MinConfirmationsAllChecks, WalletPassword = request.Password, Recipients = new[] { new Recipient { Amount = request.Amount, ScriptPubKey = new Script(carrier.Serialize()) } }.ToList() }; try { Transaction transaction = this.walletTransactionHandler.BuildTransaction(context); return(BuildCallContractTransactionResponse.Succeeded(request.MethodName, transaction, context.TransactionFee)); } catch (Exception exception) { return(BuildCallContractTransactionResponse.Failed(exception.Message)); } }
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); } }
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 SendAndReceiveLocalSmartContractTransactionsUsingController() { 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.ToString(), GasPrice = SmartContractMempoolValidator.MinGasPrice.ToString(), 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 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)); string counterRequestResult = (string)((JsonResult)senderSmartContractsController.GetStorage(new GetStorageRequest { ContractAddress = response.NewContractAddress, StorageKey = "Counter", DataType = MethodParameterDataType.Int })).Value; Assert.Equal("12345", counterRequestResult); var callRequest = new BuildCallContractTransactionRequest { AccountName = AccountName, GasLimit = gasLimit.ToString(), GasPrice = SmartContractMempoolValidator.MinGasPrice.ToString(), Amount = "0", MethodName = "Increment", 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(12346, 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)); // Check that the on-chain storage has not changed after mining counterRequestResult = (string)((JsonResult)senderSmartContractsController.GetStorage(new GetStorageRequest { ContractAddress = response.NewContractAddress, StorageKey = "Counter", DataType = MethodParameterDataType.Int })).Value; Assert.Equal("12345", counterRequestResult); // Check wallet history again to make sure nothing has changed result = (JsonResult)senderWalletController.GetHistory(new WalletHistoryRequest { AccountName = AccountName, WalletName = WalletName }); walletHistoryModel = (WalletHistoryModel)result.Value; Assert.Single(walletHistoryModel.AccountsHistoryModel.First().TransactionsHistory.Where(x => x.Type == TransactionItemType.Send)); } }