/// <summary> /// Execute the contract and add all relevant fees and refunds to the block. /// </summary> /// <remarks>TODO: At some point we need to change height to a ulong.</remarks> private ISmartContractExecutionResult ExecuteSmartContract(TxMempoolEntry mempoolEntry) { this.logger.LogTrace("()"); GetSenderResult getSenderResult = this.senderRetriever.GetSender(mempoolEntry.Transaction, this.coinView, this.inBlock.Select(x => x.Transaction).ToList()); if (!getSenderResult.Success) { throw new ConsensusErrorException(new ConsensusError("sc-block-assembler-addcontracttoblock", getSenderResult.Error)); } ISmartContractTransactionContext transactionContext = new SmartContractTransactionContext((ulong)this.height, this.coinbaseAddress, mempoolEntry.Fee, getSenderResult.Sender, mempoolEntry.Transaction); ISmartContractExecutor executor = this.executorFactory.CreateExecutor(this.stateSnapshot, transactionContext); ISmartContractExecutionResult result = executor.Execute(transactionContext); var receipt = new Receipt( new uint256(this.stateSnapshot.Root), result.GasConsumed, result.Logs.ToArray() ); this.receipts.Add(receipt); this.logger.LogTrace("(-)"); return(result); }
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); }
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 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); }
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); }