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 carrier           = SmartContractCarrier.CreateContract(1, contractExecutionCode, 1, (Gas)5000);
            var serializedCarrier = carrier.Serialize();
            var tx = new Transaction();

            tx.AddInput(new TxIn(new OutPoint(0, 0), new Script(OpcodeType.OP_1)));
            tx.AddOutput(new TxOut(new Money(5000000000L - 10000), new Script(serializedCarrier)));

            SmartContractCarrier deserialized = SmartContractCarrier.Deserialize(tx);

            Assert.Equal(1, deserialized.CallData.VmVersion);
            Assert.Equal((byte)ScOpcodeType.OP_CREATECONTRACT, deserialized.CallData.OpCodeType);
            Assert.Equal(contractExecutionCode, deserialized.CallData.ContractExecutionCode);
            Assert.Equal((Gas)1, deserialized.CallData.GasPrice);
            Assert.Equal((Gas)5000, deserialized.CallData.GasLimit);

            Assert.True(tx.Outputs[0].ScriptPubKey.IsSmartContractExec());
        }
        public string GetAddressFromScriptPubKey(Network network, Script script)
        {
            if (script.IsSmartContractCreate() || script.IsSmartContractCall())
            {
                var carrier = SmartContractCarrier.Deserialize(script);
                return(carrier.ContractAddress?.ToAddress(network));
            }

            return(this.baseAddressReader.GetAddressFromScriptPubKey(network, script));
        }
        public void SmartContract_CanSerialize_OP_CALLCONTRACT_WithoutMethodParameters()
        {
            var smartContractCarrier = SmartContractCarrier.CallContract(1, 100, "Execute", 1, (Gas)500000);

            var tx = new Transaction();

            tx.AddInput(new TxIn(new OutPoint(0, 0), new Script(OpcodeType.OP_1)));
            tx.AddOutput(new TxOut(new Money(5000000000L - 10000), new Script(smartContractCarrier.Serialize())));

            SmartContractCarrier deserialized = SmartContractCarrier.Deserialize(tx);

            Assert.Equal(smartContractCarrier.CallData.VmVersion, deserialized.CallData.VmVersion);
            Assert.Equal(smartContractCarrier.CallData.OpCodeType, deserialized.CallData.OpCodeType);
            Assert.Equal(smartContractCarrier.CallData.ContractAddress, deserialized.CallData.ContractAddress);
            Assert.Equal(smartContractCarrier.CallData.MethodName, deserialized.CallData.MethodName);
            Assert.Equal(smartContractCarrier.CallData.GasPrice, deserialized.CallData.GasPrice);
            Assert.Equal(smartContractCarrier.CallData.GasLimit, deserialized.CallData.GasLimit);
        }
        public void TransferProcessor_NoBalance_NoTransfers()
        {
            // Scenario where contract was sent 0, doesn't yet have any UTXO assigned, and no transfers were made.
            var carrierSkeleton = SmartContractCarrier.CallContract(1, new uint160(1), "Test", 1, (Gas)100_000);
            var transaction     = new Transaction();

            transaction.AddOutput(0, new Script(carrierSkeleton.Serialize()));
            var carrier   = SmartContractCarrier.Deserialize(transaction);
            var stateMock = new Mock <IContractStateRepository>();

            stateMock.Setup(x => x.GetCode(It.IsAny <uint160>())).Returns <byte[]>(null);
            var txContextMock = new Mock <ISmartContractTransactionContext>();
            var result        = new SmartContractExecutionResult();

            this.transferProcessor.Process(carrier, stateMock.Object, txContextMock.Object, new List <TransferInfo>(), false);

            // Ensure no state changes were made and no transaction has been added
            Assert.Null(result.InternalTransaction);
        }
