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());
        }
コード例 #2
0
        public void SME_CreateContract_ConstructorFails_Refund()
        {
            SmartContractCompilationResult compilationResult = SmartContractCompiler.CompileFile("SmartContracts/ContractConstructorInvalid.cs");

            Assert.True(compilationResult.Success);
            byte[] contractCode = compilationResult.Compilation;

            SmartContractCarrier carrier = SmartContractCarrier.CreateContract(0, contractCode, 1, (Gas)10000);
            var tx = new Transaction();

            tx.AddOutput(0, new Script(carrier.Serialize()));

            ISmartContractTransactionContext transactionContext = new SmartContractTransactionContext(BlockHeight, CoinbaseAddress, MempoolFee, new uint160(2), tx);

            var executor = new Executor(this.loggerFactory,
                                        this.serializer,
                                        this.state,
                                        this.refundProcessor,
                                        this.transferProcessor,
                                        this.vm);

            ISmartContractExecutionResult result = executor.Execute(transactionContext);

            Assert.NotNull(result.Exception);
            // Base cost + constructor cost
            Assert.Equal(GasPriceList.BaseCost + 13, result.GasConsumed);
        }
コード例 #3
0
        public void SME_CreateContract_MethodParameters_ParameterTypeMismatch()
        {
            SmartContractCompilationResult compilationResult = SmartContractCompiler.CompileFile("SmartContracts/ContractMethodParameterTypeMismatch.cs");

            Assert.True(compilationResult.Success);
            byte[] contractCode = compilationResult.Compilation;

            string[] methodParameters = new string[]
            {
                string.Format("{0}#{1}", (int)SmartContractCarrierDataType.Bool, true),
            };

            var carrier = SmartContractCarrier.CreateContract(0, contractCode, 1, (Gas)10000, methodParameters);
            var tx      = new Transaction();

            tx.AddOutput(0, new Script(carrier.Serialize()));

            ISmartContractTransactionContext transactionContext = new SmartContractTransactionContext(BlockHeight, CoinbaseAddress, MempoolFee, new uint160(2), tx);

            var executor = new Executor(this.loggerFactory,
                                        this.serializer,
                                        this.state,
                                        this.refundProcessor,
                                        this.transferProcessor,
                                        this.vm);

            ISmartContractExecutionResult result = executor.Execute(transactionContext);

            Assert.NotNull(result.Exception);
            Assert.Equal(GasPriceList.BaseCost, result.GasConsumed);
        }
コード例 #4
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 carrier = SmartContractCarrier.CreateContract(1, contractExecutionCode, 1, (Gas)5000);

            var serializer = CallDataSerializer.Default;

            var callDataResult = serializer.Deserialize(carrier.Serialize());
            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 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));
        }
