public IActionResult LocalCallSmartContractTransaction([FromBody] LocalCallContractRequest request) { if (!this.ModelState.IsValid) { return(ModelStateErrors.BuildErrorResponse(this.ModelState)); } // Rewrite the method name to a property name this.RewritePropertyGetterName(request); try { ContractTxData txData = this.smartContractTransactionService.BuildLocalCallTxData(request); ILocalExecutionResult result = this.localExecutor.Execute( (ulong)this.chainIndexer.Height, request.Sender?.ToUint160(this.network) ?? new uint160(), string.IsNullOrWhiteSpace(request.Amount) ? (Money)request.Amount : 0, txData); return(this.Json(result, new JsonSerializerSettings { ContractResolver = new ContractParametersContractResolver(this.network) })); } catch (MethodParameterStringSerializerException e) { return(this.Json(ErrorHelpers.BuildErrorResponse(HttpStatusCode.InternalServerError, e.Message, "Error deserializing method parameters"))); } }
public void Call_Contract_Failure() { var parameters = new object[] { }; var contractTxData = new ContractTxData(1, 1, (RuntimeObserver.Gas) 1000, uint160.One, "TestMethod", parameters); StateTransitionResult stateTransitionResult = StateTransitionResult.Fail((RuntimeObserver.Gas) 100, StateTransitionErrorKind.VmError); var fixture = new ExecutorFixture(contractTxData); IState snapshot = fixture.State.Object.Snapshot(); fixture.StateProcessor .Setup(s => s.Apply(snapshot, It.IsAny <ExternalCallMessage>())) .Returns(stateTransitionResult); IStateRepository trackedMock = Mock.Of <IStateRepository>(); fixture.ContractStateRoot.Setup(s => s.StartTracking()).Returns(trackedMock); var sut = new LocalExecutor( fixture.LoggerFactory, fixture.CallDataSerializer.Object, fixture.ContractStateRoot.Object, fixture.StateFactory.Object, fixture.StateProcessor.Object, fixture.ContractPrimitiveSerializer.Object); ILocalExecutionResult result = sut.Execute(fixture.ContractTransactionContext.BlockHeight, fixture.ContractTransactionContext.Sender, fixture.ContractTransactionContext.TxOutValue, contractTxData); fixture.StateFactory.Verify(sf => sf .Create( trackedMock, It.IsAny <IBlock>(), fixture.ContractTransactionContext.TxOutValue, It.IsAny <uint256>()), Times.Once); // We only apply the message to the snapshot. fixture.StateProcessor.Verify(sm => sm.Apply(snapshot, It.Is <ExternalCallMessage>(m => m.Method.Name == contractTxData.MethodName && m.Method.Parameters == contractTxData.MethodParameters && m.Amount == fixture.ContractTransactionContext.TxOutValue && m.From == fixture.ContractTransactionContext.Sender && m.To == contractTxData.ContractAddress)), Times.Once); // Should never transition to the snapshot. fixture.State.Verify(sm => sm.TransitionTo(snapshot), Times.Never); // Should never save on the state fixture.ContractStateRoot.Verify(sr => sr.Commit(), Times.Never); Assert.Equal(stateTransitionResult.Error.VmError, result.ErrorMessage); Assert.True(result.Revert); Assert.Equal <IReadOnlyList <TransferInfo> >(fixture.State.Object.InternalTransfers, result.InternalTransfers); Assert.Equal(stateTransitionResult.GasConsumed, result.GasConsumed); Assert.Null(result.Return); Assert.Equal <IList <Log> >(fixture.State.Object.GetLogs(fixture.ContractPrimitiveSerializer.Object), result.Logs); }
private void CheckTransaction(Transaction transaction, IEnumerable <IContractTransactionValidationRule> rules, Money suppliedBudget) { TxOut scTxOut = transaction.TryGetSmartContractTxOut(); if (scTxOut == null) { // No SC output to validate. return; } Result <ContractTxData> callDataDeserializationResult = this.callDataSerializer.Deserialize(scTxOut.ScriptPubKey.ToBytes()); if (callDataDeserializationResult.IsFailure) { new ConsensusError("invalid-calldata-format", string.Format("Invalid {0} format", typeof(ContractTxData).Name)).Throw(); } ContractTxData txData = callDataDeserializationResult.Value; foreach (IContractTransactionValidationRule rule in rules) { rule.CheckContractTransaction(txData, suppliedBudget); } }
public (Money, TxOut) Process(ContractTxData contractTxData, ulong mempoolFee, uint160 sender, Gas gasConsumed, bool outOfGas) { this.logger.LogTrace("(){0}:{1}", nameof(mempoolFee), mempoolFee); Money fee = mempoolFee; if (outOfGas) { this.logger.LogTrace("(-)[OUTOFGAS_EXCEPTION]"); return(fee, null); } var refund = new Money(contractTxData.GasCostBudget - (gasConsumed * contractTxData.GasPrice)); this.logger.LogTrace("{0}:{1},{2}:{3},{4}:{5},{6}:{7}", nameof(contractTxData.GasCostBudget), contractTxData.GasCostBudget, nameof(gasConsumed), gasConsumed, nameof(contractTxData.GasPrice), contractTxData.GasPrice, nameof(refund), refund); TxOut ret = null; if (refund > 0) { fee -= refund; ret = CreateRefund(sender, refund); } this.logger.LogTrace("(-)"); return(fee, ret); }
public void SmartContract_CanSerialize_OP_CREATECONTRACT_WithoutMethodParameters() { byte[] contractExecutionCode = Encoding.UTF8.GetBytes( @" using System; using Stratis.SmartContracts; [References] public class Test : SmartContract { public void TestMethod() { [CodeToExecute] } }" ); var contractTxData = new ContractTxData(1, 1, (RuntimeObserver.Gas) 5000, contractExecutionCode, signatures: new[] { Convert.ToBase64String(new byte[] { 1, 2, 3 }), Convert.ToBase64String(new byte[] { 7, 8, 9 }) }); Result <ContractTxData> callDataResult = this.Serializer.Deserialize(this.Serializer.Serialize(contractTxData)); ContractTxData callData = callDataResult.Value; Assert.True((bool)callDataResult.IsSuccess); Assert.Equal(1, callData.VmVersion); Assert.Equal((byte)ScOpcodeType.OP_CREATECONTRACT, callData.OpCodeType); Assert.Equal <byte[]>(contractExecutionCode, callData.ContractExecutionCode); Assert.Equal((RuntimeObserver.Gas) 1, callData.GasPrice); Assert.Equal((RuntimeObserver.Gas) 5000, callData.GasLimit); Assert.Equal(new byte[] { 1, 2, 3 }, Convert.FromBase64String(callData.Signatures[0])); Assert.Equal(new byte[] { 7, 8, 9 }, Convert.FromBase64String(callData.Signatures[1])); }
public (Money, TxOut) Process(ContractTxData contractTxData, ulong mempoolFee, uint160 sender, Gas gasConsumed, bool outOfGas) { Money fee = mempoolFee; if (outOfGas) { this.logger.LogTrace("(-)[OUTOFGAS_EXCEPTION]"); return(fee, null); } var refund = new Money(contractTxData.GasCostBudget - (gasConsumed * contractTxData.GasPrice)); TxOut ret = null; if (refund > 0) { fee -= refund; ret = CreateRefund(sender, refund); } return(fee, ret); }
public void SmartContract_CanSerialize_OP_CREATECONTRACT_WithoutMethodParameters() { byte[] contractExecutionCode = Encoding.UTF8.GetBytes( @" using System; using Stratis.SmartContracts; [References] public class Test : SmartContract { public void TestMethod() { [CodeToExecute] } }" ); var contractTxData = new ContractTxData(1, 1, (Gas)5000, contractExecutionCode); var callDataResult = this.Serializer.Deserialize(this.Serializer.Serialize(contractTxData)); var callData = callDataResult.Value; Assert.True(callDataResult.IsSuccess); Assert.Equal(1, callData.VmVersion); Assert.Equal((byte)ScOpcodeType.OP_CREATECONTRACT, callData.OpCodeType); Assert.Equal(contractExecutionCode, callData.ContractExecutionCode); Assert.Equal((Gas)1, callData.GasPrice); Assert.Equal((Gas)5000, callData.GasLimit); }
public void SmartContract_CanSerialize_OP_CREATECONTRACT_WithMethodParameters() { byte[] contractExecutionCode = Encoding.UTF8.GetBytes( @" using System; using Stratis.SmartContracts; [References] public class Test : SmartContract { public void TestMethod(int orders, bool canOrder) { [CodeToExecute] } }" ); object[] methodParameters = { (short)12, true, "te|s|t", "te#st", "#4#te#st#", '#' }; var contractTxData = new ContractTxData(1, 1, (Gas)5000, contractExecutionCode, methodParameters); var callDataResult = this.Serializer.Deserialize(this.Serializer.Serialize(contractTxData)); var callData = callDataResult.Value; Assert.True(callDataResult.IsSuccess); Assert.Equal(contractTxData.VmVersion, callData.VmVersion); Assert.Equal(contractTxData.OpCodeType, callData.OpCodeType); Assert.Equal(contractTxData.ContractExecutionCode, callData.ContractExecutionCode); Assert.Equal(methodParameters.Length, callData.MethodParameters.Length); Assert.NotNull(callData.MethodParameters[0]); Assert.Equal(methodParameters[0], callData.MethodParameters[0]); Assert.NotNull(callData.MethodParameters[1]); Assert.Equal(methodParameters[1], (bool)callData.MethodParameters[1]); Assert.NotNull(callData.MethodParameters[2]); Assert.Equal(methodParameters[2], callData.MethodParameters[2]); Assert.NotNull(callData.MethodParameters[3]); Assert.Equal(methodParameters[3], callData.MethodParameters[3]); Assert.NotNull(callData.MethodParameters[4]); Assert.Equal(methodParameters[4], callData.MethodParameters[4]); Assert.NotNull(callData.MethodParameters[5]); Assert.Equal(methodParameters[5], callData.MethodParameters[5]); Assert.Equal(contractTxData.GasPrice, callData.GasPrice); Assert.Equal(contractTxData.GasLimit, callData.GasLimit); }
public ILocalExecutionResult Execute(IContractTransactionContext transactionContext) { Result <ContractTxData> callDataDeserializationResult = this.serializer.Deserialize(transactionContext.Data); ContractTxData callData = callDataDeserializationResult.Value; bool creation = callData.IsCreateContract; var block = new Block( transactionContext.BlockHeight, transactionContext.CoinbaseAddress.ToAddress() ); IState state = this.stateFactory.Create( this.stateRoot.StartTracking(), block, transactionContext.TxOutValue, transactionContext.TransactionHash); StateTransitionResult result; IState newState = state.Snapshot(); if (creation) { var message = new ExternalCreateMessage( transactionContext.Sender, transactionContext.TxOutValue, callData.GasLimit, callData.ContractExecutionCode, callData.MethodParameters ); result = this.stateProcessor.Apply(newState, message); } else { var message = new ExternalCallMessage( callData.ContractAddress, transactionContext.Sender, transactionContext.TxOutValue, callData.GasLimit, new MethodCall(callData.MethodName, callData.MethodParameters) ); result = this.stateProcessor.Apply(newState, message); } var executionResult = new LocalExecutionResult { ErrorMessage = result.Error?.GetErrorMessage(), Revert = result.IsFailure, GasConsumed = result.GasConsumed, Return = result.Success?.ExecutionResult, InternalTransfers = state.InternalTransfers.ToList(), Logs = state.GetLogs(this.contractPrimitiveSerializer) }; return(executionResult); }
private void CheckTransaction(Transaction transaction, Money suppliedBudget) { if (!transaction.IsSmartContractExecTransaction()) { return; } TxOut scTxOut = transaction.TryGetSmartContractTxOut(); if (scTxOut == null) { new ConsensusError("no-smart-contract-tx-out", "No smart contract TxOut").Throw(); } ICallDataSerializer serializer = CallDataSerializer.Default; Result <ContractTxData> callDataDeserializationResult = serializer.Deserialize(scTxOut.ScriptPubKey.ToBytes()); if (callDataDeserializationResult.IsFailure) { new ConsensusError("invalid-calldata-format", string.Format("Invalid {0} format", typeof(ContractTxData).Name)).Throw(); } ContractTxData callData = callDataDeserializationResult.Value; if (callData.GasPrice < GasPriceMinimum) { // Supplied gas price is too low. this.ThrowGasPriceLessThanMinimum(); } if (callData.GasPrice > GasPriceMaximum) { // Supplied gas price is too high. this.ThrowGasPriceMoreThanMaximum(); } // TODO: When checking gas limit, if checking for a CREATE, do BaseFee + CreationAndValidationFee if (callData.GasLimit < GasLimitMinimum) { // Supplied gas limit is too low. this.ThrowGasLessThanBaseFee(); } if (callData.GasLimit > GasLimitMaximum) { // Supplied gas limit is too high - at a certain point we deem that a contract is taking up too much time. this.ThrowGasGreaterThanHardLimit(); } // Note carrier.GasCostBudget cannot overflow given values are within constraints above. if (suppliedBudget < new Money(callData.GasCostBudget)) { // Supplied satoshis are less than the budget we said we had for the contract execution this.ThrowGasGreaterThanFee(); } }
public void Local_Call_At_Height() { // Demonstrates some potentially unusual behaviour when saving contract state. var localExecutor = this.mockChain.Nodes[0].CoreNode.FullNode.NodeService <ILocalExecutor>(); // Ensure fixture is funded. this.mockChain.MineBlocks(1); // Deploy contract ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/StorageDemo.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(); NBitcoin.Block lastBlock = this.node1.GetLastBlock(); ReceiptResponse receipt = this.node1.GetReceipt(preResponse.TransactionId.ToString()); Assert.True(receipt.Success); // Get initial state at height var call = new ContractTxData(1, 100, (Gas)250000, preResponse.NewContractAddress.ToUint160(this.node1.CoreNode.FullNode.Network), nameof(StorageDemo.GetCounterValue)); var initialState = localExecutor.Execute((ulong)this.node1.CoreNode.FullNode.ChainIndexer.Height, this.mockChain.Nodes[0].MinerAddress.Address.ToUint160(this.node1.CoreNode.FullNode.Network), 0, call); Assert.Equal(12345, (int)initialState.Return); // Call Counter() and confirm that it succeeds BuildCallContractTransactionResponse response = this.node1.SendCallContractTransaction( nameof(StorageDemo.Increment), preResponse.NewContractAddress, 0); this.mockChain.WaitAllMempoolCount(1); this.mockChain.MineBlocks(1); lastBlock = this.node1.GetLastBlock(); // Blocks progressed Assert.NotEqual(currentHash, lastBlock.GetHash()); // Get local state at height 2 after calling counter initialState = localExecutor.Execute((ulong)this.node1.CoreNode.FullNode.ChainIndexer.Height, this.mockChain.Nodes[0].MinerAddress.Address.ToUint160(this.node1.CoreNode.FullNode.Network), 0, call); Assert.Equal(12346, (int)initialState.Return); // Get local state at previous height before calling counter initialState = localExecutor.Execute((ulong)this.node1.CoreNode.FullNode.ChainIndexer.Height - 1, this.mockChain.Nodes[0].MinerAddress.Address.ToUint160(this.node1.CoreNode.FullNode.Network), 0, call); Assert.Equal(12345, (int)initialState.Return); }
public void Create_Contract_Failure() { var contractTxData = new ContractTxData(1, 1, (Gas)1000, new byte[] { 0xAA, 0xBB, 0xCC }); StateTransitionResult stateTransitionResult = StateTransitionResult.Fail((Gas)100, StateTransitionErrorKind.VmError); var fixture = new ExecutorFixture(contractTxData); IState snapshot = fixture.State.Object.Snapshot(); fixture.StateProcessor .Setup(s => s.Apply(snapshot, It.IsAny <ExternalCreateMessage>())) .Returns(stateTransitionResult); IStateRepository trackedMock = Mock.Of <IStateRepository>(); fixture.ContractStateRoot.Setup(s => s.StartTracking()).Returns(trackedMock); var sut = new LocalExecutor( fixture.LoggerFactory, fixture.CallDataSerializer.Object, fixture.ContractStateRoot.Object, fixture.StateFactory.Object, fixture.StateProcessor.Object, fixture.ContractPrimitiveSerializer.Object); ILocalExecutionResult result = sut.Execute(fixture.ContractTransactionContext); fixture.CallDataSerializer.Verify(s => s.Deserialize(fixture.Data), Times.Once); fixture.StateFactory.Verify(sf => sf .Create( trackedMock, It.IsAny <IBlock>(), fixture.ContractTransactionContext.TxOutValue, fixture.ContractTransactionContext.TransactionHash), Times.Once); // We only apply the message to the snapshot. fixture.StateProcessor.Verify(sm => sm.Apply(fixture.State.Object.Snapshot(), It.Is <ExternalCreateMessage>(m => m.Code == contractTxData.ContractExecutionCode && m.Parameters == contractTxData.MethodParameters)), Times.Once); // Should never transition to the snapshot. fixture.State.Verify(sm => sm.TransitionTo(fixture.State.Object.Snapshot()), Times.Never); // Should never save on the state fixture.ContractStateRoot.Verify(sr => sr.Commit(), Times.Never); Assert.Equal(stateTransitionResult.Error.VmError, result.ErrorMessage); Assert.True(result.Revert); Assert.Equal(fixture.State.Object.InternalTransfers, result.InternalTransfers); Assert.Equal(stateTransitionResult.GasConsumed, result.GasConsumed); Assert.Null(result.Return); Assert.Equal(fixture.State.Object.GetLogs(fixture.ContractPrimitiveSerializer.Object), result.Logs); }
public void Should_Not_Validate_ContractCall() { var callTx = new ContractTxData(1, 1000, (Gas)10000, uint160.Zero, "Test"); var sut = new AllowedCodeHashLogic(this.hashChecker.Object, this.hashingStrategy.Object); sut.CheckContractTransaction(callTx, 0); this.hashingStrategy.Verify(h => h.Hash(It.IsAny <byte[]>()), Times.Never); this.hashChecker.Verify(h => h.CheckHashWhitelisted(It.IsAny <byte[]>()), Times.Never); }
public void ContractExecutionResult_OutOfGasException_NoRefundDue_NoFeeAdjustment() { var contractAddress = new uint160(1); var contractTxData = new ContractTxData(1, 1, (Gas)5000, contractAddress, "ThrowException"); var sender = new uint160(2); (Money fee, TxOut refund) = this.refundProcessor.Process(contractTxData, new Money(10500), sender, (Gas)5000, true); Assert.Equal(10500, fee); Assert.Null(refund); }
public void ContractExecutionResult_RefundDue_AdjustFee() { var contractAddress = new uint160(1); var contractTxData = new ContractTxData(1, 1, (Gas)5000, contractAddress, "ThrowException"); var sender = new uint160(2); (Money fee, TxOut refund) = this.refundProcessor.Process(contractTxData, new Money(10500), sender, (Gas)950, false); Assert.Equal(6450, fee); Assert.Equal(sender.ToBytes(), refund.ScriptPubKey.GetDestination(this.network).ToBytes()); Assert.Equal(4050, refund.Value); }
public static ContractTxData GetContractTxData(ICallDataSerializer callDataSerializer, TxOut scTxOut) { Result <ContractTxData> callDataDeserializationResult = callDataSerializer.Deserialize(scTxOut.ScriptPubKey.ToBytes()); if (callDataDeserializationResult.IsFailure) { new ConsensusError("invalid-calldata-format", string.Format("Invalid {0} format", typeof(ContractTxData).Name)).Throw(); } ContractTxData txData = callDataDeserializationResult.Value; return(txData); }
/// <inheritdoc/> public override void CheckTransaction(MempoolValidationContext context) { TxOut scTxOut = context.Transaction.TryGetSmartContractTxOut(); if (scTxOut == null) { // No SC output to validate. return; } ContractTxData txData = ContractTransactionChecker.GetContractTxData(this.callDataSerializer, scTxOut); SmartContractFormatLogic.Check(txData, context.Fees); }
public void CheckContractTransaction(ContractTxData txData, Money suppliedBudget) { if (!txData.IsCreateContract) { return; } byte[] hashedCode = this.hashingStrategy.Hash(txData.ContractExecutionCode); if (!this.whitelistedHashChecker.CheckHashWhitelisted(hashedCode)) { ThrowInvalidCode(); } }
public LocalExecutionResult LocalCallSmartContractTransaction([FromBody] LocalCallContractRequest request) { // Rewrite the method name to a property name this.RewritePropertyGetterName(request); ContractTxData txData = this.smartContractTransactionService.BuildLocalCallTxData(request); ulong height = request.BlockHeight.HasValue ? request.BlockHeight.Value : (ulong)this.chainIndexer.Height; ILocalExecutionResult result = this.localExecutor.Execute(height, request.Sender?.ToUint160(this.network) ?? new uint160(), string.IsNullOrWhiteSpace(request.Amount) ? (Money)request.Amount : 0, txData); return(result as LocalExecutionResult); }
public async Task SmartContractFormatRule_MultipleOutputs_SuccessAsync() { TestRulesContext testContext = TestRulesContextFactory.CreateAsync(this.network); ContractTransactionPartialValidationRule rule = testContext.CreateContractValidationRule(); var context = new PowRuleContext(new ValidationContext(), testContext.DateTimeProvider.GetTimeOffset()) { UnspentOutputSet = GetMockOutputSet() }; context.ValidationContext.BlockToValidate = testContext.Network.Consensus.ConsensusFactory.CreateBlock(); var gasPriceSatoshis = 20; var gasLimit = 4000000; var gasBudgetSatoshis = gasPriceSatoshis * gasLimit; var relayFeeSatoshis = 10000; var change = 200000; var totalSuppliedSatoshis = gasBudgetSatoshis + relayFeeSatoshis; var contractTxData = new ContractTxData(1, (ulong)gasPriceSatoshis, (Stratis.SmartContracts.RuntimeObserver.Gas)gasLimit, 0, "TestMethod"); var serialized = this.callDataSerializer.Serialize(contractTxData); Transaction funding = new Transaction { Outputs = { new TxOut(totalSuppliedSatoshis + change, new Script()) } }; var transactionBuilder = new TransactionBuilder(testContext.Network); transactionBuilder.AddCoins(funding); transactionBuilder.SendFees(totalSuppliedSatoshis); transactionBuilder.Send(new Script(serialized), 0); // Add a change output to the transaction transactionBuilder.SetChange(new Script()); Transaction transaction = transactionBuilder.BuildTransaction(false); context.ValidationContext.BlockToValidate.Transactions = new List <Transaction> { transaction }; await rule.RunAsync(context); }
/// <inheritdoc/> public override void CheckTransaction(MempoolValidationContext context) { TxOut scTxOut = context.Transaction.TryGetSmartContractTxOut(); if (scTxOut == null) { // No SC output to validate. return; } ContractTxData txData = ContractTransactionChecker.GetContractTxData(this.callDataSerializer, scTxOut); // Delegate to full validation rule. The full validation rule will differ for PoA/PoS. this.contractTransactionFullValidationRule.CheckContractTransaction(txData, null, this.chainIndexer.Tip.Height); }
public void SmartContract_CanSerialize_OP_CALLCONTRACT_WithoutMethodParameters() { var contractTxData = new ContractTxData(1, 1, (Gas)5000, 100, "Execute"); var callDataResult = this.Serializer.Deserialize(this.Serializer.Serialize(contractTxData)); var callData = callDataResult.Value; Assert.True(callDataResult.IsSuccess); Assert.Equal(contractTxData.VmVersion, callData.VmVersion); Assert.Equal(contractTxData.OpCodeType, callData.OpCodeType); Assert.Equal(contractTxData.ContractAddress, callData.ContractAddress); Assert.Equal(contractTxData.MethodName, callData.MethodName); Assert.Equal(contractTxData.GasPrice, callData.GasPrice); Assert.Equal(contractTxData.GasLimit, callData.GasLimit); }
public void SmartContract_CanSerialize_OP_CALLCONTRACT_WithMethodParameters() { object[] methodParameters = { true, (byte)1, Encoding.UTF8.GetBytes("test"), 's', "test", (uint)36, (ulong)29, "0x95D34980095380851902ccd9A1Fb4C813C2cb639".HexToAddress(), "0x95D34980095380851902ccd9A1Fb4C813C2cb639".HexToAddress() }; var contractTxData = new ContractTxData(1, 1, (Gas)5000, 100, "Execute", methodParameters); var callDataResult = this.Serializer.Deserialize(this.Serializer.Serialize(contractTxData)); var callData = callDataResult.Value; Assert.True(callDataResult.IsSuccess); Assert.NotNull(callData.MethodParameters[0]); Assert.Equal(methodParameters[0], callData.MethodParameters[0]); Assert.NotNull(callData.MethodParameters[1]); Assert.Equal(methodParameters[1], callData.MethodParameters[1]); Assert.NotNull(callData.MethodParameters[2]); Assert.True(((byte[])methodParameters[2]).SequenceEqual((byte[])callData.MethodParameters[2])); Assert.NotNull(callData.MethodParameters[3]); Assert.Equal(methodParameters[3], callData.MethodParameters[3]); Assert.NotNull(callData.MethodParameters[4]); Assert.Equal(methodParameters[4], callData.MethodParameters[4]); Assert.NotNull(callData.MethodParameters[5]); Assert.Equal(methodParameters[5], callData.MethodParameters[5]); Assert.NotNull(callData.MethodParameters[6]); Assert.Equal(methodParameters[6], callData.MethodParameters[6]); Assert.NotNull(callData.MethodParameters[7]); Assert.Equal(methodParameters[7], callData.MethodParameters[7]); Assert.NotNull(callData.MethodParameters[8]); Assert.Equal(methodParameters[8], callData.MethodParameters[8]); }
public void Should_Throw_ConsensusErrorException_If_Hash_Not_Allowed() { var code = RandomUtils.GetBytes(2048); byte[] hash = HashHelper.Keccak256(code); this.hashingStrategy.Setup(h => h.Hash(code)).Returns(hash); this.hashChecker.Setup(h => h.CheckHashWhitelisted(hash)).Returns(false); var sut = new AllowedCodeHashLogic(this.hashChecker.Object, this.hashingStrategy.Object); var tx = new ContractTxData(1, 1000, (Gas)10000, code); Assert.Throws <ConsensusErrorException>(() => sut.CheckContractTransaction(tx, 0)); this.hashChecker.Verify(h => h.CheckHashWhitelisted(hash), Times.Once); }
private void CheckTransaction(Transaction transaction, IEnumerable <IContractTransactionValidationRule> rules, int blockHeight) { TxOut scTxOut = transaction.TryGetSmartContractTxOut(); if (scTxOut == null) { // No SC output to validate. return; } ContractTxData txData = GetContractTxData(this.callDataSerializer, scTxOut); foreach (IContractTransactionValidationRule rule in rules) { rule.CheckContractTransaction(txData, null, blockHeight); } }
public void Should_Allow_Code_With_Valid_Hash() { var code = RandomUtils.GetBytes(2048); byte[] hash = HashHelper.Keccak256(code); this.hashingStrategy.Setup(h => h.Hash(code)).Returns(hash); this.hashChecker.Setup(h => h.CheckHashWhitelisted(hash)).Returns(true); var tx = new ContractTxData(1, 1000, (Gas)10000, code); var sut = new AllowedCodeHashLogic(this.hashChecker.Object, this.hashingStrategy.Object); sut.CheckContractTransaction(tx, 0); this.hashChecker.Verify(h => h.CheckHashWhitelisted(hash), Times.Once); }
public void CheckContractTransaction(ContractTxData txData, Money suppliedBudget) { if (!txData.IsCreateContract) { // We do not need to validate calls. return; } // If this rule is being used as part of consensus, then we need to have the SignedCodeCallDataSerializer being used. // If the below line is throwing, it must not be being used. var signedTxData = (SignedCodeContractTxData)txData; if (!this.contractSigner.Verify(this.signingContractPubKey, signedTxData.ContractExecutionCode, signedTxData.CodeSignature)) { this.ThrowInvalidCode(); } }
public IActionResult LocalCallSmartContractTransaction([FromBody] LocalCallContractRequest request) { if (!this.ModelState.IsValid) { return(ModelStateErrors.BuildErrorResponse(this.ModelState)); } // Rewrite the method name to a property name this.RewritePropertyGetterName(request); try { ContractTxData txData = this.smartContractTransactionService.BuildLocalCallTxData(request); var height = request.BlockHeight.HasValue ? request.BlockHeight.Value : (ulong)this.chainIndexer.Height; ILocalExecutionResult result = this.localExecutor.Execute( height, request.Sender?.ToUint160(this.network) ?? new uint160(), !string.IsNullOrWhiteSpace(request.Amount) ? (Money)request.Amount : 0, txData); var deserializer = new ApiLogDeserializer(this.primitiveSerializer, this.network, result.StateRoot, this.contractAssemblyCache); var response = new LocalExecutionResponse { InternalTransfers = deserializer.MapTransferInfo(result.InternalTransfers.ToArray()), Logs = deserializer.MapLogResponses(result.Logs.ToArray()), GasConsumed = result.GasConsumed, Revert = result.Revert, ErrorMessage = result.ErrorMessage, Return = result.Return // All return values should be primitives, let default serializer handle. }; return(this.Json(response, new JsonSerializerSettings { ContractResolver = new ContractParametersContractResolver(this.network) })); } catch (MethodParameterStringSerializerException e) { return(this.Json(ErrorHelpers.BuildErrorResponse(HttpStatusCode.InternalServerError, e.Message, "Error deserializing method parameters"))); } }
public void Local_Call_Should_Produce_Logs_And_Transfers() { // Demonstrates some potentially unusual behaviour when saving contract state. var localExecutor = this.mockChain.Nodes[0].CoreNode.FullNode.NodeService <ILocalExecutor>(); // Ensure fixture is funded. this.mockChain.MineBlocks(1); // Deploy contract ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/LocalCallTests.cs"); Assert.True(compilationResult.Success); BuildCreateContractTransactionResponse preResponse = this.node1.SendCreateContractTransaction(compilationResult.Compilation, 10); this.mockChain.WaitAllMempoolCount(1); this.mockChain.MineBlocks(1); Assert.NotNull(this.node1.GetCode(preResponse.NewContractAddress)); Assert.Equal(1000000000UL, this.node1.GetContractBalance(preResponse.NewContractAddress)); uint256 currentHash = this.node1.GetLastBlock().GetHash(); NBitcoin.Block lastBlock = this.node1.GetLastBlock(); ReceiptResponse receipt = this.node1.GetReceipt(preResponse.TransactionId.ToString()); Assert.True(receipt.Success); // Create a log in a local call var call = new ContractTxData(1, 100, (Gas)250000, preResponse.NewContractAddress.ToUint160(this.node1.CoreNode.FullNode.Network), nameof(LocalCallTests.CreateLog)); var createLogResult = 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(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 async Task SmartContractFormatRule_FailureAsync() { TestRulesContext testContext = TestRulesContextFactory.CreateAsync(this.network); ContractTransactionPartialValidationRule rule = testContext.CreateContractValidationRule(); var context = new PowRuleContext(new ValidationContext(), testContext.DateTimeProvider.GetTimeOffset()); context.ValidationContext.BlockToValidate = testContext.Network.Consensus.ConsensusFactory.CreateBlock(); var gasPriceSatoshis = 20; var gasLimit = 4000000; var gasBudgetSatoshis = gasPriceSatoshis * gasLimit; var relayFeeSatoshis = 10000; var totalSuppliedSatoshis = gasBudgetSatoshis + relayFeeSatoshis; var higherGasLimit = gasLimit + 10000; var contractTxData = new ContractTxData(1, (ulong)gasPriceSatoshis, (Stratis.SmartContracts.RuntimeObserver.Gas)higherGasLimit, 0, "TestMethod"); var serialized = this.callDataSerializer.Serialize(contractTxData); Transaction funding = new Transaction { Outputs = { new TxOut(totalSuppliedSatoshis, new Script()) } }; var transactionBuilder = new TransactionBuilder(testContext.Network); transactionBuilder.AddCoins(funding); transactionBuilder.SendFees(relayFeeSatoshis); transactionBuilder.Send(new Script(serialized), gasBudgetSatoshis); Transaction transaction = transactionBuilder.BuildTransaction(false); context.ValidationContext.BlockToValidate.Transactions = new List <Transaction> { new Transaction(), // Include an empty transaction to ensure we're checking multiple. transaction }; await Assert.ThrowsAsync <ConsensusErrorException>(async() => await rule.RunAsync(context)); }