protected PoAMockChainFixture(int nodeNum)
        {
            var network = new SmartContractsPoARegTest();

            // TODO: The PoA tests seem to use the same network class to do sets of tests with different rule requirements (signed/unsigned). Need to normalise it to avoid this hack.
            network.Consensus.MempoolRules.Remove(typeof(AllowedCodeHashLogicMempoolRule));

            this.builder = SmartContractNodeBuilder.Create(this);

            CoreNode factory(int nodeIndex) => this.builder.CreateSmartContractPoANode(network, nodeIndex).Start();

            PoAMockChain mockChain = new PoAMockChain(nodeNum, factory).Build();

            this.Chain = mockChain;
            MockChainNode node1 = this.Chain.Nodes[0];
            MockChainNode node2 = this.Chain.Nodes[1];

            // Get premine
            mockChain.MineBlocks(10);

            // Send half to other from whoever received premine
            if ((long)node1.WalletSpendableBalance == node1.CoreNode.FullNode.Network.Consensus.PremineReward.Satoshi)
            {
                this.PayHalfPremine(node1, node2);
            }
            else
            {
                this.PayHalfPremine(node2, node1);
            }
        }
        protected PoAMockChainFixture(int nodeNum)
        {
            var network = new SmartContractsPoARegTest();

            this.builder = SmartContractNodeBuilder.Create(this);

            CoreNode factory(int nodeIndex) => this.builder.CreateSmartContractPoANode(network, nodeIndex).Start();

            PoAMockChain mockChain = new PoAMockChain(2, factory).Build();

            this.Chain = mockChain;
            MockChainNode node1 = this.Chain.Nodes[0];
            MockChainNode node2 = this.Chain.Nodes[1];

            // Get premine
            mockChain.MineBlocks(10);

            // Send half to other from whoever received premine
            if ((long)node1.WalletSpendableBalance == node1.CoreNode.FullNode.Network.Consensus.PremineReward.Satoshi)
            {
                this.PayHalfPremine(node1, node2);
            }
            else
            {
                this.PayHalfPremine(node2, node1);
            }
        }
예제 #3
0
        public SmartContractRPCTests()
        {
            var network = new SmartContractsPoARegTest();

            this.network     = network;
            this.builder     = SmartContractNodeBuilder.Create(this);
            this.nodeFactory = (nodeIndex) => this.builder.CreateSmartContractPoANode(network, nodeIndex).Start();
            this.methodParameterStringSerializer = new MethodParameterStringSerializer(this.network);
        }
예제 #4
0
        public TestChain()
        {
            var network = new SmartContractsPoARegTest();

            this.network         = network;
            this.builder         = SmartContractNodeBuilder.Create(this);
            this.nodeFactory     = (nodeIndex) => this.builder.CreateSmartContractPoANode(network, nodeIndex).Start();
            this.chain           = new PoAMockChain(2, nodeFactory, SharedWalletMnemonic);
            this.paramSerializer = new MethodParameterStringSerializer(network); // TODO: Inject
        }
예제 #5
0
        public PoWMockChain(int numberOfNodes)
        {
            this.builder = SmartContractNodeBuilder.Create(this);
            this.nodes   = new MockChainNode[numberOfNodes];

            for (int nodeIndex = 0; nodeIndex < numberOfNodes; nodeIndex++)
            {
                CoreNode node = this.builder.CreateSmartContractPowNode().Start();

                for (int j = 0; j < nodeIndex; j++)
                {
                    MockChainNode otherNode = this.nodes[j];
                    TestHelper.Connect(node, otherNode.CoreNode);
                }

                this.nodes[nodeIndex] = new MockChainNode(node, this);
            }
        }