コード例 #6
0
        public void SmartContracts_AddToMempool_OnlyValid()
        {
            using (NodeBuilder builder = NodeBuilder.Create(this))
            {
                var stratisNodeSync = builder.CreateSmartContractPowNode();
                builder.StartAll();

                stratisNodeSync.SetDummyMinerSecret(new BitcoinSecret(new Key(), stratisNodeSync.FullNode.Network));
                stratisNodeSync.GenerateStratisWithMiner(105); // coinbase maturity = 100
                TestHelper.WaitLoop(() => stratisNodeSync.FullNode.ConsensusLoop().Tip.HashBlock == stratisNodeSync.FullNode.Chain.Tip.HashBlock);
                TestHelper.WaitLoop(() => stratisNodeSync.FullNode.GetBlockStoreTip().HashBlock == stratisNodeSync.FullNode.Chain.Tip.HashBlock);

                var block   = stratisNodeSync.FullNode.BlockStoreManager().BlockRepository.GetAsync(stratisNodeSync.FullNode.Chain.GetBlock(4).HashBlock).Result;
                var prevTrx = block.Transactions.First();
                var dest    = new BitcoinSecret(new Key(), stratisNodeSync.FullNode.Network);

                // Gas higher than allowed limit
                Transaction tx = new Transaction();
                tx.AddInput(new TxIn(new OutPoint(prevTrx.GetHash(), 0), PayToPubkeyHashTemplate.Instance.GenerateScriptPubKey(stratisNodeSync.MinerSecret.PubKey)));
                SmartContractCarrier smartContractCarrier = SmartContractCarrier.CallContract(1, new uint160(0), "Test", 1, new Gas(10_000_000));
                tx.AddOutput(new TxOut(1, new Script(smartContractCarrier.Serialize())));
                tx.Sign(stratisNodeSync.FullNode.Network, stratisNodeSync.MinerSecret, false);
                stratisNodeSync.Broadcast(tx);

                // OP_SPEND in user's tx - we can't sign this because the TransactionBuilder recognises the ScriptPubKey is invalid.
                tx = new Transaction();
                tx.AddInput(new TxIn(new OutPoint(prevTrx.GetHash(), 0), new Script(new[] { (byte)ScOpcodeType.OP_SPEND })));
                smartContractCarrier = SmartContractCarrier.CallContract(1, new uint160(0), "Test", 1, new Gas(100_000));
                tx.AddOutput(new TxOut(1, new Script(smartContractCarrier.Serialize())));
                stratisNodeSync.Broadcast(tx);

                // 2 smart contract outputs
                tx = new Transaction();
                tx.AddInput(new TxIn(new OutPoint(prevTrx.GetHash(), 0), PayToPubkeyHashTemplate.Instance.GenerateScriptPubKey(stratisNodeSync.MinerSecret.PubKey)));
                smartContractCarrier = SmartContractCarrier.CallContract(1, new uint160(0), "Test", 1, new Gas(100_000));
                tx.AddOutput(new TxOut(1, new Script(smartContractCarrier.Serialize())));
                tx.AddOutput(new TxOut(1, new Script(smartContractCarrier.Serialize())));
                tx.Sign(stratisNodeSync.FullNode.Network, stratisNodeSync.MinerSecret, false);
                stratisNodeSync.Broadcast(tx);

                // After 5 seconds (plenty of time but ideally we would have a more accurate measure) no txs in mempool. All failed validation.
                Thread.Sleep(5000);
                Assert.Empty(stratisNodeSync.CreateRPCClient().GetRawMempool());

                // Valid tx still works
                tx = new Transaction();
                tx.AddInput(new TxIn(new OutPoint(prevTrx.GetHash(), 0), PayToPubkeyHashTemplate.Instance.GenerateScriptPubKey(stratisNodeSync.MinerSecret.PubKey)));
                tx.AddOutput(new TxOut("25", dest.PubKey.Hash));
                tx.AddOutput(new TxOut("24", new Key().PubKey.Hash)); // 1 btc fee
                tx.Sign(stratisNodeSync.FullNode.Network, stratisNodeSync.MinerSecret, false);
                stratisNodeSync.Broadcast(tx);
                TestHelper.WaitLoop(() => stratisNodeSync.CreateRPCClient().GetRawMempool().Length == 1);
            }
        }
コード例 #7
0
        public void ContractExecutionResult_NoRefundDue_NoFeeAdjustment()
        {
            var contractAddress = new uint160(1);

            var carrier = SmartContractCarrier.CallContract(1, contractAddress, "ThrowException", 1, (Gas)5000);

            carrier.Sender = new uint160(2);

            (Money fee, TxOut refund) = this.refundProcessor.Process(carrier.ContractTxData, new Money(10500), carrier.Sender, (Gas)5000, false);

            Assert.Equal(10500, fee);
            Assert.Null(refund);
        }
コード例 #8
0
        public void ContractExecutionResult_OutOfGasException_NoRefundDue_NoFeeAdjustment()
        {
            var contractAddress = new uint160(1);

            var carrier = SmartContractCarrier.CallContract(1, contractAddress, "ThrowException", 1, (Gas)5000);

            carrier.Sender = new uint160(2);

            (var fee, var refunds) = this.refundProcessor.Process(carrier.ContractTxData, new Money(10500), carrier.Sender, (Gas)5000, new OutOfGasException());

            Assert.Equal(10500, fee);
            Assert.Empty(refunds);
        }
コード例 #9
0
        public void ContractExecutionResult_RefundDue_AdjustFee()
        {
            var contractAddress = new uint160(1);

            var carrier = SmartContractCarrier.CallContract(1, contractAddress, "ThrowException", 1, (Gas)5000);

            carrier.Sender = new uint160(2);

            (Money fee, TxOut refund) = this.refundProcessor.Process(carrier.ContractTxData, new Money(10500), carrier.Sender, (Gas)950, false);

            Assert.Equal(6450, fee);
            Assert.Equal(carrier.Sender.ToBytes(), refund.ScriptPubKey.GetDestination(this.network).ToBytes());
            Assert.Equal(4050, refund.Value);
        }
コード例 #10
0
        public async Task SmartContractFormatRule_MultipleOutputs_SuccessAsync()
        {
            TestRulesContext        testContext = TestRulesContextFactory.CreateAsync(this.network);
            SmartContractFormatRule rule        = testContext.CreateRule <SmartContractFormatRule>();

            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 carrier    = SmartContractCarrier.CallContract(1, 0, "TestMethod", (ulong)gasPriceSatoshis, (Gas)gasLimit);
            var serialized = carrier.Serialize();

            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);
        }
