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")));
            }
        }
예제 #2
0
        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);
        }
예제 #3
0
        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);
        }
예제 #5
0
        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);
        }
예제 #7
0
        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);
        }
예제 #8
0
        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);
        }
예제 #9
0
        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);
        }
예제 #10
0
        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();
            }
        }
예제 #11
0
        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);
        }
예제 #13
0
        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);
        }
예제 #14
0
        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);
        }
예제 #15
0
        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();
            }
        }
예제 #19
0
        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);
        }
예제 #22
0
        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);
        }
예제 #23
0
        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]);
        }
예제 #24
0
        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);
            }
        }
예제 #26
0
        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);
        }
예제 #27
0
        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();
            }
        }
예제 #28
0
        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")));
            }
        }
예제 #29
0
        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));
        }