예제 #6
0
        public PoAMockChain(int numNodes)
        {
            this.builder = SmartContractNodeBuilder.Create(this);
            this.nodes   = new MockChainNode[numNodes];
            var network = new SmartContractsPoARegTest();

            this.Network = network;
            for (int i = 0; i < numNodes; i++)
            {
                CoreNode node = this.builder.CreateSmartContractPoANode(network.FederationKeys[i]).Start();

                for (int j = 0; j < i; j++)
                {
                    MockChainNode otherNode = this.nodes[j];
                    TestHelper.Connect(node, otherNode.CoreNode);
                    TestHelper.Connect(otherNode.CoreNode, node);
                }

                this.nodes[i] = new MockChainNode(node, this);
            }
        }
        public PoWMockChain(int numNodes)
        {
            this.Network = new SmartContractsRegTest(); // TODO: Make this configurable.

            this.builder = SmartContractNodeBuilder.Create(this);
            this.nodes   = new MockChainNode[numNodes];

            for (int i = 0; i < numNodes; i++)
            {
                CoreNode node = this.builder.CreateSmartContractPowNode().Start();

                // Add other nodes
                for (int j = 0; j < i; j++)
                {
                    MockChainNode otherNode = this.nodes[j];
                    TestHelper.Connect(node, otherNode.CoreNode);
                    TestHelper.Connect(otherNode.CoreNode, node);
                }

                this.nodes[i] = new MockChainNode(node, this);
            }
        }
        public void NodesCanConnectToEachOthers()
        {
            using (SmartContractNodeBuilder builder = SmartContractNodeBuilder.Create(this))
            {
                var node1 = builder.CreateSmartContractPowNode().Start();
                var node2 = builder.CreateSmartContractPowNode().Start();

                Assert.Empty(node1.FullNode.ConnectionManager.ConnectedPeers);
                Assert.Empty(node2.FullNode.ConnectionManager.ConnectedPeers);

                TestHelper.Connect(node1, node2);
                Assert.Single(node1.FullNode.ConnectionManager.ConnectedPeers);
                Assert.Single(node2.FullNode.ConnectionManager.ConnectedPeers);

                var behavior = node1.FullNode.ConnectionManager.ConnectedPeers.First().Behaviors.OfType <IConnectionManagerBehavior>().FirstOrDefault();
                Assert.False(behavior.AttachedPeer.Inbound);
                Assert.True(behavior.OneTry);
                behavior = node2.FullNode.ConnectionManager.ConnectedPeers.First().Behaviors.OfType <IConnectionManagerBehavior>().FirstOrDefault();
                Assert.True(behavior.AttachedPeer.Inbound);
                Assert.False(behavior.OneTry);
            }
        }
예제 #9
0
        public void SmartContractsController_Builds_Transaction_With_Minimum_Inputs()
        {
            using (SmartContractNodeBuilder builder = SmartContractNodeBuilder.Create(this))
            {
                CoreNode scSender = builder.CreateSmartContractPowNode().WithWallet().Start();

                var maturity = (int)scSender.FullNode.Network.Consensus.CoinbaseMaturity;

                HdAddress addr = TestHelper.MineBlocks(scSender, maturity + 5).AddressUsed;

                int spendableBlocks = GetSpendableBlocks(maturity + 5, maturity);
                var total           = scSender.FullNode.WalletManager().GetSpendableTransactionsInWallet(WalletName).Sum(s => s.Transaction.Amount);
                Assert.Equal(Money.COIN * spendableBlocks * 50, total);

                SmartContractsController senderSmartContractsController = scSender.FullNode.NodeService <SmartContractsController>();

                SmartContractWalletController senderWalletController = scSender.FullNode.NodeService <SmartContractWalletController>();
                ContractCompilationResult     compilationResult      = ContractCompiler.CompileFile("SmartContracts/StorageDemo.cs");
                Assert.True(compilationResult.Success);

                var buildRequest = new BuildCreateContractTransactionRequest
                {
                    AccountName  = AccountName,
                    GasLimit     = 10_000,
                    GasPrice     = 1,
                    ContractCode = compilationResult.Compilation.ToHexString(),
                    FeeAmount    = "0.001",
                    Password     = Password,
                    WalletName   = WalletName,
                    Sender       = addr.Address
                };

                JsonResult result      = (JsonResult)senderSmartContractsController.BuildCreateSmartContractTransaction(buildRequest);
                var        response    = (BuildCreateContractTransactionResponse)result.Value;
                var        transaction = scSender.FullNode.Network.CreateTransaction(response.Hex);
                Assert.Single(transaction.Inputs);
            }
        }
        public void SmartContracts_AddToMempool_Success()
        {
            using (SmartContractNodeBuilder builder = SmartContractNodeBuilder.Create(this))
            {
                var stratisNodeSync = builder.CreateSmartContractPowNode().WithWallet().Start();

                TestHelper.MineBlocks(stratisNodeSync, 105); // coinbase maturity = 100

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

                var tx = stratisNodeSync.FullNode.Network.CreateTransaction();
                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);
            }
        }
