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); } }
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); }
public void SME_CreateContract_MethodParameters_InvalidParameterCount() { SmartContractCompilationResult compilationResult = SmartContractCompiler.CompileFile("SmartContracts/ContractInvalidParameterCount.cs"); Assert.True(compilationResult.Success); byte[] contractCode = compilationResult.Compilation; string[] methodParameters = new string[] { string.Format("{0}#{1}", (int)SmartContractCarrierDataType.Short, 5), }; SmartContractCarrier 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); }
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); }
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); }