diff --git a/spec.md b/spec.md index 262ea062..767c3124 100644 --- a/spec.md +++ b/spec.md @@ -43,7 +43,7 @@ The default/initial values of the cells are provided along with the declaration In the texual rules below, we'll refer to cells by accesing subcells with the `.` operator. For example, we would access contents of the `statusCode` cell with `eei.statusCode`. For cells that contain elements of K builtin sorts `Map`, `List`, and `Set`, we'll use standard K operators for referring to their contents. -For example, we can access the third element of the `returnData` cell's list using `eei.callState.returnData[2]`. +For example, we can access the third element of the `returnData` cell's list using `eei.returnData[2]`. For some cells, we have comments following the cell declarations with the name the [Yellow Paper] gives to that element of the state. @@ -52,24 +52,24 @@ For some cells, we have comments following the cell declarations with the name t $PGM:EthereumSimulation .StatusCode + .List ``` The `` sub-configuration can be saved/restored when needed between calls. +When stored, it's stored in the `` cell as a list. ```k - 0 - .List - + 0 0 // I_a .Program // I_b 0 // I_s .List // I_d 0 // I_v - - 0 // \mu_g - 0 // \mu_i + 0 // \mu_g + + .List ``` The execution `` keeps track of the self-destruct set, the log, and accumulated gas refund. @@ -86,6 +86,8 @@ The `` sub-configuration stores information about each account on the The `multiplicity="*"` allows us to have multiple accounts simultaneously, and `type="Map"` allows us to access accounts by using the `` as a key. For example, `eei.accounts[0x0001].nonce` would access the nonce of account `0x0001`. +Similar to the ``, the an `` state can be saved or restored on the `` cell. + ```k @@ -96,6 +98,8 @@ For example, `eei.accounts[0x0001].nonce` would access the nonce of account `0x0 0 + + .List ``` Transaction state ``: @@ -192,6 +196,17 @@ The following codes all indicate that the VM ended execution with an exception, | "EVMC_PRECOMPILE_FAILURE" ``` +The following are status codes used to report network state failures to the EVM from the client. +These are not present in the [EVM-C API]. + +- `EVMC_ACCOUNT_ALREADY_EXISTS` indicates that a newly created account already exists. +- `EVMC_BALANCE_UNDERFLOW` indicates an attempt to create an account which already exists. + +```k + syntax ExceptionalStatusCode ::= "EVMC_ACCOUNT_ALREADY_EXISTS" + | "EVMC_BALANCE_UNDERFLOW" +``` + ### Ending Codes These additional status codes indicate that execution has ended in some non-exceptional way. @@ -233,6 +248,145 @@ The semantics are provided in three forms: 3. a set K rules specifying the state update that can happen. +### EEI Internal Helpers + +These methods are used by the other EEI methods as helpers and intermediates to perform larger more complex tasks. +They are for the most part not intended to be exposed to the execution engine or Ethereum client for direct usage. + +**TODO**: `{push,pop,drop}Accounts` should be able to take a specific list of accounts to push/pop/drop, making them more efficient. + +#### `EEI.pushCallState` + +Saves a copy of the current call state in the ``. + +1. Load the current `CALLSTATE` from `eei.callState`. + +2. Prepend `CALLSTATE` to the `eei.callStack`. + +```k + syntax EEIMethod ::= "EEI.pushCallState" + // ---------------------------------------- + rule EEI.pushCallState => . ... + CALLSTATE + (.List => ListItem(CALLSTATE)) ... +``` + +#### `EEI.popCallState` + +Restores the most recently saved ``. + +1. Load the new `CALLSTATE` from `eei.callStack[0]`. + +2. Remove the first element of `eei.callStack`. + +3. Set `eei.callState` to `CALLSTATE`. + +```k + syntax EEIMethod ::= "EEI.popCallState" + // ---------------------------------------- + rule EEI.popCallState => . ... + _ => CALLSTATE + (ListItem(CALLSTATE) => .List) ... +``` + +#### `EEI.dropCallState` + +Forgets the most recently saved `` as reverting back to it will no longer happen. + +1. Remove the first element of `eei.callStack`. + +```k + syntax EEIMethod ::= "EEI.dropCallState" + // ---------------------------------------- + rule EEI.dropCallState => . ... + (ListItem(_) => .List) ... +``` + +#### `EEI.pushAccounts` + +Saves a copy of the `` state in the `` cell. + +1. Load the current `ACCTDATA` from `eei.accounts`. + +2. Prepend `ACCTDATA` to the `eei.accountStack`. + +```k + syntax EEIMethod ::= "EEI.pushAccount" + // -------------------------------------- + rule EEI.pushAccount => . ... + ACCTDATA + (.List => ListItem(ACCTDATA)) ... +``` + +#### `EEI.popAccounts` + +Restores the most recently saved `` state. + +1. Load the new `ACCTDATA` from `eei.accountsStack[0]`. + +2. Remove the first element of `eei.accountsStack`. + +3. Set `eei.accounts` to `ACCTDATA`. + +```k + syntax EEIMethod ::= "EEI.popAccounts" + // -------------------------------------- + rule EEI.popAccounts => . ... + _ => ACCTDATA + (ListItem(ACCTDATA) => .List) ... +``` + +#### `EEI.dropAccounts` + +Forgets the most recently saved `` state as reverting back to it will no longer happen. + +1. Remove the first element of `eei.accountsStack`. + +```k + syntax EEIMethod ::= "EEI.dropAccounts" + // --------------------------------------- + rule EEI.dropAccounts => . ... + (ListItem(_) => .List) ... +``` + +#### `EEI.ifStatus : EthereumSimulation EthereumSimulation` + +If the statuscode is not exception, execute `ETHSIMULATIONGOOD`, otherwise execute `ETHSIMULATIONBAD`. + +1. Load the `STATUSCODE` from `eei.statusCode`. + +2. If `STATUSCODE` is not an `ExceptionalStatusCode`, then: + + i. Call `ETHSIMULATIONGOOD`. + + else: + + i. Call `ETHSIMULATIONBAD`. + +```k + syntax EEIMethod ::= "EEI.ifStatus" EthereumSimulation EthereumSimulation + // ------------------------------------------------------------------------- + rule EEI.ifStatus ETHSIMULATIONGOOD ETHSIMULATIONBAD => ETHSIMULATIONGOOD ... + STATUSCODE + requires notBool isExceptionalStatusCode(STATUSCODE) + + rule EEI.ifStatus ETHSIMULATIONGOOD ETHSIMULATIONBAD => ETHSIMULATIONBAD ... + STATUSCODE + requires isExceptionalStatusCode(STATUSCODE) +``` + +#### `EEI.onGoodStatus : EthereumSimulation` + +Executes the given `ETHSIMULATION` if the current status code is not exceptional. + +1. Call `EEI.ifStatus ETHSIMULATION .EthereumSimulation` + +```k + syntax EEIMethod ::= "EEI.onGoodStatus" EthereumSimulation + // ---------------------------------------------------------- + rule EEI.onGoodStatus ETHSIMULATION => EEI.ifStatus ETHSIMULATION .EthereumSimulation ... +``` + ### Block and Transaction Information Getters Many of the methods exported by the EEI simply query for some state of the current block/transaction. @@ -286,11 +440,13 @@ If there are not `N` blocks yet, return `0`. 1. Load `BLOCKNUM` from `eei.block.number`. -2. If `N EEI.getAccountStorage INDEX => VALUE ... ACCT @@ -623,17 +783,17 @@ In any case, the status is set to `EVMC_SUCCESS`. 2. Add `ACCT` to the set `eei.substate.selfDestruct`. -3. Set `eei.callState.returnData` to `.List` (empty). +3. Set `eei.returnData` to `.List` (empty). -4. Load `BAL` from `eei.accounts[ACCT].balance`. +4. Load `BALFROM` from `eei.accounts[ACCT].balance`. 5. Set `eei.accounts[ACCT].balance` to `0`. -6. If `ACCT == ACCTTO`: +6. If `ACCT =/=Int ACCTTO`, then: - i. then: skip. + i. Load `BALTO` from `eei.acounts[ACCTTO].balance`. - ii. else: add `BAL` to `eei.accounts[ACCTTO].balance`. + ii. Set `eei.accounts[ACCTTO].balance` to `BALTO +Int BALFROM`. ```k syntax EEIMethod ::= "EEI.selfDestruct" Int @@ -646,12 +806,12 @@ In any case, the status is set to `EVMC_SUCCESS`. ACCT - BAL => 0 + BALFROM => 0 ... ACCTTO - BALTO => BALTO +Int BAL + BALTO => BALTO +Int BALFROM ... ... @@ -666,7 +826,7 @@ In any case, the status is set to `EVMC_SUCCESS`. ACCT - BAL => 0 + BALFROM => 0 ... ... @@ -677,7 +837,7 @@ In any case, the status is set to `EVMC_SUCCESS`. Set the return data to the given list of `RDATA` as well setting the status code to `EVMC_SUCCESS`. -1. Set `eei.callState.returnData` to `RDATA`. +1. Set `eei.returnData` to `RDATA`. 2. Set `eei.statusCode` to `EVMC_SUCCESS`. @@ -693,7 +853,7 @@ Set the return data to the given list of `RDATA` as well setting the status code Set the return data to the given list of `RDATA` as well setting the status code to `EVMC_REVERT`. -1. Set `eei.callState.returnData` to `RDATA`. +1. Set `eei.returnData` to `RDATA`. 2. Set `eei.statusCode` to `EVMC_REVERT`. @@ -705,7 +865,166 @@ Set the return data to the given list of `RDATA` as well setting the status code _ => RDATA ``` -#### `EEI.call : Int ByteString ByteString` +#### `EEI.transfer : Int Int` + +Transfer `VALUE` funds into account `ACCTTO`. + +1. Load `ACCTFROM` from `eei.callState.acct`. + +2. Load `BALFROM` from `eei.accounts[ACCTFROM].balance`. + +3. If `VALUE >Int BALFROM`, then: + + i. Set `eei.statusCode` to `EVMC_BALANCE_UNDERFLOW`. + + else: + + i. Set `eei.accounts[ACCTFROM].balance` to `BAL -Int VALUE`. + + ii. Load `BALTO` from `eei.accounts[ACCTTO].balance`. + + iii. Set `eei.accounts[ACCTTO].balance` to `BALTO +Int VALUE`. + +```k + syntax EEIMethod ::= "EEI.transfer" Int Int + // ------------------------------------------- + rule EEI.transfer ACCTTO VALUE => ... + _ => EVMC_BALANCE_UNDERFLOW + ACCTFROM + + ACCTFROM + BALFROM + ... + + requires VALUE >Int BALFROM + + rule EEI.transfer ACCTTO VALUE => ... + ACCTFROM + + ACCTFROM + BALFROM => BALFROM -Int VALUE + ... + + + ACCTTO + BALTO => BALTO +Int VALUE + ... + + requires VALUE <=Int BALFROM +``` + +#### `EEI.callInit : Int Int Int Int Program List` + +Helper for setting up the execution engine to run a specific program as if called by `ACCTFROM` into `ACCTTO`, with apparent value transfer `APPVALUE`, gas allocation `GAVAIL`, program `CODE`, and arguments `ARGS`. + +1. Load `CALLDEPTH` from `eei.callState.callDepth`. + +2. Set `eei.callState.callDepth` to `CALLDEPTH +Int 1`. + +3. Set `eei.callState.caller` to `ACCTFROM`. + +4. Set `eei.callState.acct` to `ACCTTO`. + +5. Set `eei.callState.callValue` to `APPVALUE`. + +6. Set `eei.callState.gas` to `GAVAIL`. + +7. Set `eei.callState.program` to `CODE`. + +8. Set `eei.callState.callData` to `ARGS`. + +9. Set `eei.returnData` to the empty `.List`. + +```k + syntax EEIMethod ::= "EEI.callInit" Int Int Int Int Program List + // ---------------------------------------------------------------- + rule EEI.callInit ACCTFROM ACCTTO APPVALUE GAVAIL CODE ARGS => . ... + + CALLDEPTH => CALLDEPTH +Int 1 + _ => ACCTFROM + _ => ACCTTO + _ => APPVALUE + _ => GAVAIL + _ => CODE + _ => ARGS + +``` + +#### `EEI.call : Int Int Int List` + +**TODO**: Parameterize the `1024` max call depth. + +Call into account `ACCTTO`, with gas allocation `GAVAIL`, apparent value `APPVALUE`, and arguments `ARGS`. + +1. Load `CALLDEPTH` from `eei.callState.callDepth`. + +2. If `CALLDEPTH >=Int 1024`, then: + + i. Set `eei.statusCode` to `EVMC_CALL_DEPTH_EXCEEDED`. + + else: + + i. Load `CODE` from `eei.accountss[ACCTTO].code`. + + ii. Load `ACCTFROM` from `eei.callState.acct`. + + iii. Call `EEI.pushCallState`. + + iv. Call `EEI.pushAccounts`. + + vi. Call `EEI.callInit ACCTFROM ACCTTO APPVALUE GAVAIL CODE ARGS` + + vii. Call `EEI.execute`. + + viii. Call `EEI.popCallState`. + + viii. Call `EEI.ifStatus EEI.dropAccounts EEI.popAccounts`. + + iv. Call `EEI.execute`. + +```k + syntax EEIMethod ::= "EEI.call" Int Int Int List + // ------------------------------------------------ + rule EEI.call ACCTTO GAVAIL APPVALUE ARGS => . ... + _ => EVMC_CALL_DEPTH_EXCEEDED + CALLDEPTH + requires CALLDEPTH >=Int 1024 + + rule EEI.call ACCTTO GAVAIL APPVALUE ARGS + => EEI.pushCallState ~> EEI.pushAccounts + ~> EEI.initCallState ACCTFROM ACCTTO APPVALUE GAVAIL CODE ARGS + ~> EEI.execute + ~> EEI.callFinish + ~> EEI.execute + ... + + ACCTFROM + CALLDEPTH + + ACCTTO + CODE + ... + + requires CALLDEPTH EEI.transferCall ACCTTO VALUE GAVAIL ARGS + => EEI.transfer VALUE ACCTTO + ~> EEI.onGoodStatus (EEI.call ACCTTO VALUE GAVAIL ARGS) + ... + +``` - `EEI.call` **TODO** - `EEI.callCode` **TODO**