Example #5
0
        private void CheckTransaction(Transaction transaction, Money suppliedBudget)
        {
            if (!transaction.IsSmartContractExecTransaction())
            {
                return;
            }

            // TODO: What if deserialization throws an error? We should check this.
            // Also the deserializer should throw custom exceptions.
            SmartContractCarrier carrier = SmartContractCarrier.Deserialize(transaction);

            if (carrier.CallData.GasPrice < GasPriceMinimum)
            {
                // Supplied gas price is too low.
                this.ThrowGasPriceLessThanMinimum();
            }

            if (carrier.CallData.GasPrice > GasPriceMaximum)
            {
                // Supplied gas price is too high.
                this.ThrowGasPriceMoreThanMaximum();
            }

            if (carrier.CallData.GasLimit < GasLimitMinimum)
            {
                // Supplied gas limit is too low.
                this.ThrowGasLessThanBaseFee();
            }

            if (carrier.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(carrier.GasCostBudget))
            {
                // Supplied satoshis are less than the budget we said we had for the contract execution
                this.ThrowGasGreaterThanFee();
            }
        }
        public void TransferProcessor_NoBalance_ReceivedFunds()
        {
            // Scenario where contract was sent some funds, doesn't yet have any UTXO assigned, and no transfers were made.
            var carrierSkeleton = SmartContractCarrier.CallContract(1, new uint160(1), "Test", 1, (Gas)100_000);
            var transaction     = new Transaction();

            transaction.AddOutput(100, new Script(carrierSkeleton.Serialize()));
            var carrier   = SmartContractCarrier.Deserialize(transaction);
            var stateMock = new Mock <IContractStateRepository>();

            stateMock.Setup(x => x.GetCode(It.IsAny <uint160>())).Returns <byte[]>(null);
            var txContextMock = new Mock <ISmartContractTransactionContext>();
            var result        = new SmartContractExecutionResult();

            this.transferProcessor.Process(carrier, stateMock.Object, txContextMock.Object, new List <TransferInfo>(), false);

            // Ensure unspent was saved, but no condensing transaction was generated.
            Assert.Null(result.InternalTransaction);
            stateMock.Verify(x => x.SetUnspent(new uint160(1), It.IsAny <ContractUnspentOutput>()));
        }
        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]
                    }
                }"
                );

            string[] methodParameters = new string[]
            {
                string.Format("{0}#{1}", (int)SmartContractCarrierDataType.Short, 12),
                string.Format("{0}#{1}", (int)SmartContractCarrierDataType.Bool, true),
                string.Format("{0}#{1}", (int)SmartContractCarrierDataType.String, "te|s|t"),
                string.Format("{0}#{1}", (int)SmartContractCarrierDataType.String, "te#st"),
                string.Format("{0}#{1}", (int)SmartContractCarrierDataType.String, "#4#te#st#"),
                string.Format("{0}#{1}", (int)SmartContractCarrierDataType.Char, '#'),
            };

            var carrier = SmartContractCarrier.CreateContract(1, contractExecutionCode, 1, (Gas)500000, methodParameters);

            var tx = new Transaction();

            tx.AddInput(new TxIn(new OutPoint(0, 0), new Script(OpcodeType.OP_1)));
            tx.AddOutput(new TxOut(new Money(5000000000L - 10000), new Script(carrier.Serialize())));

            SmartContractCarrier deserialized = SmartContractCarrier.Deserialize(tx);

            Assert.Equal(carrier.CallData.VmVersion, deserialized.CallData.VmVersion);
            Assert.Equal(carrier.CallData.OpCodeType, deserialized.CallData.OpCodeType);
            Assert.Equal(carrier.CallData.ContractExecutionCode, deserialized.CallData.ContractExecutionCode);
            Assert.Equal(6, deserialized.MethodParameters.Length);

            Assert.NotNull(carrier.MethodParameters[0]);
            Assert.Equal(12, deserialized.MethodParameters[0]);

            Assert.NotNull(carrier.MethodParameters[1]);
            Assert.True((bool)deserialized.MethodParameters[1]);

            Assert.NotNull(carrier.MethodParameters[2]);
            Assert.Equal("te|s|t", deserialized.MethodParameters[2]);

            Assert.NotNull(carrier.MethodParameters[3]);
            Assert.Equal("te#st", deserialized.MethodParameters[3]);

            Assert.NotNull(carrier.MethodParameters[4]);
            Assert.Equal("#4#te#st#", deserialized.MethodParameters[4]);

            Assert.NotNull(carrier.MethodParameters[5]);
            Assert.Equal("#", deserialized.MethodParameters[5]);

            Assert.Equal(carrier.CallData.GasPrice, deserialized.CallData.GasPrice);
            Assert.Equal(carrier.CallData.GasLimit, deserialized.CallData.GasLimit);
        }
        public void SmartContract_CanSerialize_OP_CALLCONTRACT_WithMethodParameters()
        {
            string[] methodParameters = new string[]
            {
                string.Format("{0}#{1}", (int)SmartContractCarrierDataType.Bool, true),
                string.Format("{0}#{1}", (int)SmartContractCarrierDataType.Byte, (byte)1),
                string.Format("{0}#{1}", (int)SmartContractCarrierDataType.ByteArray, BitConverter.ToString(Encoding.UTF8.GetBytes("test"))),
                string.Format("{0}#{1}", (int)SmartContractCarrierDataType.Char, 's'),
                string.Format("{0}#{1}", (int)SmartContractCarrierDataType.SByte, -45),
                string.Format("{0}#{1}", (int)SmartContractCarrierDataType.Short, 7),
                string.Format("{0}#{1}", (int)SmartContractCarrierDataType.String, "test"),
                string.Format("{0}#{1}", (int)SmartContractCarrierDataType.UInt, 36),
                string.Format("{0}#{1}", (int)SmartContractCarrierDataType.UInt160, new uint160(new byte[20] {
                    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
                })),
                string.Format("{0}#{1}", (int)SmartContractCarrierDataType.ULong, 29),
                string.Format("{0}#{1}", (int)SmartContractCarrierDataType.Address, new Address("0x95D34980095380851902ccd9A1Fb4C813C2cb639")),
                string.Format("{0}#{1}", (int)SmartContractCarrierDataType.Address, new Address("mxKorCkWmtrPoekfWiMzERJPhaT13nnkMy"))
            };

            var carrier = SmartContractCarrier.CallContract(1, 100, "Execute", 1, (Gas)500000, methodParameters);

            var tx = new Transaction();

            tx.AddInput(new TxIn(new OutPoint(0, 0), new Script(OpcodeType.OP_1)));
            tx.AddOutput(new TxOut(new Money(5000000000L - 10000), new Script(carrier.Serialize())));

            SmartContractCarrier deserialized = SmartContractCarrier.Deserialize(tx);

            Assert.NotNull(deserialized.MethodParameters[0]);
            Assert.Equal(carrier.MethodParameters[0], deserialized.MethodParameters[0]);

            Assert.NotNull(deserialized.MethodParameters[1]);
            Assert.Equal(carrier.MethodParameters[1], deserialized.MethodParameters[1]);

            Assert.NotNull(deserialized.MethodParameters[2]);
            Assert.Equal(carrier.MethodParameters[2], deserialized.MethodParameters[2]);

            Assert.NotNull(deserialized.MethodParameters[3]);
            Assert.Equal(carrier.MethodParameters[3], deserialized.MethodParameters[3]);

            Assert.NotNull(deserialized.MethodParameters[4]);
            Assert.Equal(carrier.MethodParameters[4], deserialized.MethodParameters[4]);

            Assert.NotNull(deserialized.MethodParameters[5]);
            Assert.Equal(carrier.MethodParameters[5], deserialized.MethodParameters[5]);

            Assert.NotNull(deserialized.MethodParameters[6]);
            Assert.Equal(carrier.MethodParameters[6], deserialized.MethodParameters[6]);

            Assert.NotNull(deserialized.MethodParameters[7]);
            Assert.Equal(carrier.MethodParameters[7], deserialized.MethodParameters[7]);

            Assert.NotNull(deserialized.MethodParameters[8]);
            Assert.Equal(carrier.MethodParameters[8], deserialized.MethodParameters[8]);

            Assert.NotNull(deserialized.MethodParameters[9]);
            Assert.Equal(carrier.MethodParameters[9], deserialized.MethodParameters[9]);

            Assert.NotNull(deserialized.MethodParameters[10]);
            Assert.Equal(carrier.MethodParameters[10], deserialized.MethodParameters[10]);

            Assert.NotNull(deserialized.MethodParameters[11]);
            Assert.Equal(carrier.MethodParameters[11], deserialized.MethodParameters[11]);
        }