コード例 #11
0
        public void ContractExecutionResult_RefundDue_AdjustFee()
        {
            var contractAddress = new uint160(1);

            var carrier = SmartContractCarrier.CallContract(1, contractAddress, "ThrowException", 1, (Gas)5000);

            carrier.Sender = new uint160(2);

            (var fee, var refunds) = this.refundProcessor.Process(carrier, new Money(10500), (Gas)950, null);

            Assert.Equal(6450, fee);
            Assert.Single(refunds);
            Assert.Equal(carrier.Sender.ToBytes(), refunds.First().ScriptPubKey.GetDestination(this.network).ToBytes());
            Assert.Equal(4050, refunds.First().Value);
        }
コード例 #12
0
        public void SmartContract_CanSerialize_OP_CALLCONTRACT_WithoutMethodParameters()
        {
            var smartContractCarrier = SmartContractCarrier.CallContract(1, 100, "Execute", 1, (Gas)500000);

            var serializer = CallDataSerializer.Default;

            var callDataResult = serializer.Deserialize(smartContractCarrier.Serialize());
            var callData       = callDataResult.Value;

            Assert.True(callDataResult.IsSuccess);
            Assert.Equal(smartContractCarrier.ContractTxData.VmVersion, callData.VmVersion);
            Assert.Equal(smartContractCarrier.ContractTxData.OpCodeType, callData.OpCodeType);
            Assert.Equal(smartContractCarrier.ContractTxData.ContractAddress, callData.ContractAddress);
            Assert.Equal(smartContractCarrier.ContractTxData.MethodName, callData.MethodName);
            Assert.Equal(smartContractCarrier.ContractTxData.GasPrice, callData.GasPrice);
            Assert.Equal(smartContractCarrier.ContractTxData.GasLimit, callData.GasLimit);
        }
コード例 #13
0
        public void SmartContractExecutor_CallContract_Fails_ReturnFundsToSender()
        {
            //Get the contract execution code------------------------
            SmartContractCompilationResult compilationResult = SmartContractCompiler.CompileFile("SmartContracts/ThrowExceptionContract.cs");

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


            //Call smart contract and add to transaction-------------
            SmartContractCarrier carrier = SmartContractCarrier.CallContract(1, ToAddress, "ThrowException", 1, (Gas)5000);
            var   transactionCall        = new Transaction();
            TxOut callTxOut = transactionCall.AddOutput(0, new Script(carrier.Serialize()));

            callTxOut.Value = 100;
            //-------------------------------------------------------

            //Deserialize the contract from the transaction----------
            //and get the module definition
            //-------------------------------------------------------
            this.state.SetCode(new uint160(1), contractExecutionCode);
            this.state.SetContractType(new uint160(1), "ThrowExceptionContract");

            ISmartContractTransactionContext transactionContext = new SmartContractTransactionContext(BlockHeight, CoinbaseAddress, MempoolFee, SenderAddress, transactionCall);

            var executor = new Executor(this.loggerFactory,
                                        this.serializer,
                                        this.state,
                                        this.refundProcessor,
                                        this.transferProcessor,
                                        this.vm);

            ISmartContractExecutionResult result = executor.Execute(transactionContext);

            Assert.True(result.Revert);
            Assert.NotNull(result.InternalTransaction);
            Assert.Single(result.InternalTransaction.Inputs);
            Assert.Single(result.InternalTransaction.Outputs);

            var actualSender = new uint160(result.InternalTransaction.Outputs[0].ScriptPubKey.GetDestination(this.network).ToBytes());

            Assert.Equal(SenderAddress, actualSender);
            Assert.Equal(100, result.InternalTransaction.Outputs[0].Value);
        }
コード例 #14
0
        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);
        }
コード例 #15
0
        public void SmartContractFormatRule_FailureAsync()
        {
            TestRulesContext        testContext = TestRulesContextFactory.CreateAsync(this.network);
            SmartContractFormatRule rule        = testContext.CreateRule <SmartContractFormatRule>();

            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 carrier    = SmartContractCarrier.CallContract(1, 0, "TestMethod", (ulong)gasPriceSatoshis, (Gas)higherGasLimit);
            var serialized = carrier.Serialize();

            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>
            {
                transaction
            };

            Task <ConsensusErrorException> error = Assert.ThrowsAsync <ConsensusErrorException>(async() => await rule.RunAsync(context));
        }
        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);
        }
コード例 #17
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>()));
        }
