public ISmartContractExecutionResult Execute(ISmartContractTransactionContext transactionContext) { this.logger.LogTrace("()"); var carrier = SmartContractCarrier.Deserialize(transactionContext); // Create a new address for the contract. uint160 newContractAddress = carrier.GetNewContractAddress(); // Create an account for the contract in the state repository. this.stateSnapshot.CreateAccount(newContractAddress); // Decompile the contract execution code and validate it. SmartContractDecompilation decompilation = SmartContractDecompiler.GetModuleDefinition(carrier.CallData.ContractExecutionCode); SmartContractValidationResult validation = this.validator.Validate(decompilation); // If validation failed, refund the sender any remaining gas. if (!validation.IsValid) { this.logger.LogTrace("(-)[CONTRACT_VALIDATION_FAILED]"); return(SmartContractExecutionResult.ValidationFailed(carrier, validation)); } var block = new Block(transactionContext.BlockHeight, transactionContext.CoinbaseAddress.ToAddress(this.network)); var executionContext = new SmartContractExecutionContext ( block, new Message( newContractAddress.ToAddress(this.network), carrier.Sender.ToAddress(this.network), carrier.Value, carrier.CallData.GasLimit ), newContractAddress, carrier.CallData.GasPrice, carrier.MethodParameters ); LogExecutionContext(this.logger, block, executionContext.Message, newContractAddress, carrier); var gasMeter = new GasMeter(carrier.CallData.GasLimit); IPersistenceStrategy persistenceStrategy = new MeteredPersistenceStrategy(this.stateSnapshot, gasMeter, new BasicKeyEncodingStrategy()); var persistentState = new PersistentState(persistenceStrategy, newContractAddress, this.network); gasMeter.Spend((Gas)GasPriceList.BaseCost); var result = this.vm.Create(carrier.CallData.ContractExecutionCode, executionContext, gasMeter, persistentState, this.stateSnapshot); var revert = result.ExecutionException != null; var internalTransaction = this.transferProcessor.Process( carrier, this.stateSnapshot, transactionContext, result.InternalTransfers, revert); (var fee, var refundTxOuts) = this.refundProcessor.Process( carrier, transactionContext.MempoolFee, result.GasConsumed, result.ExecutionException); var executionResult = new SmartContractExecutionResult { NewContractAddress = revert ? null : newContractAddress, Exception = result.ExecutionException, GasConsumed = result.GasConsumed, Return = result.Result, InternalTransaction = internalTransaction, Fee = fee, Refunds = refundTxOuts }; if (revert) { this.logger.LogTrace("(-)[CONTRACT_EXECUTION_FAILED]"); this.stateSnapshot.Rollback(); } else { this.logger.LogTrace("(-):{0}={1}", nameof(newContractAddress), newContractAddress); this.stateSnapshot.SetCode(newContractAddress, carrier.CallData.ContractExecutionCode); this.stateSnapshot.Commit(); } return(executionResult); }
private ISmartContractExecutionResult CreateContextAndExecute(uint160 contractAddress, byte[] contractCode, string methodName, ISmartContractTransactionContext transactionContext, SmartContractCarrier carrier) { this.logger.LogTrace("()"); var block = new Block(transactionContext.BlockHeight, transactionContext.CoinbaseAddress.ToAddress(this.network)); var executionContext = new SmartContractExecutionContext ( block, new Message( contractAddress.ToAddress(this.network), carrier.Sender.ToAddress(this.network), carrier.Value, carrier.CallData.GasLimit ), contractAddress, carrier.CallData.GasPrice, carrier.MethodParameters ); LogExecutionContext(this.logger, block, executionContext.Message, contractAddress, carrier); var gasMeter = new GasMeter(carrier.CallData.GasLimit); IPersistenceStrategy persistenceStrategy = new MeteredPersistenceStrategy(this.stateSnapshot, gasMeter, this.keyEncodingStrategy); var persistentState = new PersistentState(persistenceStrategy, contractAddress, this.network); gasMeter.Spend((Gas)GasPriceList.BaseCost); var result = this.vm.ExecuteMethod( contractCode, methodName, executionContext, gasMeter, persistentState, this.stateSnapshot); var revert = result.ExecutionException != null; this.logger.LogTrace("(-)"); var internalTransaction = this.transferProcessor.Process( carrier, this.stateSnapshot, transactionContext, result.InternalTransfers, revert); (var fee, var refundTxOuts) = this.refundProcessor.Process( carrier, transactionContext.MempoolFee, result.GasConsumed, result.ExecutionException); var executionResult = new SmartContractExecutionResult { Exception = result.ExecutionException, GasConsumed = result.GasConsumed, Return = result.Result, InternalTransaction = internalTransaction, Fee = fee, Refunds = refundTxOuts }; if (revert) { this.stateSnapshot.Rollback(); } else { this.stateSnapshot.Commit(); } return(executionResult); }
public IContractExecutionResult Execute(IContractTransactionContext transactionContext) { // Deserialization can't fail because this has already been through SmartContractFormatRule. Result <ContractTxData> callDataDeserializationResult = this.serializer.Deserialize(transactionContext.Data); ContractTxData callData = callDataDeserializationResult.Value; bool creation = callData.IsCreateContract; var block = new Block( transactionContext.BlockHeight, transactionContext.CoinbaseAddress.ToAddress(this.network) ); IState state = this.stateFactory.Create( this.stateRoot, block, transactionContext.TxOutValue, transactionContext.TransactionHash); StateTransitionResult result; IState newState = state.Snapshot(); if (creation) { var message = new ExternalCreateMessage( transactionContext.Sender, transactionContext.TxOutValue, callData.GasLimit, callData.ContractExecutionCode, callData.MethodParameters ); result = this.stateProcessor.Apply(newState, message); } else { var message = new ExternalCallMessage( callData.ContractAddress, transactionContext.Sender, transactionContext.TxOutValue, callData.GasLimit, new MethodCall(callData.MethodName, callData.MethodParameters) ); result = this.stateProcessor.Apply(newState, message); } if (result.IsSuccess) { state.TransitionTo(newState); } bool revert = !result.IsSuccess; Transaction internalTransaction = this.transferProcessor.Process( this.stateRoot, result.Success?.ContractAddress, transactionContext, state.InternalTransfers, revert); bool outOfGas = result.IsFailure && result.Error.Kind == StateTransitionErrorKind.OutOfGas; (Money fee, TxOut refundTxOut) = this.refundProcessor.Process( callData, transactionContext.MempoolFee, transactionContext.Sender, result.GasConsumed, outOfGas); var executionResult = new SmartContractExecutionResult { To = !callData.IsCreateContract ? callData.ContractAddress : null, NewContractAddress = !revert && creation ? result.Success?.ContractAddress : null, ErrorMessage = result.Error?.GetErrorMessage(), Revert = revert, GasConsumed = result.GasConsumed, Return = result.Success?.ExecutionResult, InternalTransaction = internalTransaction, Fee = fee, Refund = refundTxOut, Logs = state.GetLogs(this.contractPrimitiveSerializer) }; return(executionResult); }