public void SmartContracts_GasMeter_NewHasNoConsumedGas() { var gas = new RuntimeObserver.Gas(1000); var gasMeter = new GasMeter(gas); Assert.Equal(RuntimeObserver.Gas.None, gasMeter.GasConsumed); }
public void SmartContracts_GasMeter_NewHasCorrectInitialGas() { var gas = new RuntimeObserver.Gas(1000); var gasMeter = new GasMeter(gas); Assert.Equal(gas, gasMeter.GasLimit); }
/// <summary> /// Creates a new result for a successful state transition. /// </summary> public static StateTransitionResult Ok(RuntimeObserver.Gas gasConsumed, uint160 contractAddress, object result = null) { return(new StateTransitionResult( new StateTransitionSuccess(gasConsumed, contractAddress, result))); }
public void SmartContracts_GasMeter_NewHasAllAvailableGas() { var gas = new RuntimeObserver.Gas(1000); var gasMeter = new GasMeter(gas); Assert.Equal(gas, gasMeter.GasAvailable); }
public (Money, TxOut) Process(ContractTxData contractTxData, ulong mempoolFee, uint160 sender, RuntimeObserver.Gas gasConsumed, bool outOfGas) { Money fee = mempoolFee; if (outOfGas) { this.logger.LogTrace("(-)[OUTOFGAS_EXCEPTION]"); return(fee, null); } var refund = new Money(contractTxData.GasCostBudget - (gasConsumed * contractTxData.GasPrice)); TxOut ret = null; if (refund > 0) { fee -= refund; ret = this.CreateRefund(sender, refund); } return(fee, ret); }
public void SmartContract_GasMeter_DoesNotHaveEnoughGasOperation() { var gas = new RuntimeObserver.Gas(1000); var operationCost = new RuntimeObserver.Gas(1500); var gasMeter = new GasMeter(gas); Assert.Throws <OutOfGasException>(() => gasMeter.Spend(operationCost)); }
/// <summary> /// Creates a new result for a failed state transition due to a VM exception. /// </summary> public static StateTransitionResult Fail(RuntimeObserver.Gas gasConsumed, VmExecutionError vmError) { // If VM execution ran out of gas we return a different kind of state transition error. StateTransitionErrorKind errorKind = vmError.ErrorKind == VmExecutionErrorKind.OutOfGas ? StateTransitionErrorKind.OutOfGas : StateTransitionErrorKind.VmError; return(new StateTransitionResult(new StateTransitionError(gasConsumed, errorKind, vmError.Message))); }
public StateTransitionSuccess( RuntimeObserver.Gas gasConsumed, uint160 contractAddress, object result = null) { this.GasConsumed = gasConsumed; this.ContractAddress = contractAddress; this.ExecutionResult = result; }
public byte[] FetchBytes(uint160 address, byte[] key) { byte[] encodedKey = this.keyEncodingStrategy.GetBytes(key); byte[] value = this.stateDb.GetStorageValue(address, encodedKey); RuntimeObserver.Gas operationCost = GasPriceList.StorageRetrieveOperationCost(encodedKey, value); this.gasMeter.Spend(operationCost); return(value); }
public void StoreBytes(uint160 address, byte[] key, byte[] value) { byte[] encodedKey = this.keyEncodingStrategy.GetBytes(key); RuntimeObserver.Gas operationCost = GasPriceList.StorageSaveOperationCost( encodedKey, value); this.gasMeter.Spend(operationCost); this.stateDb.SetStorageValue(address, encodedKey, value); }
/// <inheritdoc/> public void Spend(RuntimeObserver.Gas gasToSpend) { if (this.GasAvailable >= gasToSpend) { this.GasAvailable -= gasToSpend; return; } this.GasAvailable = (RuntimeObserver.Gas) 0; throw new OutOfGasException("Went over gas limit of " + this.GasLimit); }
public void SmartContracts_GasMeter_HasEnoughGasOperation() { var diff = (RuntimeObserver.Gas) 100; var gas = new RuntimeObserver.Gas(1000); var consumed = (RuntimeObserver.Gas)(gas - diff); var gasMeter = new GasMeter(gas); gasMeter.Spend(consumed); Assert.Equal(consumed, gasMeter.GasConsumed); Assert.Equal(diff, gasMeter.GasAvailable); }
/// <summary> /// Creates a ContractTxData for contract creation /// </summary> public ContractTxData(int vmVersion, ulong gasPrice, RuntimeObserver.Gas gasLimit, byte[] code, object[] methodParameters = null) { this.OpCodeType = (byte)ScOpcodeType.OP_CREATECONTRACT; this.VmVersion = vmVersion; this.GasPrice = gasPrice; this.GasLimit = gasLimit; this.ContractExecutionCode = code; this.MethodName = ""; this.MethodParameters = methodParameters; this.ContractAddress = uint160.Zero; }
/// <summary> /// Creates a ContractTxData object for a method invocation /// </summary> public ContractTxData(int vmVersion, ulong gasPrice, RuntimeObserver.Gas gasLimit, uint160 contractAddress, string method, object[] methodParameters = null) { this.OpCodeType = (byte)ScOpcodeType.OP_CALLCONTRACT; this.VmVersion = vmVersion; this.GasPrice = gasPrice; this.GasLimit = gasLimit; this.ContractAddress = contractAddress; this.MethodName = method; this.MethodParameters = methodParameters; this.ContractExecutionCode = new byte[0]; }
///<inheritdoc /> public ITransferResult Call( ISmartContractState smartContractState, Address addressTo, ulong amountToTransfer, string methodName, object[] parameters, ulong gasLimit = 0) { RuntimeObserver.Gas gasRemaining = this.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; if (gasRemaining < gasBudget || gasRemaining < GasPriceList.BaseCost) { return(TransferResult.Failed()); } var message = new InternalCallMessage( addressTo.ToUint160(), smartContractState.Message.ContractAddress.ToUint160(), amountToTransfer, (RuntimeObserver.Gas)gasBudget, new MethodCall(methodName, parameters) ); // 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); } this.gasMeter.Spend(result.GasConsumed); return(result.IsSuccess ? TransferResult.Transferred(result.Success.ExecutionResult) : TransferResult.Failed()); }
///<inheritdoc /> public ICreateResult Create <T>(ISmartContractState smartContractState, ulong amountToTransfer, object[] parameters, ulong gasLimit = 0) { RuntimeObserver.Gas gasRemaining = this.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, (RuntimeObserver.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); } this.gasMeter.Spend(result.GasConsumed); return(result.IsSuccess ? CreateResult.Succeeded(result.Success.ContractAddress.ToAddress()) : CreateResult.Failed()); }
///<inheritdoc /> public ITransferResult Transfer(ISmartContractState smartContractState, Address addressTo, ulong amountToTransfer) { RuntimeObserver.Gas gasRemaining = this.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, (RuntimeObserver.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); } this.gasMeter.Spend(result.GasConsumed); return(result.IsSuccess ? TransferResult.Empty() : TransferResult.Failed()); }
/// <summary> /// Total gas cost to execute the instructions in this segment. /// </summary> public RuntimeObserver.Gas CalculateGasCost() { RuntimeObserver.Gas gasTally = (RuntimeObserver.Gas) 0; foreach (Instruction instruction in this.Instructions) { RuntimeObserver.Gas instructionCost = GasPriceList.InstructionOperationCost(instruction); gasTally = (RuntimeObserver.Gas)(gasTally + instructionCost); if (instruction.IsMethodCall()) { var methodToCall = (MethodReference)instruction.Operand; // If it's a method outside this contract then we will add some cost. if (this.methodDefinition.DeclaringType != methodToCall.DeclaringType) { RuntimeObserver.Gas methodCallCost = GasPriceList.MethodCallCost(methodToCall); gasTally = (RuntimeObserver.Gas)(gasTally + methodCallCost); } } } return(gasTally); }
public Result <ContractTxData> SerializeCallContract(byte[] smartContractBytes, int vmVersion, ulong gasPrice, RuntimeObserver.Gas gasLimit) { byte[] contractAddressBytes = smartContractBytes.Slice(PrefixSize, AddressSize); var contractAddress = new uint160(contractAddressBytes); byte[] remaining = smartContractBytes.Slice(CallContractPrefixSize, (uint)(smartContractBytes.Length - CallContractPrefixSize)); IList <byte[]> decodedParams = RLPDecode(remaining); string methodName = this.primitiveSerializer.Deserialize <string>(decodedParams[0]); object[] methodParameters = this.DeserializeMethodParameters(decodedParams[1]); string[] signatures = (decodedParams.Count > 2) ? this.DeserializeSignatures(decodedParams[2]) : null; var callData = new ContractTxData(vmVersion, gasPrice, gasLimit, contractAddress, methodName, methodParameters, signatures); return(Result.Ok(callData)); }
public void SetGasMeterLimitBelow(RuntimeObserver.Gas maximum) { this.GasMeter.SetupGet(g => g.GasAvailable).Returns((RuntimeObserver.Gas)(maximum - 1)); }
protected virtual Result <ContractTxData> SerializeCreateContract(byte[] smartContractBytes, int vmVersion, ulong gasPrice, RuntimeObserver.Gas gasLimit) { byte[] remaining = smartContractBytes.Slice(PrefixSize, (uint)(smartContractBytes.Length - PrefixSize)); IList <byte[]> decodedParams = RLPDecode(remaining); var contractExecutionCode = this.primitiveSerializer.Deserialize <byte[]>(decodedParams[0]); object[] methodParameters = this.DeserializeMethodParameters(decodedParams[1]); string[] signatures = (decodedParams.Count > 2) ? this.DeserializeSignatures(decodedParams[2]) : null; var callData = new ContractTxData(vmVersion, gasPrice, gasLimit, contractExecutionCode, methodParameters, signatures); return(Result.Ok(callData)); }
public SignedCodeContractTxData(int vmVersion, ulong gasPrice, RuntimeObserver.Gas gasLimit, byte[] code, byte[] codeSignature, object[] methodParameters = null) : base(vmVersion, gasPrice, gasLimit, code, methodParameters) { this.CodeSignature = codeSignature; }
public void SetGasMeterLimitAbove(RuntimeObserver.Gas minimum) { this.GasMeter.SetupGet(g => g.GasAvailable).Returns((RuntimeObserver.Gas)(minimum + 1)); }
private Result <ContractTxData> SerializeCreateContract(byte[] smartContractBytes, int vmVersion, ulong gasPrice, RuntimeObserver.Gas gasLimit) { var remaining = smartContractBytes.Slice(PrefixSize, (uint)(smartContractBytes.Length - PrefixSize)); IList <byte[]> decodedParams = RLPDecode(remaining); var contractExecutionCode = this.primitiveSerializer.Deserialize <byte[]>(decodedParams[0]); var methodParameters = this.DeserializeMethodParameters(decodedParams[1]); var callData = new ContractTxData(vmVersion, gasPrice, gasLimit, contractExecutionCode, methodParameters); return(Result.Ok(callData)); }
protected override Result <ContractTxData> SerializeCreateContract(byte[] smartContractBytes, int vmVersion, ulong gasPrice, RuntimeObserver.Gas gasLimit) { byte[] remaining = smartContractBytes.Slice(PrefixSize, (uint)(smartContractBytes.Length - PrefixSize)); IList <byte[]> decodedParams = RLPDecode(remaining); byte[] codeAndSignature = decodedParams[0]; IList <byte[]> decodedCodeAndSignature = RLPDecode(codeAndSignature); byte[] contractExecutionCode = decodedCodeAndSignature[0]; byte[] signature = decodedCodeAndSignature[1]; object[] methodParameters = this.DeserializeMethodParameters(decodedParams[1]); var callData = new SignedCodeContractTxData(vmVersion, gasPrice, gasLimit, contractExecutionCode, signature, methodParameters); return(Result.Ok <ContractTxData>(callData)); }
public ContractTransferMessage(uint160 to, uint160 from, ulong amount, RuntimeObserver.Gas gasLimit) : base(to, from, amount, gasLimit, MethodCall.Receive()) { }
/// <summary> /// Creates a new result for a failed state transition. /// </summary> public static StateTransitionResult Fail(RuntimeObserver.Gas gasConsumed, StateTransitionErrorKind kind) { return(new StateTransitionResult(new StateTransitionError(gasConsumed, kind, null))); }
public InternalCallMessage(uint160 to, uint160 from, ulong amount, RuntimeObserver.Gas gasLimit, MethodCall methodCall) : base(to, from, amount, gasLimit, methodCall) { }
public GasMeter(RuntimeObserver.Gas gasAvailable) { this.GasAvailable = gasAvailable; this.GasLimit = gasAvailable; }
public StateTransitionError(RuntimeObserver.Gas gasConsumed, StateTransitionErrorKind kind, ContractErrorMessage vmError) { this.Kind = kind; this.GasConsumed = gasConsumed; this.VmError = vmError; }