コード例 #19
0
        public void SmartContractExecutor_CallContract_DoesNotExist_Refund()
        {
            SmartContractCarrier carrier = SmartContractCarrier.CallContract(1, ToAddress, "TestMethod", 1, (Gas)10000);

            var   transaction = new Transaction();
            TxOut txOut       = transaction.AddOutput(0, new Script(carrier.Serialize()));

            txOut.Value = 100;

            ISmartContractTransactionContext transactionContext = new SmartContractTransactionContext(BlockHeight, CoinbaseAddress, MempoolFee, new uint160(2), transaction);

            var executor = new Executor(this.loggerFactory,
                                        this.serializer,
                                        this.state,
                                        this.refundProcessor,
                                        this.transferProcessor,
                                        this.vm);

            ISmartContractExecutionResult result = executor.Execute(transactionContext);

            Assert.IsType <SmartContractDoesNotExistException>(result.Exception);
        }
コード例 #20
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")));
        }
コード例 #21
0
        public void Execute_InterContractCall_InfiniteLoop_AllGasConsumed()
        {
            // Create contract 1

            //Get the contract execution code------------------------
            SmartContractCompilationResult compilationResult = SmartContractCompiler.CompileFile("SmartContracts/InfiniteLoop.cs");

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

            // Add contract creation code to transaction-------------
            var   carrier     = SmartContractCarrier.CreateContract(1, contractExecutionCode, 1, (Gas)3500);
            var   transaction = new Transaction();
            TxOut txOut       = transaction.AddOutput(0, new Script(carrier.Serialize()));

            txOut.Value = 100;
            //-------------------------------------------------------

            //Deserialize the contract from the transaction----------
            //and get the module definition
            ISmartContractTransactionContext transactionContext = new SmartContractTransactionContext(BlockHeight, CoinbaseAddress, MempoolFee, SenderAddress, transaction);

            var executor = new Executor(this.loggerFactory,
                                        this.serializer,
                                        this.state,
                                        this.refundProcessor,
                                        this.transferProcessor,
                                        this.vm);

            ISmartContractExecutionResult result = executor.Execute(transactionContext);
            uint160 address1 = result.NewContractAddress;

            //-------------------------------------------------------


            // Create contract 2

            //Get the contract execution code------------------------
            compilationResult = SmartContractCompiler.CompileFile("SmartContracts/CallInfiniteLoopContract.cs");
            Assert.True(compilationResult.Success);

            contractExecutionCode = compilationResult.Compilation;
            //-------------------------------------------------------

            //Call smart contract and add to transaction-------------
            carrier     = SmartContractCarrier.CreateContract(1, contractExecutionCode, 1, (Gas)3500);
            transaction = new Transaction();
            txOut       = transaction.AddOutput(0, new Script(carrier.Serialize()));
            txOut.Value = 100;
            //-------------------------------------------------------

            //Deserialize the contract from the transaction----------
            //and get the module definition
            //-------------------------------------------------------

            transactionContext = new SmartContractTransactionContext(BlockHeight, CoinbaseAddress, MempoolFee, SenderAddress, transaction);

            result = executor.Execute(transactionContext);

            uint160 address2 = result.NewContractAddress;

            // Invoke infinite loop

            var gasLimit = (Gas)1000000;

            string[] parameters =
            {
                string.Format("{0}#{1}", (int)SmartContractCarrierDataType.String, address1.ToAddress(this.network).Value),
            };

            carrier     = SmartContractCarrier.CallContract(1, address2, "CallInfiniteLoop", 1, gasLimit, parameters);
            transaction = new Transaction();
            txOut       = transaction.AddOutput(0, new Script(carrier.Serialize()));
            txOut.Value = 100;

            transactionContext = new SmartContractTransactionContext(BlockHeight, CoinbaseAddress, MempoolFee, SenderAddress, transaction);

            var callExecutor = new Executor(this.loggerFactory,
                                            this.serializer,
                                            this.state,
                                            this.refundProcessor,
                                            this.transferProcessor,
                                            this.vm);

            // Because our contract contains an infinite loop, we want to kill our test after
            // some amount of time without achieving a result. 3 seconds is an arbitrarily high enough timeout
            // for the method body to have finished execution while minimising the amount of time we spend
            // running tests
            // If you're running with the debugger on this will obviously be a source of failures
            result = RunWithTimeout(3, () => callExecutor.Execute(transactionContext));

            Assert.IsType <OutOfGasException>(result.Exception);
            Assert.Equal(gasLimit, result.GasConsumed);
        }
コード例 #22
0
        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 serializer = CallDataSerializer.Default;

            var callDataResult = serializer.Deserialize(carrier.Serialize());
            var callData       = callDataResult.Value;

            Assert.True(callDataResult.IsSuccess);

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

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

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

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

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

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

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

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

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

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

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

            Assert.NotNull(callData.MethodParameters[11]);
            Assert.Equal(carrier.MethodParameters[11], callData.MethodParameters[11]);
        }