Example #9
0
        public void VM_ExecuteContract_WithoutParameters()
        {
            //Get the contract execution code------------------------
            SmartContractCompilationResult compilationResult = SmartContractCompiler.CompileFile("SmartContracts/StorageTest.cs");

            Assert.True(compilationResult.Success);

            byte[] contractExecutionCode = compilationResult.Compilation;
            //-------------------------------------------------------

            //Call smart contract and add to transaction-------------
            var carrier         = SmartContractCarrier.CallContract(1, new uint160(1), "StoreData", 1, (Gas)500000);
            var transactionCall = new Transaction();

            transactionCall.AddInput(new TxIn());
            TxOut callTxOut = transactionCall.AddOutput(0, new Script(carrier.Serialize()));
            //-------------------------------------------------------

            //Deserialize the contract from the transaction----------
            var deserializedCall = SmartContractCarrier.Deserialize(transactionCall);
            //-------------------------------------------------------

            var repository = new ContractStateRepositoryRoot(new NoDeleteSource <byte[], byte[]>(new MemoryDictionarySource()));
            IContractStateRepository stateRepository = repository.StartTracking();

            var gasMeter = new GasMeter(deserializedCall.CallData.GasLimit);

            var persistenceStrategy = new MeteredPersistenceStrategy(repository, gasMeter, this.keyEncodingStrategy);
            var persistentState     = new PersistentState(persistenceStrategy, deserializedCall.CallData.ContractAddress, this.network);

            var internalTxExecutorFactory =
                new InternalTransactionExecutorFactory(this.keyEncodingStrategy, this.loggerFactory, this.network);
            var vm = new ReflectionVirtualMachine(internalTxExecutorFactory, this.loggerFactory);

            var sender = deserializedCall.Sender?.ToString() ?? TestAddress.ToString();

            var context = new SmartContractExecutionContext(
                new Block(1, new Address("2")),
                new Message(
                    new Address(deserializedCall.CallData.ContractAddress.ToString()),
                    new Address(sender),
                    deserializedCall.Value,
                    deserializedCall.CallData.GasLimit
                    ),
                TestAddress.ToUint160(this.network),
                deserializedCall.CallData.GasPrice
                );

            var result = vm.ExecuteMethod(
                contractExecutionCode,
                "StoreData",
                context,
                gasMeter,
                persistentState,
                repository);

            stateRepository.Commit();

            Assert.Equal(Encoding.UTF8.GetBytes("TestValue"), stateRepository.GetStorageValue(deserializedCall.CallData.ContractAddress, Encoding.UTF8.GetBytes("TestKey")));
            Assert.Equal(Encoding.UTF8.GetBytes("TestValue"), repository.GetStorageValue(deserializedCall.CallData.ContractAddress, Encoding.UTF8.GetBytes("TestKey")));
        }
