public ITransferResult TransferFunds(ISmartContractState smartContractState, Address addressTo, ulong amountToTransfer, TransferFundsToContract transferFundsToContractDetails) { ChainBalanceTracker[ContractAddress] = ChainBalanceTracker[ContractAddress] - amountToTransfer; ChainBalanceTracker[addressTo] = ChainBalanceTracker[addressTo] + amountToTransfer; var fakeTransferResult = new TestTransferResult { Success = true }; return(fakeTransferResult); }
/// <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); ulong gasBudget = contractDetails.GasBudget == 0 ? DefaultGasLimit : contractDetails.GasBudget; // Ensure we have enough gas left to be able to fund the new GasMeter. if (smartContractState.GasMeter.GasAvailable < gasBudget) { throw new InsufficientGasException(); } var nestedGasMeter = new GasMeter((Gas)gasBudget); IContractStateRepository track = this.contractStateRepository.StartTracking(); var callData = new CallData(smartContractState.GasMeter.GasLimit, addressTo.ToUint160(this.network), contractDetails.ContractMethodName, contractDetails.MethodParameters); var context = new TransactionContext( this.transactionContext.TransactionHash, this.transactionContext.BlockHeight, this.transactionContext.Coinbase, smartContractState.Message.ContractAddress.ToUint160(this.network), amountToTransfer, this.transactionContext.GetNonceAndIncrement()); VmExecutionResult result = this.vm.ExecuteMethod(nestedGasMeter, track, callData, context); // Update parent gas meter. smartContractState.GasMeter.Spend(nestedGasMeter.GasConsumed); 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)); }
/// <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(); var callData = new CallData(smartContractState.GasMeter.GasLimit, addressTo.ToUint160(this.network), contractDetails.ContractMethodName, contractDetails.MethodParameters); var context = new TransactionContext( this.transactionContext.TransactionHash, this.transactionContext.BlockHeight, this.transactionContext.Coinbase, smartContractState.Message.ContractAddress.ToUint160(this.network), amountToTransfer); var result = this.vm.ExecuteMethod(smartContractState.GasMeter, track, callData, context); 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)); }
///<inheritdoc /> public ITransferResult TransferFunds(ISmartContractState smartContractState, Address addressTo, ulong amountToTransfer, TransferFundsToContract contractDetails) { this.logger.LogTrace("({0}:{1},{2}:{3})", nameof(addressTo), addressTo, nameof(amountToTransfer), amountToTransfer); // TODO: Spend BaseFee here var balance = smartContractState.GetBalance(); if (balance < amountToTransfer) { this.logger.LogTrace("(-)[INSUFFICIENT_BALANCE]:{0}={1}", nameof(balance), balance); throw new InsufficientBalanceException(); } // Discern whether this is a contract or an ordinary address. byte[] contractCode = this.contractStateRepository.GetCode(addressTo.ToUint160(this.network)); if (contractCode == null || contractCode.Length == 0) { this.internalTransferList.Add(new TransferInfo { From = smartContractState.Message.ContractAddress.ToUint160(this.network), To = addressTo.ToUint160(this.network), Value = amountToTransfer }); this.logger.LogTrace("(-)[TRANSFER_TO_SENDER]:Transfer {0} from {1} to {2}.", smartContractState.Message.ContractAddress, addressTo, amountToTransfer); return(TransferResult.Empty()); } this.logger.LogTrace("(-)[TRANSFER_TO_CONTRACT]"); return(ExecuteTransferFundsToContract(contractCode, smartContractState, addressTo, amountToTransfer, contractDetails)); }
/// <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)); }