コード例 #23
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]
                    }
                }"
                );

            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 serializer = CallDataSerializer.Default;

            var callDataResult = serializer.Deserialize(carrier.Serialize());
            var callData       = callDataResult.Value;

            Assert.True(callDataResult.IsSuccess);
            Assert.Equal(carrier.ContractTxData.VmVersion, callData.VmVersion);
            Assert.Equal(carrier.ContractTxData.OpCodeType, callData.OpCodeType);
            Assert.Equal(carrier.ContractTxData.ContractExecutionCode, callData.ContractExecutionCode);
            Assert.Equal(6, callData.MethodParameters.Length);

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

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

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

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

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

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

            Assert.Equal(carrier.ContractTxData.GasPrice, callData.GasPrice);
            Assert.Equal(carrier.ContractTxData.GasLimit, callData.GasLimit);
        }
コード例 #24
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]
                    }
                }"
                );

            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);
        }
コード例 #25
0
        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]);
        }
コード例 #26
0
        private BuildCallContractTransactionResponse BuildCallTx(BuildCallContractTransactionRequest request)
        {
            this.logger.LogTrace(request.ToString());

            AddressBalance addressBalance = this.walletManager.GetAddressBalance(request.Sender);

            if (addressBalance.AmountConfirmed == 0)
            {
                return(BuildCallContractTransactionResponse.Failed($"The 'Sender' address you're trying to spend from doesn't have a confirmed balance. Current unconfirmed balance: {addressBalance.AmountUnconfirmed}. Please check the 'Sender' address."));
            }

            var selectedInputs = new List <OutPoint>();

            selectedInputs = this.walletManager.GetSpendableTransactionsInWallet(request.WalletName, MinConfirmationsAllChecks).Where(x => x.Address.Address == request.Sender).Select(x => x.ToOutPoint()).ToList();

            ulong   gasPrice       = ulong.Parse(request.GasPrice);
            ulong   gasLimit       = ulong.Parse(request.GasLimit);
            uint160 addressNumeric = new Address(request.ContractAddress).ToUint160(this.network);

            SmartContractCarrier carrier;

            if (request.Parameters != null && request.Parameters.Any())
            {
                carrier = SmartContractCarrier.CallContract(ReflectionVirtualMachine.VmVersion, addressNumeric, request.MethodName, gasPrice, new Gas(gasLimit), request.Parameters);
            }
            else
            {
                carrier = SmartContractCarrier.CallContract(ReflectionVirtualMachine.VmVersion, addressNumeric, request.MethodName, gasPrice, new Gas(gasLimit));
            }

            HdAddress senderAddress = null;

            if (!string.IsNullOrWhiteSpace(request.Sender))
            {
                Features.Wallet.Wallet wallet = this.walletManager.GetWallet(request.WalletName);
                HdAccount account             = wallet.GetAccountByCoinType(request.AccountName, this.coinType);
                senderAddress = account.GetCombinedAddresses().FirstOrDefault(x => x.Address == request.Sender);
            }

            ulong totalFee = (gasPrice * gasLimit) + Money.Parse(request.FeeAmount);
            var   context  = new TransactionBuildContext(this.network)
            {
                AccountReference = new WalletAccountReference(request.WalletName, request.AccountName),
                TransactionFee   = totalFee,
                ChangeAddress    = senderAddress,
                SelectedInputs   = selectedInputs,
                MinConfirmations = MinConfirmationsAllChecks,
                WalletPassword   = request.Password,
                Recipients       = new[] { new Recipient {
                                               Amount = request.Amount, ScriptPubKey = new Script(carrier.Serialize())
                                           } }.ToList()
            };

            try
            {
                Transaction transaction = this.walletTransactionHandler.BuildTransaction(context);
                return(BuildCallContractTransactionResponse.Succeeded(request.MethodName, transaction, context.TransactionFee));
            }
            catch (Exception exception)
            {
                return(BuildCallContractTransactionResponse.Failed(exception.Message));
            }
        }
コード例 #27
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")));
        }