Example #10
0
        public void VM_CreateContract_WithParameters()
        {
            //Get the contract execution code------------------------
            SmartContractCompilationResult compilationResult =
                SmartContractCompiler.CompileFile("SmartContracts/Auction.cs");

            Assert.True(compilationResult.Success);
            byte[] contractExecutionCode = compilationResult.Compilation;
            //-------------------------------------------------------

            //    //Call smart contract and add to transaction-------------
            string[] methodParameters = new string[]
            {
                string.Format("{0}#{1}", (int)SmartContractCarrierDataType.ULong, 5),
            };

            var carrier         = SmartContractCarrier.CreateContract(1, contractExecutionCode, 1, (Gas)500000, methodParameters);
            var transactionCall = new Transaction();

            transactionCall.AddInput(new TxIn());
            TxOut callTxOut = transactionCall.AddOutput(0, new Script(carrier.Serialize()));
            //-------------------------------------------------------

            //Deserialize the contract from the transaction----------
            var deserializedCall = SmartContractCarrier.Deserialize(transactionCall);
            //-------------------------------------------------------

            var repository = new ContractStateRepositoryRoot(new NoDeleteSource <byte[], byte[]>(new MemoryDictionarySource()));
            IContractStateRepository track = repository.StartTracking();

            var gasMeter                  = new GasMeter(deserializedCall.CallData.GasLimit);
            var persistenceStrategy       = new MeteredPersistenceStrategy(repository, gasMeter, new BasicKeyEncodingStrategy());
            var persistentState           = new PersistentState(persistenceStrategy, TestAddress.ToUint160(this.network), this.network);
            var internalTxExecutorFactory =
                new InternalTransactionExecutorFactory(this.keyEncodingStrategy, this.loggerFactory, this.network);
            var vm = new ReflectionVirtualMachine(internalTxExecutorFactory, this.loggerFactory);

            var context = new SmartContractExecutionContext(
                new Block(1, TestAddress),
                new Message(
                    TestAddress,
                    TestAddress,
                    deserializedCall.Value,
                    deserializedCall.CallData.GasLimit
                    ),
                TestAddress.ToUint160(this.network),
                deserializedCall.CallData.GasPrice,
                deserializedCall.MethodParameters
                );

            var result = vm.Create(
                contractExecutionCode,
                context,
                gasMeter,
                persistentState,
                repository);

            track.Commit();

            Assert.Equal(6, BitConverter.ToInt16(track.GetStorageValue(context.Message.ContractAddress.ToUint160(this.network), Encoding.UTF8.GetBytes("EndBlock")), 0));
            Assert.Equal(TestAddress.ToUint160(this.network).ToBytes(), track.GetStorageValue(context.Message.ContractAddress.ToUint160(this.network), Encoding.UTF8.GetBytes("Owner")));
        }