///<inheritdoc /> public ICreateResult Create <T>(ISmartContractState smartContractState, ulong amountToTransfer, object[] parameters, ulong gasLimit = 0) { // TODO: Expend any neccessary costs. ulong gasBudget = (gasLimit != 0) ? gasLimit : DefaultGasLimit; // 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); // Check balance. EnsureContractHasEnoughBalance(smartContractState, amountToTransfer); // Build objects for VM byte[] contractCode = this.contractStateRepository.GetCode(smartContractState.Message.ContractAddress.ToUint160(this.network)); // TODO: Fix this when calling from constructor. var context = new TransactionContext( this.transactionContext.TransactionHash, this.transactionContext.BlockHeight, this.transactionContext.Coinbase, smartContractState.Message.ContractAddress.ToUint160(this.network), amountToTransfer, this.transactionContext.GetNonceAndIncrement()); IContractStateRepository track = this.contractStateRepository.StartTracking(); var createData = new CreateData(nestedGasMeter.GasLimit, contractCode, parameters); // Do create in vm VmExecutionResult result = this.vm.Create(nestedGasMeter, track, createData, context, typeof(T).Name); // Update parent gas meter. smartContractState.GasMeter.Spend(nestedGasMeter.GasConsumed); var revert = result.ExecutionException != null; if (revert) { this.logger.LogTrace("(-)[CONTRACT_EXECUTION_FAILED]"); track.Rollback(); return(CreateResult.Failed()); } this.logger.LogTrace("(-)[CONTRACT_EXECUTION_SUCCEEDED]"); track.Commit(); // TODO: Add internaltransfer update here this.contractLogHolder.AddRawLogs(result.RawLogs); return(CreateResult.Succeeded(result.NewContractAddress.ToAddress(this.network))); }
///<inheritdoc /> public ICreateResult Create <T>(ISmartContractState smartContractState, ulong amountToTransfer, object[] parameters, ulong gasLimit = 0) { Gas gasRemaining = smartContractState.GasMeter.GasAvailable; // For a method call, send all the gas unless an amount was selected.Should only call trusted methods so re - entrance is less problematic. ulong gasBudget = (gasLimit != 0) ? gasLimit : gasRemaining; Debug.WriteLine("Gas budget:" + gasBudget); if (gasRemaining < gasBudget || gasRemaining < GasPriceList.CreateCost) { return(CreateResult.Failed()); } var message = new InternalCreateMessage( smartContractState.Message.ContractAddress.ToUint160(), amountToTransfer, (Gas)gasBudget, parameters, typeof(T).Name ); // 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 ? CreateResult.Succeeded(result.Success.ContractAddress.ToAddress()) : CreateResult.Failed()); }
///<inheritdoc /> public ICreateResult Create <T>(ISmartContractState smartContractState, ulong amountToTransfer, object[] parameters, ulong gasLimit = 0) { ulong gasBudget = (gasLimit != 0) ? gasLimit : smartContractState.GasMeter.GasAvailable; var message = new InternalCreateMessage( smartContractState.Message.ContractAddress.ToUint160(this.network), amountToTransfer, (Gas)gasBudget, parameters, typeof(T).Name ); var result = this.state.Apply(message); return(result.IsSuccess ? CreateResult.Succeeded(result.Success.ContractAddress.ToAddress(this.network)) : CreateResult.Failed()); }