Skip to content

Commit

Permalink
Exception, INVALID, RETURN, REVERT and STOP costs.
Browse files Browse the repository at this point in the history
  • Loading branch information
virgil-serbanuta committed Nov 27, 2017
1 parent ef831f8 commit 6aecbfe
Showing 1 changed file with 70 additions and 10 deletions.
80 changes: 70 additions & 10 deletions gas.md
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,9 @@ We assume that all operations interrogating the local state have complexity
currentRegisterMemory + sum [registerSize(r) | r <- rVALUES]
```

* `RETURN`
* `RETURN` (local version)
A `RETURN` is a local one if the call stack is not empty.

Copy values from return registers to caller locations restore local context,
including (the current register stack memory requirements), mark registers'
data for reclaiming, and jump back to call site. Note that, since the
Expand All @@ -399,18 +401,66 @@ We assume that all operations interrogating the local state have complexity
sum [registerLoadDelta(r, v) | (r, v) <- getReturns() `zip` rVALUES]
```

#### `STOP` and `REVERT`
#### `RETURN` (account call version), `INVALID`, `STOP`, `REVERT` and exceptions

A `RETURN` is a an account call one if the call stack is empty.

`INVALID` generates an exception in the callee, whose cost is pre-paid.

`STOP` is an explicit instruction, but reaching the end of a function would
also do an implicit stop. `STOP` has `0` actual return values.

For `STOP`, `RETURN` and `REVERT`: if the actual return values count is
different fron the expected return value count, the caller experiences an
exception, in which case one should use the exception-tagged cost. Note that
in such cases it does not make sense to set the output values and return code
since the exception means that the caller can't handle them.

* `STOP`
All the costs below are billed to the caller and not taken out of the callee
gas limit. The `- exceptionCost` part refers to the callee prepaid exception
cost which is being refunded since any possible exception belongs to the caller.

* `INVALID` and exceptions in general
```hs
computationCost(INVALID|exception) = 0
```
* `STOP`.
```hs
computationCost(STOP) = stopCost() -- defined in terms of the current execution context
computationCost(STOP) =
environmentRestoreCost(with-world) + wordCopyCost * (registersize 1) +
refundCost + returnValueCountComparisonCost - exceptionCost
computationCost(exception, STOP) =
environmentRestoreCost(with-world) + refundCost +
returnValueCountComparisonCost - exceptionCost
```
* `REVERT`
```hs
computationCost(REVERT(nRETURNS) rVALUES) = wordCopyCost * registerSize(rValues) +
revertCost() -- defined in terms of the current execution context.
computationCost(REVERT(nRETURNS) rVALUES) =
environmentRestoreCost + wordCopyCost * (registersize 0) +
wordCopyCost * sum [registerSize(r) | r <- rVALUES] +
returnValueCountComparisonCost - exceptionCost
computationCost(exception, REVERT(nRETURNS) rVALUES) =
environmentRestoreCost + returnValueCountComparisonCost - exceptionCost
```
* `RETURN`
```hs
computationCost(RETURN(nRETURNS) rVALUES) =
environmentRestoreCost + wordCopyCost * (registersize 0) +
wordCopyCost * sum [registerSize(r) | r <- rVALUES] +
returnValueCountComparisonCost - exceptionCost
computationCost(exception, RETURN(nRETURNS) rVALUES) =
environmentRestoreCost + returnValueCountComparisonCost - exceptionCost
```

environmentRestoreCost is the cost of re-establishing the callStack, worldState
and subState pointers to what they were before the current contract call.

TODO: Do we count any cost for freeing memory? This occurs at any operation
which resizes a register or a memory value, but it's most obvious at calls,
returns and similar things. I guess that it's better to include the memory
freeing cost in the allocation cost since all memory seems to be freed after the
top call finishes. We should check that this is the case.

TODO: Figure out more precise costs for these

#### `CALL`, `CALLCODE`, `DELEGATECALL` and `STATICCALL`
Expand Down Expand Up @@ -502,7 +552,7 @@ in a flat-fee cost.
computationCost(existent-account, #callWithCode(...)) =
accountTypeCheckCost + codeLoadingCost + methodCallCheckCost +
callStateSavingCost + accountTransferCost(CALLOP) + constantCallSetupCost +
callDataSetupCost + callFeeCost
callDataSetupCost + callFeeCost + exceptionCost

codeLoadingCost = codeByteLoadingCost * codeSize
callDataSetupCost = wordCopyCost * callDataSize
Expand Down Expand Up @@ -560,6 +610,19 @@ TODO: Is the callFeeCost fixed or based on the stack size?
TODO: Returning can be either implicit or explicit, should take that into
account

#### Exception costs

Many things generate exceptions, including being out of gas, which means that
there may not be any gas left to pay for the exception. Therefore it is
preferable that all exception handling costs are pre-paid by `CALL`-like
operations and returned by `RETURN`-like operations. TODO: Make sure that this
actually happens.

```hs
exceptionCost = environmentRestoreCost + wordCopyCost * (registersize 0)
```


#### Logging
We use the same schema from the yellow paper, but taking into account the size
of the logged registers.
Expand Down Expand Up @@ -605,8 +668,6 @@ of the logged registers.
(registerSize wVALUE - storeCellSize(value wIndex))
```



#### Account operations

* `BALANCE`
Expand Down Expand Up @@ -708,7 +769,6 @@ Definitions
* MOVE
* CREATE
* SELFDESTRUCT
* INVALID
* MLOADN
* MSTOREN
* LOADPOS
Expand Down

0 comments on commit 6aecbfe

Please sign in to comment.