예제 #11
0
        public void SendAndReceiveSmartContractTransactionsUsingController()
        {
            using (SmartContractNodeBuilder builder = SmartContractNodeBuilder.Create(this))
            {
                CoreNode scSender   = builder.CreateSmartContractPowNode().WithWallet().Start();
                CoreNode scReceiver = builder.CreateSmartContractPowNode().WithWallet().Start();

                int maturity = (int)scReceiver.FullNode.Network.Consensus.CoinbaseMaturity;

                HdAddress addr = TestHelper.MineBlocks(scSender, maturity + 5).AddressUsed;

                int spendable = GetSpendableBlocks(maturity + 5, maturity);
                var total     = scSender.FullNode.WalletManager().GetSpendableTransactionsInWallet(WalletName).Sum(s => s.Transaction.Amount);
                Assert.Equal(Money.COIN * spendable * 50, total);

                SmartContractsController      senderSmartContractsController = scSender.FullNode.NodeService <SmartContractsController>();
                SmartContractWalletController senderWalletController         = scSender.FullNode.NodeService <SmartContractWalletController>();
                ContractCompilationResult     compilationResult = ContractCompiler.CompileFile("SmartContracts/StorageDemo.cs");
                Assert.True(compilationResult.Success);

                Gas gasLimit = (Gas)(SmartContractFormatRule.GasLimitMaximum / 2);

                var buildRequest = new BuildCreateContractTransactionRequest
                {
                    AccountName  = AccountName,
                    GasLimit     = gasLimit,
                    GasPrice     = SmartContractMempoolValidator.MinGasPrice,
                    ContractCode = compilationResult.Compilation.ToHexString(),
                    FeeAmount    = "0.001",
                    Password     = Password,
                    WalletName   = WalletName,
                    Sender       = addr.Address
                };

                JsonResult result   = (JsonResult)senderSmartContractsController.BuildCreateSmartContractTransaction(buildRequest);
                var        response = (BuildCreateContractTransactionResponse)result.Value;
                TestHelper.Connect(scSender, scReceiver);

                SmartContractSharedSteps.SendTransaction(scSender, scReceiver, senderWalletController, response.Hex);
                TestHelper.MineBlocks(scReceiver, 2);
                TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(scReceiver, scSender));

                // Check receipt was stored and can be retrieved.
                var receiptResponse = (ReceiptResponse)((JsonResult)senderSmartContractsController.GetReceipt(response.TransactionId.ToString())).Value;
                Assert.True(receiptResponse.Success);
                Assert.Equal(response.NewContractAddress, receiptResponse.NewContractAddress);
                Assert.Null(receiptResponse.To);
                Assert.Equal(addr.Address, receiptResponse.From);

                string storageRequestResult = (string)((JsonResult)senderSmartContractsController.GetStorage(new GetStorageRequest
                {
                    ContractAddress = response.NewContractAddress.ToString(),
                    StorageKey = "TestSave",
                    DataType = MethodParameterDataType.String
                })).Value;
                Assert.Equal("Hello, smart contract world!", storageRequestResult);

                string ownerRequestResult = (string)((JsonResult)senderSmartContractsController.GetStorage(new GetStorageRequest
                {
                    ContractAddress = response.NewContractAddress.ToString(),
                    StorageKey = "Owner",
                    DataType = MethodParameterDataType.Address
                })).Value;
                Assert.NotEmpty(ownerRequestResult);

                string counterRequestResult = (string)((JsonResult)senderSmartContractsController.GetStorage(new GetStorageRequest
                {
                    ContractAddress = response.NewContractAddress.ToString(),
                    StorageKey = "Counter",
                    DataType = MethodParameterDataType.Int
                })).Value;
                Assert.Equal("12345", counterRequestResult);

                var callRequest = new BuildCallContractTransactionRequest
                {
                    AccountName     = AccountName,
                    GasLimit        = gasLimit,
                    GasPrice        = SmartContractMempoolValidator.MinGasPrice,
                    Amount          = "0",
                    MethodName      = "Increment",
                    ContractAddress = response.NewContractAddress,
                    FeeAmount       = "0.001",
                    Password        = Password,
                    WalletName      = WalletName,
                    Sender          = addr.Address
                };
                result = (JsonResult)senderSmartContractsController.BuildCallSmartContractTransaction(callRequest);
                var callResponse = (BuildCallContractTransactionResponse)result.Value;

                SmartContractSharedSteps.SendTransaction(scSender, scReceiver, senderWalletController, callResponse.Hex);
                TestHelper.MineBlocks(scReceiver, 2);
                TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(scReceiver, scSender));

                counterRequestResult = (string)((JsonResult)senderSmartContractsController.GetStorage(new GetStorageRequest
                {
                    ContractAddress = response.NewContractAddress.ToString(),
                    StorageKey = "Counter",
                    DataType = MethodParameterDataType.Int
                })).Value;
                Assert.Equal("12346", counterRequestResult);

                // Check receipt was stored and can be retrieved.
                receiptResponse = (ReceiptResponse)((JsonResult)senderSmartContractsController.GetReceipt(callResponse.TransactionId.ToString())).Value;
                Assert.True(receiptResponse.Success);
                Assert.Null(receiptResponse.NewContractAddress);
                Assert.Equal(response.NewContractAddress, receiptResponse.To);
                Assert.Equal(addr.Address, receiptResponse.From);

                // Test serialization
                // TODO: When refactoring integration tests, move this to the one place and test all types, from method param to storage to serialization.

                var serializationRequest = new BuildCallContractTransactionRequest
                {
                    AccountName     = AccountName,
                    GasLimit        = gasLimit,
                    GasPrice        = SmartContractMempoolValidator.MinGasPrice,
                    Amount          = "0",
                    MethodName      = "TestSerializer",
                    ContractAddress = response.NewContractAddress,
                    FeeAmount       = "0.001",
                    Password        = Password,
                    WalletName      = WalletName,
                    Sender          = addr.Address
                };
                result = (JsonResult)senderSmartContractsController.BuildCallSmartContractTransaction(serializationRequest);
                var serializationResponse = (BuildCallContractTransactionResponse)result.Value;
                SmartContractSharedSteps.SendTransaction(scSender, scReceiver, senderWalletController, serializationResponse.Hex);
                TestHelper.MineBlocks(scReceiver, 2);
                TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(scReceiver, scSender));

                // Would have only saved if execution completed successfully
                counterRequestResult = (string)((JsonResult)senderSmartContractsController.GetStorage(new GetStorageRequest
                {
                    ContractAddress = response.NewContractAddress.ToString(),
                    StorageKey = "Int32",
                    DataType = MethodParameterDataType.Int
                })).Value;
                Assert.Equal("12345", counterRequestResult);
            }
        }
        public void SmartContracts_AddToMempool_OnlyValid()
        {
            using (SmartContractNodeBuilder builder = SmartContractNodeBuilder.Create(this))
            {
                var stratisNodeSync = builder.CreateSmartContractPowNode().WithWallet().Start();

                var callDataSerializer = new CallDataSerializer(new ContractPrimitiveSerializer(stratisNodeSync.FullNode.Network));

                TestHelper.MineBlocks(stratisNodeSync, 105); // coinbase maturity = 100

                var block   = stratisNodeSync.FullNode.BlockStore().GetBlockAsync(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
                var tx = stratisNodeSync.FullNode.Network.CreateTransaction();
                tx.AddInput(new TxIn(new OutPoint(prevTrx.GetHash(), 0), PayToPubkeyHashTemplate.Instance.GenerateScriptPubKey(stratisNodeSync.MinerSecret.PubKey)));
                var contractTxData = new ContractTxData(1, 100, new Gas(10_000_000), new uint160(0), "Test");
                tx.AddOutput(new TxOut(1, new Script(callDataSerializer.Serialize(contractTxData))));
                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 = stratisNodeSync.FullNode.Network.CreateTransaction();
                tx.AddInput(new TxIn(new OutPoint(prevTrx.GetHash(), 0), new Script(new[] { (byte)ScOpcodeType.OP_SPEND })));
                tx.AddOutput(new TxOut(1, new Script(callDataSerializer.Serialize(contractTxData))));
                stratisNodeSync.Broadcast(tx);

                // 2 smart contract outputs
                tx = stratisNodeSync.FullNode.Network.CreateTransaction();
                tx.AddInput(new TxIn(new OutPoint(prevTrx.GetHash(), 0), PayToPubkeyHashTemplate.Instance.GenerateScriptPubKey(stratisNodeSync.MinerSecret.PubKey)));
                tx.AddOutput(new TxOut(1, new Script(callDataSerializer.Serialize(contractTxData))));
                tx.AddOutput(new TxOut(1, new Script(callDataSerializer.Serialize(contractTxData))));
                tx.Sign(stratisNodeSync.FullNode.Network, stratisNodeSync.MinerSecret, false);
                stratisNodeSync.Broadcast(tx);

                // Send to contract
                uint160 contractAddress = new uint160(123);
                var     state           = stratisNodeSync.FullNode.NodeService <IStateRepositoryRoot>();
                state.CreateAccount(contractAddress);
                state.Commit();
                tx = stratisNodeSync.FullNode.Network.CreateTransaction();
                tx.AddInput(new TxIn(new OutPoint(prevTrx.GetHash(), 0), PayToPubkeyHashTemplate.Instance.GenerateScriptPubKey(stratisNodeSync.MinerSecret.PubKey)));
                tx.AddOutput(new TxOut(100, PayToPubkeyHashTemplate.Instance.GenerateScriptPubKey(new KeyId(contractAddress))));
                tx.Sign(stratisNodeSync.FullNode.Network, stratisNodeSync.MinerSecret, false);
                stratisNodeSync.Broadcast(tx);

                // Gas price lower than minimum
                tx = stratisNodeSync.FullNode.Network.CreateTransaction();
                tx.AddInput(new TxIn(new OutPoint(prevTrx.GetHash(), 0), PayToPubkeyHashTemplate.Instance.GenerateScriptPubKey(stratisNodeSync.MinerSecret.PubKey)));
                var lowGasPriceContractTxData = new ContractTxData(1, SmartContractMempoolValidator.MinGasPrice - 1, new Gas(SmartContractFormatRule.GasLimitMaximum), new uint160(0), "Test");
                tx.AddOutput(new TxOut(1, new Script(callDataSerializer.Serialize(lowGasPriceContractTxData))));
                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 = stratisNodeSync.FullNode.Network.CreateTransaction();
                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);
            }
        }
        public void SendAndReceiveSmartContractTransactionsOnPosNetwork()
        {
            using (SmartContractNodeBuilder builder = SmartContractNodeBuilder.Create(this))
            {
                CoreNode scSender   = builder.CreateSmartContractPosNode().WithWallet().Start();
                CoreNode scReceiver = builder.CreateSmartContractPosNode().WithWallet().Start();

                var callDataSerializer = new CallDataSerializer(new ContractPrimitiveSerializer(scSender.FullNode.Network));

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

                // 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;
                ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/TransferTestPos.cs");
                Assert.True(compilationResult.Success);

                var contractTxData = new ContractTxData(vmVersion, gasPrice, gasLimit, compilationResult.Compilation);

                var contractCreateScript = new Script(callDataSerializer.Serialize(contractTxData));
                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
                TestHelper.MineBlocks(scSender, 1);

                // Sync to the receiver node
                TestHelper.ConnectAndSync(scSender, scReceiver);

                // Ensure that boths nodes has the contract
                IStateRepositoryRoot senderState      = scSender.FullNode.NodeService <IStateRepositoryRoot>();
                IStateRepositoryRoot receiverState    = scReceiver.FullNode.NodeService <IStateRepositoryRoot>();
                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 = ContractCompiler.CompileFile("SmartContracts/TransferTestPos.cs");
                Assert.True(compilationResult.Success);
                contractTxData       = new ContractTxData(vmVersion, gasPrice, gasLimit, compilationResult.Compilation);
                contractCreateScript = new Script(callDataSerializer.Serialize(contractTxData));
                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);
                TestHelper.MineBlocks(scSender, 1);

                // 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
                contractTxData = new ContractTxData(1, gasPrice, gasLimit, tokenContractAddress, "Test");
                Script contractCallScript = new Script(callDataSerializer.Serialize(contractTxData));
                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);
                TestHelper.MineBlocks(scSender, 1);

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

                // The balance should now reflect the transfer
                Assert.Equal((ulong)900, senderState.GetCurrentBalance(tokenContractAddress));
            }
        }
