private StateTransitionResult ApplyCall(IState state, CallMessage message, byte[] contractCode) { var gasMeter = new GasMeter(message.GasLimit); gasMeter.Spend((Gas)GasPriceList.BaseCost); // This needs to happen after the base fee is charged, which is why it's in here. // TODO - Remove this check. It isn't possible for the method name to be null. if (message.Method.Name == null) { return(StateTransitionResult.Fail(gasMeter.GasConsumed, StateTransitionErrorKind.NoMethodName)); } string type = state.ContractState.GetContractType(message.To); ISmartContractState smartContractState = state.CreateSmartContractState(state, gasMeter, message.To, message, state.ContractState); VmExecutionResult result = this.Vm.ExecuteMethod(smartContractState, message.Method, contractCode, type); bool revert = !result.IsSuccess; if (revert) { return(StateTransitionResult.Fail( gasMeter.GasConsumed, result.Error)); } return(StateTransitionResult.Ok( gasMeter.GasConsumed, message.To, result.Success.Result )); }
private StateTransitionResult ApplyCreate(IState state, object[] parameters, byte[] code, BaseMessage message, uint160 address, string type = null) { var gasMeter = new GasMeter(message.GasLimit); gasMeter.Spend((Gas)GasPriceList.BaseCost); state.ContractState.CreateAccount(address); ISmartContractState smartContractState = state.CreateSmartContractState(state, gasMeter, address, message, state.ContractState); VmExecutionResult result = this.Vm.Create(state.ContractState, smartContractState, code, parameters, type); bool revert = !result.IsSuccess; if (revert) { return(StateTransitionResult.Fail( gasMeter.GasConsumed, result.Error)); } return(StateTransitionResult.Ok( gasMeter.GasConsumed, address, result.Success.Result )); }
/// <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); }
private StateTransitionResult ApplyCall(CallMessage message, byte[] contractCode) { if (this.GasRemaining < message.GasLimit || this.GasRemaining < GasPriceList.BaseCost) { return(StateTransitionResult.Fail((Gas)0, StateTransitionErrorKind.InsufficientGas)); } var gasMeter = new GasMeter(message.GasLimit); gasMeter.Spend((Gas)GasPriceList.BaseCost); if (message.Method.Name == null) { return(StateTransitionResult.Fail(gasMeter.GasConsumed, StateTransitionErrorKind.NoMethodName)); } StateSnapshot stateSnapshot = this.TakeSnapshot(); IContractState state = this.CreateIntermediateState(); string type = state.GetContractType(message.To); ISmartContractState smartContractState = this.CreateSmartContractState(gasMeter, message.To, message, state); VmExecutionResult result = this.Vm.ExecuteMethod(smartContractState, message.Method, contractCode, type); this.GasRemaining -= gasMeter.GasConsumed; bool revert = result.ExecutionException != null; if (revert) { this.Rollback(stateSnapshot); return(StateTransitionResult.Fail( gasMeter.GasConsumed, result.ExecutionException)); } state.Commit(); this.GasRemaining -= gasMeter.GasConsumed; return(StateTransitionResult.Ok( gasMeter.GasConsumed, message.To, result.Result )); }
private StateTransitionResult ApplyCreate(object[] parameters, byte[] code, BaseMessage message, string type = null) { if (this.GasRemaining < message.GasLimit || this.GasRemaining < GasPriceList.BaseCost) { return(StateTransitionResult.Fail((Gas)0, StateTransitionErrorKind.InsufficientGas)); } StateSnapshot stateSnapshot = this.TakeSnapshot(); var gasMeter = new GasMeter(message.GasLimit); gasMeter.Spend((Gas)GasPriceList.BaseCost); uint160 address = this.GetNewAddress(); // Begin tracking the new intermediate state. We need to keep this reference around // for the scope of the transaction, so we can commit it later. IContractState state = this.CreateIntermediateState(); state.CreateAccount(address); ISmartContractState smartContractState = this.CreateSmartContractState(gasMeter, address, message, state); VmExecutionResult result = this.Vm.Create(state, smartContractState, code, parameters, type); this.GasRemaining -= gasMeter.GasConsumed; bool revert = result.ExecutionException != null; if (revert) { this.Rollback(stateSnapshot); return(StateTransitionResult.Fail( gasMeter.GasConsumed, result.ExecutionException)); } state.Commit(); return(StateTransitionResult.Ok( gasMeter.GasConsumed, address, result.Result )); }
/// <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); }