/// <summary> /// Applies an externally generated contract creation message to the current state. /// </summary> public StateTransitionResult Apply(IState state, ExternalCreateMessage message) { var gasMeter = new GasMeter(message.GasLimit); gasMeter.Spend((Gas)GasPriceList.CreateCost); // We need to generate an address here so that we can set the initial balance. uint160 address = state.GenerateAddress(this.AddressGenerator); // For external creates we need to increment the balance state to take into // account any funds sent as part of the original contract invocation transaction. state.AddInitialTransfer(new TransferInfo(message.From, address, message.Amount)); return(ApplyCreate(state, message.Parameters, message.Code, message, address, gasMeter)); }
/// <summary> /// Applies an externally generated contract method call message to the current state. /// </summary> public StateTransitionResult Apply(IState state, ExternalCallMessage message) { var gasMeter = new GasMeter(message.GasLimit); gasMeter.Spend((Gas)GasPriceList.BaseCost); byte[] contractCode = state.ContractState.GetCode(message.To); if (contractCode == null || contractCode.Length == 0) { return(StateTransitionResult.Fail(gasMeter.GasConsumed, StateTransitionErrorKind.NoCode)); } // For external calls we need to increment the balance state to take into // account any funds sent as part of the original contract invocation transaction. state.AddInitialTransfer(new TransferInfo(message.From, message.To, message.Amount)); return(ApplyCall(state, message, contractCode, gasMeter)); }
/// <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)); } var observer = new Observer(gasMeter, new MemoryMeter(ReflectionVirtualMachine.MemoryUnitLimit)); var executionContext = new ExecutionContext(observer); // 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, executionContext); return(result); }