コード例 #28
0
        public void SendAndReceiveSmartContractTransactions()
        {
            using (NodeBuilder builder = NodeBuilder.Create(this))
            {
                CoreNode scSender   = builder.CreateSmartContractPowNode();
                CoreNode scReceiver = builder.CreateSmartContractPowNode();

                builder.StartAll();

                scSender.NotInIBD();
                scReceiver.NotInIBD();

                scSender.FullNode.WalletManager().CreateWallet(Password, WalletName);
                scReceiver.FullNode.WalletManager().CreateWallet(Password, WalletName);
                HdAddress addr = scSender.FullNode.WalletManager().GetUnusedAddress(new WalletAccountReference(WalletName, AccountName));
                Features.Wallet.Wallet wallet = scSender.FullNode.WalletManager().GetWalletByName(WalletName);
                Key key = wallet.GetExtendedPrivateKeyForAddress(Password, addr).PrivateKey;

                scSender.SetDummyMinerSecret(new BitcoinSecret(key, scSender.FullNode.Network));
                var maturity = (int)scSender.FullNode.Network.Consensus.CoinbaseMaturity;
                scSender.GenerateStratisWithMiner(maturity + 5);

                // Wait for block repo for block sync to work.
                TestHelper.WaitLoop(() => TestHelper.IsNodeSynced(scSender));

                // The mining should add coins to the wallet.
                var total = scSender.FullNode.WalletManager().GetSpendableTransactionsInWallet(WalletName).Sum(s => s.Transaction.Amount);
                Assert.Equal(Money.COIN * (maturity + 5) * 50, total);

                // Create a token contract
                ulong gasPrice  = 1;
                int   vmVersion = 1;
                Gas   gasLimit  = (Gas)2000;
                SmartContractCompilationResult compilationResult = SmartContractCompiler.CompileFile("SmartContracts/TransferTest.cs");
                Assert.True(compilationResult.Success);

                var contractCarrier = SmartContractCarrier.CreateContract(vmVersion, compilationResult.Compilation, gasPrice, gasLimit);

                var contractCreateScript = new Script(contractCarrier.Serialize());
                var txBuildContext       = new TransactionBuildContext(scSender.FullNode.Network)
                {
                    AccountReference = new WalletAccountReference(WalletName, AccountName),
                    MinConfirmations = maturity,
                    FeeType          = FeeType.High,
                    WalletPassword   = Password,
                    Recipients       = new[] { new Recipient {
                                                   Amount = 0, ScriptPubKey = contractCreateScript
                                               } }.ToList()
                };

                Transaction transferContractTransaction = (scSender.FullNode.NodeService <IWalletTransactionHandler>() as SmartContractWalletTransactionHandler).BuildTransaction(txBuildContext);

                // Broadcast the token transaction to the network
                scSender.FullNode.NodeService <IBroadcasterManager>().BroadcastTransactionAsync(transferContractTransaction);

                // Wait for the token transaction to be picked up by the mempool
                TestHelper.WaitLoop(() => scSender.CreateRPCClient().GetRawMempool().Length > 0);

                // Mine the token transaction and wait for it sync
                scSender.GenerateStratisWithMiner(1);
                TestHelper.WaitLoop(() => TestHelper.IsNodeSynced(scSender));

                // Sync to the receiver node
                scSender.CreateRPCClient().AddNode(scReceiver.Endpoint, true);
                TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(scReceiver, scSender));

                // Ensure that boths nodes has the contract
                ContractStateRepositoryRoot senderState      = scSender.FullNode.NodeService <ContractStateRepositoryRoot>();
                ContractStateRepositoryRoot receiverState    = scReceiver.FullNode.NodeService <ContractStateRepositoryRoot>();
                IAddressGenerator           addressGenerator = scSender.FullNode.NodeService <IAddressGenerator>();

                uint160 tokenContractAddress = addressGenerator.GenerateAddress(transferContractTransaction.GetHash(), 0);
                Assert.NotNull(senderState.GetCode(tokenContractAddress));
                Assert.NotNull(receiverState.GetCode(tokenContractAddress));
                scSender.FullNode.MempoolManager().Clear();

                // Create a transfer token contract
                compilationResult = SmartContractCompiler.CompileFile("SmartContracts/TransferTest.cs");
                Assert.True(compilationResult.Success);
                contractCarrier      = SmartContractCarrier.CreateContract(vmVersion, compilationResult.Compilation, gasPrice, gasLimit);
                contractCreateScript = new Script(contractCarrier.Serialize());
                txBuildContext       = new TransactionBuildContext(scSender.FullNode.Network)
                {
                    AccountReference = new WalletAccountReference(WalletName, AccountName),
                    MinConfirmations = maturity,
                    FeeType          = FeeType.High,
                    WalletPassword   = Password,
                    Recipients       = new[] { new Recipient {
                                                   Amount = 0, ScriptPubKey = contractCreateScript
                                               } }.ToList()
                };

                // Broadcast the token transaction to the network
                transferContractTransaction = (scSender.FullNode.NodeService <IWalletTransactionHandler>() as SmartContractWalletTransactionHandler).BuildTransaction(txBuildContext);
                scSender.FullNode.NodeService <IBroadcasterManager>().BroadcastTransactionAsync(transferContractTransaction);

                // Wait for the token transaction to be picked up by the mempool
                TestHelper.WaitLoop(() => scSender.CreateRPCClient().GetRawMempool().Length > 0);
                scSender.GenerateStratisWithMiner(1);

                // Ensure the node is synced
                TestHelper.WaitLoop(() => TestHelper.IsNodeSynced(scSender));

                // Ensure both nodes are synced with each other
                TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(scReceiver, scSender));

                // Ensure that boths nodes has the contract
                senderState          = scSender.FullNode.NodeService <ContractStateRepositoryRoot>();
                receiverState        = scReceiver.FullNode.NodeService <ContractStateRepositoryRoot>();
                tokenContractAddress = addressGenerator.GenerateAddress(transferContractTransaction.GetHash(), 0);
                Assert.NotNull(senderState.GetCode(tokenContractAddress));
                Assert.NotNull(receiverState.GetCode(tokenContractAddress));
                scSender.FullNode.MempoolManager().Clear();

                // Create a call contract transaction which will transfer funds
                contractCarrier = SmartContractCarrier.CallContract(1, tokenContractAddress, "Test", gasPrice, gasLimit);
                Script contractCallScript = new Script(contractCarrier.Serialize());
                txBuildContext = new TransactionBuildContext(scSender.FullNode.Network)
                {
                    AccountReference = new WalletAccountReference(WalletName, AccountName),
                    MinConfirmations = maturity,
                    FeeType          = FeeType.High,
                    WalletPassword   = Password,
                    Recipients       = new[] { new Recipient {
                                                   Amount = 1000, ScriptPubKey = contractCallScript
                                               } }.ToList()
                };

                // Broadcast the token transaction to the network
                transferContractTransaction = (scSender.FullNode.NodeService <IWalletTransactionHandler>() as SmartContractWalletTransactionHandler).BuildTransaction(txBuildContext);
                scSender.FullNode.NodeService <IBroadcasterManager>().BroadcastTransactionAsync(transferContractTransaction);
                TestHelper.WaitLoop(() => scSender.CreateRPCClient().GetRawMempool().Length > 0);

                // Mine the transaction
                scSender.GenerateStratisWithMiner(1);

                // Ensure the nodes are synced
                TestHelper.WaitLoop(() => TestHelper.IsNodeSynced(scSender));
                TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(scReceiver, scSender));

                // The balance should now reflect the transfer
                Assert.Equal((ulong)900, senderState.GetCurrentBalance(tokenContractAddress));
            }
        }
