/// <summary> /// Applies an internally generated contract funds transfer message to the current state. /// </summary> public StateTransitionResult Apply(ContractTransferMessage message) { bool enoughBalance = this.EnsureContractHasEnoughBalance(message.From, message.Amount); if (!enoughBalance) { return(StateTransitionResult.Fail((Gas)0, StateTransitionErrorKind.InsufficientBalance)); } // If it's not a contract, create a regular P2PKH tx // If it is a contract, do a regular contract call byte[] contractCode = this.intermediateState.GetCode(message.To); if (contractCode == null || contractCode.Length == 0) { // No contract at this address, create a regular P2PKH xfer this.internalTransfers.Add(new TransferInfo { From = message.From, To = message.To, Value = message.Amount }); return(StateTransitionResult.Ok((Gas)0, message.To)); } return(this.ApplyCall(message, contractCode)); }
/// <summary> /// Applies an internally generated contract funds transfer message to the current state. /// </summary> public StateTransitionResult Apply(IState state, ContractTransferMessage message) { bool enoughBalance = this.EnsureSenderHasEnoughBalance(state, message.From, message.Amount); if (!enoughBalance) { return(StateTransitionResult.Fail((Gas)0, StateTransitionErrorKind.InsufficientBalance)); } var gasMeter = new GasMeter(message.GasLimit); // If it's not a contract, create a regular P2PKH tx // If it is a contract, do a regular contract call byte[] contractCode = state.ContractState.GetCode(message.To); if (contractCode == null || contractCode.Length == 0) { gasMeter.Spend((Gas)GasPriceList.TransferCost); // No contract at this address, create a regular P2PKH xfer state.AddInternalTransfer(new TransferInfo(message.From, message.To, message.Amount)); return(StateTransitionResult.Ok(gasMeter.GasConsumed, message.To)); } // For internal contract-contract transfers we need to add the value contained in the contract invocation transaction // to the internal transfer list. This must occur before we apply the message to the state. state.AddInternalTransfer(new TransferInfo(message.From, message.To, message.Amount)); gasMeter.Spend((Gas)GasPriceList.BaseCost); StateTransitionResult result = this.ApplyCall(state, message, contractCode, gasMeter); return(result); }
///<inheritdoc /> public ITransferResult Transfer(ISmartContractState smartContractState, Address addressTo, ulong amountToTransfer) { this.logger.LogTrace("({0}:{1},{2}:{3})", nameof(addressTo), addressTo, nameof(amountToTransfer), amountToTransfer); ulong gasBudget = DefaultGasLimit; // for Transfer always send limited gas to prevent re-entrance. var message = new ContractTransferMessage( addressTo.ToUint160(this.network), smartContractState.Message.ContractAddress.ToUint160(this.network), amountToTransfer, (Gas)gasBudget ); var result = this.state.Apply(message); return(result.IsSuccess ? TransferResult.Empty() : TransferResult.Failed()); }
/// <summary> /// Applies an internally generated contract funds transfer message to the current state. /// </summary> public StateTransitionResult Apply(IState state, ContractTransferMessage message) { bool enoughBalance = this.EnsureContractHasEnoughBalance(state, message.From, message.Amount); if (!enoughBalance) { return(StateTransitionResult.Fail((Gas)0, StateTransitionErrorKind.InsufficientBalance)); } // If it's not a contract, create a regular P2PKH tx // If it is a contract, do a regular contract call byte[] contractCode = state.ContractState.GetCode(message.To); if (contractCode == null || contractCode.Length == 0) { // No contract at this address, create a regular P2PKH xfer state.AddInternalTransfer(new TransferInfo { From = message.From, To = message.To, Value = message.Amount }); return(StateTransitionResult.Ok((Gas)0, message.To)); } StateTransitionResult result = this.ApplyCall(state, message, contractCode); // For successful internal contract-contract transfers we need to add the transfer to the internal transfer list. if (result.IsSuccess) { state.AddInternalTransfer(new TransferInfo { From = message.From, To = message.To, Value = message.Amount }); } return(result); }
///<inheritdoc /> public ITransferResult Transfer(ISmartContractState smartContractState, Address addressTo, ulong amountToTransfer) { this.logger.LogTrace("({0}:{1},{2}:{3})", nameof(addressTo), addressTo, nameof(amountToTransfer), amountToTransfer); ulong gasBudget = DefaultGasLimit; // for Transfer always send limited gas to prevent re-entrance. Gas gasRemaining = smartContractState.GasMeter.GasAvailable; if (gasRemaining < gasBudget || gasRemaining < GasPriceList.BaseCost) { return(TransferResult.Failed()); } var message = new ContractTransferMessage( addressTo.ToUint160(this.network), smartContractState.Message.ContractAddress.ToUint160(this.network), amountToTransfer, (Gas)gasBudget ); // Create a snapshot of the current state IState newState = this.state.Snapshot(); // Apply the message to the snapshot StateTransitionResult result = this.stateProcessor.Apply(newState, message); // Transition the current state to the new state if (result.IsSuccess) { this.state.TransitionTo(newState); } smartContractState.GasMeter.Spend(result.GasConsumed); return(result.IsSuccess ? TransferResult.Empty() : TransferResult.Failed()); }
///<inheritdoc /> public ITransferResult Transfer(ISmartContractState smartContractState, Address addressTo, ulong amountToTransfer) { Gas gasRemaining = smartContractState.GasMeter.GasAvailable; if (gasRemaining < GasPriceList.TransferCost) { return(TransferResult.Failed()); } ulong gasBudget = (gasRemaining < DefaultGasLimit) ? gasRemaining // have enough for at least a transfer but not for the DefaultGasLimit : DefaultGasLimit; // have enough for anything var message = new ContractTransferMessage( addressTo.ToUint160(), smartContractState.Message.ContractAddress.ToUint160(), amountToTransfer, (Gas)gasBudget ); // Create a snapshot of the current state IState newState = this.state.Snapshot(); // Apply the message to the snapshot StateTransitionResult result = this.stateProcessor.Apply(newState, message); // Transition the current state to the new state if (result.IsSuccess) { this.state.TransitionTo(newState); } smartContractState.GasMeter.Spend(result.GasConsumed); return(result.IsSuccess ? TransferResult.Empty() : TransferResult.Failed()); }