예제 #14
0
 public PoAMockChain(int numNodes)
 {
     this.builder = SmartContractNodeBuilder.Create(this);
     this.nodes   = new MockChainNode[numNodes];
 }
예제 #15
0
        public void SendAndReceiveLocalSmartContractTransactionsUsingController()
        {
            using (SmartContractNodeBuilder builder = SmartContractNodeBuilder.Create(this))
            {
                CoreNode scSender   = builder.CreateSmartContractPowNode().WithWallet().Start();
                CoreNode scReceiver = builder.CreateSmartContractPowNode().WithWallet().Start();

                int maturity = (int)scReceiver.FullNode.Network.Consensus.CoinbaseMaturity;

                HdAddress addr = TestHelper.MineBlocks(scSender, maturity + 5).AddressUsed;

                int spendable = GetSpendableBlocks(maturity + 5, maturity);
                var total     = scSender.FullNode.WalletManager().GetSpendableTransactionsInWallet(WalletName).Sum(s => s.Transaction.Amount);
                Assert.Equal(Money.COIN * spendable * 50, total);

                SmartContractsController      senderSmartContractsController = scSender.FullNode.NodeService <SmartContractsController>();
                SmartContractWalletController senderWalletController         = scSender.FullNode.NodeService <SmartContractWalletController>();
                ContractCompilationResult     compilationResult = ContractCompiler.CompileFile("SmartContracts/StorageDemo.cs");
                Assert.True(compilationResult.Success);

                Gas gasLimit = (Gas)(SmartContractFormatRule.GasLimitMaximum / 2);

                var buildRequest = new BuildCreateContractTransactionRequest
                {
                    AccountName  = AccountName,
                    GasLimit     = gasLimit.ToString(),
                    GasPrice     = SmartContractMempoolValidator.MinGasPrice.ToString(),
                    ContractCode = compilationResult.Compilation.ToHexString(),
                    FeeAmount    = "0.001",
                    Password     = Password,
                    WalletName   = WalletName,
                    Sender       = addr.Address
                };

                JsonResult result   = (JsonResult)senderSmartContractsController.BuildCreateSmartContractTransaction(buildRequest);
                var        response = (BuildCreateContractTransactionResponse)result.Value;
                TestHelper.Connect(scSender, scReceiver);

                SmartContractSharedSteps.SendTransaction(scSender, scReceiver, senderWalletController, response.Hex);
                TestHelper.MineBlocks(scReceiver, 2);
                TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(scReceiver, scSender));

                // Check wallet history is updating correctly.
                result = (JsonResult)senderWalletController.GetHistory(new WalletHistoryRequest
                {
                    AccountName = AccountName,
                    WalletName  = WalletName
                });

                var walletHistoryModel = (WalletHistoryModel)result.Value;
                Assert.Single(walletHistoryModel.AccountsHistoryModel.First().TransactionsHistory.Where(x => x.Type == TransactionItemType.Send));

                string counterRequestResult = (string)((JsonResult)senderSmartContractsController.GetStorage(new GetStorageRequest
                {
                    ContractAddress = response.NewContractAddress,
                    StorageKey = "Counter",
                    DataType = MethodParameterDataType.Int
                })).Value;

                Assert.Equal("12345", counterRequestResult);

                var callRequest = new BuildCallContractTransactionRequest
                {
                    AccountName     = AccountName,
                    GasLimit        = gasLimit.ToString(),
                    GasPrice        = SmartContractMempoolValidator.MinGasPrice.ToString(),
                    Amount          = "0",
                    MethodName      = "Increment",
                    ContractAddress = response.NewContractAddress,
                    FeeAmount       = "0.001",
                    Password        = Password,
                    WalletName      = WalletName,
                    Sender          = addr.Address
                };

                result = (JsonResult)senderSmartContractsController.LocalCallSmartContractTransaction(callRequest);
                var callResponse = (ILocalExecutionResult)result.Value;

                // Check that the locally executed transaction returns the correct results
                Assert.Equal(12346, callResponse.Return);
                Assert.False(callResponse.Revert);
                Assert.True(callResponse.GasConsumed > 0);
                Assert.Null(callResponse.ErrorMessage);
                Assert.NotNull(callResponse.InternalTransfers);

                TestHelper.MineBlocks(scReceiver, 2);
                TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(scReceiver, scSender));

                // Check that the on-chain storage has not changed after mining
                counterRequestResult = (string)((JsonResult)senderSmartContractsController.GetStorage(new GetStorageRequest
                {
                    ContractAddress = response.NewContractAddress,
                    StorageKey = "Counter",
                    DataType = MethodParameterDataType.Int
                })).Value;

                Assert.Equal("12345", counterRequestResult);

                // Check wallet history again to make sure nothing has changed
                result = (JsonResult)senderWalletController.GetHistory(new WalletHistoryRequest
                {
                    AccountName = AccountName,
                    WalletName  = WalletName
                });

                walletHistoryModel = (WalletHistoryModel)result.Value;
                Assert.Single(walletHistoryModel.AccountsHistoryModel.First().TransactionsHistory.Where(x => x.Type == TransactionItemType.Send));
            }
        }