コード例 #29
0
        public void SendAndReceiveSmartContractTransactionsOnPosNetwork()
        {
            using (NodeBuilder builder = NodeBuilder.Create(this))
            {
                CoreNode scSender   = builder.CreateSmartContractPosNode();
                CoreNode scReceiver = builder.CreateSmartContractPosNode();

                builder.StartAll();

                scSender.NotInIBD();
                scReceiver.NotInIBD();

                scSender.FullNode.WalletManager().CreateWallet(Password, WalletName, Passphrase);
                scReceiver.FullNode.WalletManager().CreateWallet(Password, WalletName, Passphrase);

                var       maturity      = (int)scSender.FullNode.Network.Consensus.CoinbaseMaturity;
                HdAddress senderAddress = TestHelper.MineBlocks(scSender, WalletName, Password, AccountName, maturity + 5).AddressUsed;

                // Wait for block repo for block sync to work.
                TestHelper.WaitLoop(() => TestHelper.IsNodeSynced(scSender));

                // The mining should add coins to the wallet.
                var total = scSender.FullNode.WalletManager().GetSpendableTransactionsInWallet(WalletName).Sum(s => s.Transaction.Amount);
                Assert.Equal(Money.COIN * 6 * 50, total);

                // Create a token contract
                ulong gasPrice  = 1;
                int   vmVersion = 1;
                Gas   gasLimit  = (Gas)5000;
                SmartContractCompilationResult compilationResult = SmartContractCompiler.CompileFile("SmartContracts/TransferTestPos.cs");
                Assert.True(compilationResult.Success);

                var contractCarrier = SmartContractCarrier.CreateContract(vmVersion, compilationResult.Compilation, gasPrice, gasLimit);

                var contractCreateScript = new Script(contractCarrier.Serialize());
                var txBuildContext       = new TransactionBuildContext(scSender.FullNode.Network)
                {
                    AccountReference = new WalletAccountReference(WalletName, AccountName),
                    ChangeAddress    = senderAddress,
                    MinConfirmations = maturity,
                    FeeType          = FeeType.High,
                    WalletPassword   = Password,
                    Recipients       = new[] { new Recipient {
                                                   Amount = 0, ScriptPubKey = contractCreateScript
                                               } }.ToList()
                };

                // Build the transfer contract transaction
                var transferContractTransaction = BuildTransferContractTransaction(scSender, txBuildContext);

                // Add the smart contract transaction to the mempool to be mined.
                scSender.AddToStratisMempool(transferContractTransaction);

                // Ensure the smart contract transaction is in the mempool.
                TestHelper.WaitLoop(() => scSender.CreateRPCClient().GetRawMempool().Length > 0);

                // Mine the token transaction and wait for it sync
                scSender.GenerateStratisWithMiner(1);
                TestHelper.WaitLoop(() => TestHelper.IsNodeSynced(scSender));

                // Sync to the receiver node
                scSender.CreateRPCClient().AddNode(scReceiver.Endpoint, true);
                TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(scReceiver, scSender));

                // Ensure that boths nodes has the contract
                IContractStateRoot senderState      = scSender.FullNode.NodeService <IContractStateRoot>();
                IContractStateRoot receiverState    = scReceiver.FullNode.NodeService <IContractStateRoot>();
                IAddressGenerator  addressGenerator = scSender.FullNode.NodeService <IAddressGenerator>();

                uint160 tokenContractAddress = addressGenerator.GenerateAddress(transferContractTransaction.GetHash(), 0);
                Assert.NotNull(senderState.GetCode(tokenContractAddress));
                Assert.NotNull(receiverState.GetCode(tokenContractAddress));
                scSender.FullNode.MempoolManager().Clear();

                // Create a transfer token contract
                compilationResult = SmartContractCompiler.CompileFile("SmartContracts/TransferTestPos.cs");
                Assert.True(compilationResult.Success);
                contractCarrier      = SmartContractCarrier.CreateContract(vmVersion, compilationResult.Compilation, gasPrice, gasLimit);
                contractCreateScript = new Script(contractCarrier.Serialize());
                txBuildContext       = new TransactionBuildContext(scSender.FullNode.Network)
                {
                    AccountReference = new WalletAccountReference(WalletName, AccountName),
                    ChangeAddress    = senderAddress,
                    MinConfirmations = maturity,
                    FeeType          = FeeType.High,
                    WalletPassword   = Password,
                    Recipients       = new[] { new Recipient {
                                                   Amount = 0, ScriptPubKey = contractCreateScript
                                               } }.ToList()
                };

                // Build the transfer contract transaction
                transferContractTransaction = BuildTransferContractTransaction(scSender, txBuildContext);

                // Add the smart contract transaction to the mempool to be mined.
                scSender.AddToStratisMempool(transferContractTransaction);

                // Wait for the token transaction to be picked up by the mempool
                TestHelper.WaitLoop(() => scSender.CreateRPCClient().GetRawMempool().Length > 0);
                scSender.GenerateStratisWithMiner(1);

                // Ensure the node is synced
                TestHelper.WaitLoop(() => TestHelper.IsNodeSynced(scSender));

                // Ensure both nodes are synced with each other
                TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(scReceiver, scSender));

                tokenContractAddress = addressGenerator.GenerateAddress(transferContractTransaction.GetHash(), 0); // nonce is 0 for user contract creation.
                Assert.NotNull(senderState.GetCode(tokenContractAddress));
                Assert.NotNull(receiverState.GetCode(tokenContractAddress));
                scSender.FullNode.MempoolManager().Clear();

                // Create a call contract transaction which will transfer funds
                contractCarrier = SmartContractCarrier.CallContract(1, tokenContractAddress, "Test", gasPrice, gasLimit);
                Script contractCallScript = new Script(contractCarrier.Serialize());
                txBuildContext = new TransactionBuildContext(scSender.FullNode.Network)
                {
                    AccountReference = new WalletAccountReference(WalletName, AccountName),
                    ChangeAddress    = senderAddress,
                    MinConfirmations = maturity,
                    FeeType          = FeeType.High,
                    WalletPassword   = Password,
                    Recipients       = new[] { new Recipient {
                                                   Amount = 1000, ScriptPubKey = contractCallScript
                                               } }.ToList()
                };

                // Build the transfer contract transaction
                var callContractTransaction = BuildTransferContractTransaction(scSender, txBuildContext);

                // Add the smart contract transaction to the mempool to be mined.
                scSender.AddToStratisMempool(callContractTransaction);

                // Wait for the token transaction to be picked up by the mempool
                TestHelper.WaitLoop(() => scSender.CreateRPCClient().GetRawMempool().Length > 0);
                scSender.GenerateStratisWithMiner(1);

                // Ensure the nodes are synced
                TestHelper.WaitLoop(() => TestHelper.IsNodeSynced(scSender));
                TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(scReceiver, scSender));

                // The balance should now reflect the transfer
                Assert.Equal((ulong)900, senderState.GetCurrentBalance(tokenContractAddress));
            }
        }