/// <summary>
        /// If the address to where the funds will be tranferred to is a contract, instantiate and execute it.
        /// </summary>
        private ITransferResult ExecuteTransferFundsToContract(byte[] contractCode, ISmartContractState smartContractState, Address addressTo, ulong amountToTransfer, TransferFundsToContract contractDetails)
        {
            this.logger.LogTrace("({0}:{1},{2}:{3})", nameof(addressTo), addressTo, nameof(amountToTransfer), amountToTransfer);

            IContractStateRepository track = this.contractStateRepository.StartTracking();
            IPersistenceStrategy     persistenceStrategy = new MeteredPersistenceStrategy(track, smartContractState.GasMeter, this.keyEncodingStrategy);
            IPersistentState         newPersistentState  = new PersistentState(persistenceStrategy, addressTo.ToUint160(this.network), this.network);

            var newMessage = new Message(addressTo, smartContractState.Message.ContractAddress, amountToTransfer, (Gas)(smartContractState.Message.GasLimit - smartContractState.GasMeter.GasConsumed));

            ISmartContractExecutionContext newContext = new SmartContractExecutionContext(smartContractState.Block, newMessage, addressTo.ToUint160(this.network), 0, contractDetails.MethodParameters);

            ISmartContractVirtualMachine vm = new ReflectionVirtualMachine(new InternalTransactionExecutorFactory(this.keyEncodingStrategy, this.loggerFactory, this.network), this.loggerFactory);

            var result = vm.ExecuteMethod(
                contractCode,
                contractDetails.ContractMethodName,
                newContext,
                smartContractState.GasMeter,
                newPersistentState,
                track);

            var revert = result.ExecutionException != null;

            if (revert)
            {
                track.Rollback();
                return(TransferResult.Failed(result.ExecutionException));
            }

            track.Commit();

            this.internalTransferList.Add(new TransferInfo
            {
                From  = smartContractState.Message.ContractAddress.ToUint160(this.network),
                To    = addressTo.ToUint160(this.network),
                Value = amountToTransfer
            });

            this.logger.LogTrace("(-)");

            return(TransferResult.Transferred(result.Result));
        }
        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 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);
        }