예제 #16
0
        public void SendAndReceiveSmartContractTransactions()
        {
            NetworkRegistration.Register(new SmartContractsRegTest());

            using (SmartContractNodeBuilder builder = SmartContractNodeBuilder.Create(this))
            {
                CoreNode scSender   = builder.CreateSmartContractPowNode().WithWallet().Start();
                CoreNode scReceiver = builder.CreateSmartContractPowNode().WithWallet().Start();

                var callDataSerializer = new CallDataSerializer(new ContractPrimitiveSerializer(scSender.FullNode.Network));

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

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

                // Create a token contract.
                ulong gasPrice  = SmartContractMempoolValidator.MinGasPrice;
                int   vmVersion = 1;
                Gas   gasLimit  = (Gas)(SmartContractFormatRule.GasLimitMaximum / 2);
                ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/TransferTest.cs");
                Assert.True(compilationResult.Success);

                var contractTxData = new ContractTxData(vmVersion, gasPrice, gasLimit, compilationResult.Compilation);

                var contractCreateScript = new Script(callDataSerializer.Serialize(contractTxData));
                var txBuildContext       = new TransactionBuildContext(scSender.FullNode.Network)
                {
                    AccountReference = new WalletAccountReference(WalletName, AccountName),
                    MinConfirmations = maturity,
                    TransactionFee   = new Money(1, MoneyUnit.BTC),
                    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 to sync.
                TestHelper.MineBlocks(scSender, 1);

                // Sync to the receiver node.
                TestHelper.ConnectAndSync(scSender, scReceiver);

                // Ensure that both nodes have the contract.
                IStateRepositoryRoot senderState      = scSender.FullNode.NodeService <IStateRepositoryRoot>();
                IStateRepositoryRoot receiverState    = scReceiver.FullNode.NodeService <IStateRepositoryRoot>();
                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 = ContractCompiler.CompileFile("SmartContracts/TransferTest.cs");
                Assert.True(compilationResult.Success);
                contractTxData       = new ContractTxData(vmVersion, gasPrice, gasLimit, compilationResult.Compilation);
                contractCreateScript = new Script(callDataSerializer.Serialize(contractTxData));
                txBuildContext       = new TransactionBuildContext(scSender.FullNode.Network)
                {
                    AccountReference = new WalletAccountReference(WalletName, AccountName),
                    MinConfirmations = maturity,
                    TransactionFee   = new Money(1, MoneyUnit.BTC),
                    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);
                TestHelper.MineBlocks(scSender, 1);

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

                // Ensure that both nodes have the contract.
                senderState          = scSender.FullNode.NodeService <IStateRepositoryRoot>();
                receiverState        = scReceiver.FullNode.NodeService <IStateRepositoryRoot>();
                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.
                contractTxData = new ContractTxData(1, gasPrice, gasLimit, tokenContractAddress, "Test");
                Script contractCallScript = new Script(callDataSerializer.Serialize(contractTxData));
                txBuildContext = new TransactionBuildContext(scSender.FullNode.Network)
                {
                    AccountReference = new WalletAccountReference(WalletName, AccountName),
                    MinConfirmations = maturity,
                    TransactionFee   = new Money(1, MoneyUnit.BTC),
                    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.
                TestHelper.MineBlocks(scSender, 1);

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

                // The balance should now reflect the transfer.
                Assert.Equal((ulong)900, senderState.GetCurrentBalance(tokenContractAddress));
            }
        }
예제 #17
0
        public void SendAndReceiveLocalSmartContractPropertyCallTransactionsUsingController()
        {
            using (SmartContractNodeBuilder builder = SmartContractNodeBuilder.Create(this))
            {
                CoreNode scSender   = builder.CreateSmartContractPowNode().WithWallet().Start();
                CoreNode scReceiver = builder.CreateSmartContractPowNode().WithWallet().Start();

                int maturity = (int)scReceiver.FullNode.Network.Consensus.CoinbaseMaturity;

                HdAddress addr = TestHelper.MineBlocks(scSender, maturity + 5).AddressUsed;

                int spendable = GetSpendableBlocks(maturity + 5, maturity);
                var total     = scSender.FullNode.WalletManager().GetSpendableTransactionsInWallet(WalletName).Sum(s => s.Transaction.Amount);
                Assert.Equal(Money.COIN * spendable * 50, total);

                SmartContractsController      senderSmartContractsController = scSender.FullNode.NodeService <SmartContractsController>();
                SmartContractWalletController senderWalletController         = scSender.FullNode.NodeService <SmartContractWalletController>();
                ContractCompilationResult     compilationResult = ContractCompiler.CompileFile("SmartContracts/StorageDemo.cs");
                Assert.True(compilationResult.Success);

                Gas gasLimit = (Gas)(SmartContractFormatRule.GasLimitMaximum / 2);

                var buildRequest = new BuildCreateContractTransactionRequest
                {
                    AccountName  = AccountName,
                    GasLimit     = gasLimit,
                    GasPrice     = SmartContractMempoolValidator.MinGasPrice,
                    ContractCode = compilationResult.Compilation.ToHexString(),
                    FeeAmount    = "0.001",
                    Password     = Password,
                    WalletName   = WalletName,
                    Sender       = addr.Address
                };

                JsonResult result   = (JsonResult)senderSmartContractsController.BuildCreateSmartContractTransaction(buildRequest);
                var        response = (BuildCreateContractTransactionResponse)result.Value;
                TestHelper.Connect(scSender, scReceiver);

                SmartContractSharedSteps.SendTransaction(scSender, scReceiver, senderWalletController, response.Hex);
                TestHelper.MineBlocks(scReceiver, 2);
                TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(scReceiver, scSender));

                // Make a call request where the MethodName is the name of a property
                var callRequest = new BuildCallContractTransactionRequest
                {
                    AccountName     = AccountName,
                    GasLimit        = gasLimit,
                    GasPrice        = SmartContractMempoolValidator.MinGasPrice,
                    Amount          = "0",
                    MethodName      = "Counter",
                    ContractAddress = response.NewContractAddress,
                    FeeAmount       = "0.001",
                    Password        = Password,
                    WalletName      = WalletName,
                    Sender          = addr.Address
                };

                result = (JsonResult)senderSmartContractsController.LocalCallSmartContractTransaction(callRequest);
                var callResponse = (ILocalExecutionResult)result.Value;

                // Check that the locally executed transaction returns the correct results
                Assert.Equal(12345, callResponse.Return);
                Assert.False(callResponse.Revert);
                Assert.True(callResponse.GasConsumed > 0);
                Assert.Null(callResponse.ErrorMessage);
                Assert.NotNull(callResponse.InternalTransfers);

                TestHelper.MineBlocks(scReceiver, 2);
                TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(scReceiver, scSender));
            }
        }
예제 #18
0
 public PoAMockChain(int numNodes, Mnemonic mnemonic = null)
 {
     this.builder      = SmartContractNodeBuilder.Create(this);
     this.nodes        = new MockChainNode[numNodes];
     this.initMnemonic = mnemonic;
 }