-
Notifications
You must be signed in to change notification settings - Fork 4k
Docs cleanup and truffle usage #9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 4 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| =================================== | ||
| ``CODECOPY`` in Transpiled Bytecode | ||
| =================================== | ||
|
|
||
| The opcode ``CODECOPY`` accepts ``memOffset``, ``codeOffset``, and ``length`` inputs from the stack, modifying the memory so that ``memory[memOffset:memOffset + length] = code[codeOffset:codeOffset + length]``. Since we are by definition modifying the ``code`` of a contract by transpiling, there is no general way to handle pre-transpiled ``CODECOPYs`` since the impact on execution is dependent on how the ``CODECOPY`` was expected to be used. For Solidity, there are three ways in which ``CODECOPY`` is used: | ||
|
|
||
| 1. Constants which exceed 32 bytes in length are stored in the bytecode and ``CODECOPY`` ed for use in execution. (if <=32 bytes they are just ``PUSHN`` ed) | ||
| 2. All constructor logic for initcode is prefixed to the bytecode to be deployed, and this prefix runs ``CODECOPY(suffixToDeploy), ..., RETURN`` during ``CREATE(2)`` . | ||
| 3. Constructor parameters are passed as bytecode and then are ``CODECOPY`` ed to memory before being treated like calldata. | ||
|
|
||
| This document explains each of these cases and how they're handled transpilation-side. | ||
|
|
||
| Constants | ||
| ========= | ||
|
|
||
| Constants larger than 32 bytes are stored in the bytecode and ``CODECOPY`` ed to access in execution. Initial investigation shows that the pattern which always occurs leading up to a ``CODECOPY`` for constants is: | ||
|
|
||
| .. code-block:: none | ||
|
|
||
| ... | ||
| PUSH2 // offset | ||
| PUSH1 // length | ||
| SWAP2 // where to shove it into memory | ||
| CODECOPY | ||
| ... | ||
|
|
||
| With some memory allocation operations preceding the ``PUSH, PUSH, SWAP...`` which may also be standard (haven't tested). Some sample code which this example was pulled from can be found `this gist`_ . | ||
|
|
||
| To deal with constants, we still want to copy the correct constant--this will just be at a different index once we insert transpiled bytecode above it. So, we just increase the ``codeOffset`` input to ``CODECOPY`` in every case that a constant is being loaded into memory. Hopefully, all constants are appended to the end of a file so that we may simply add a fixed offset for every constant. | ||
|
|
||
| Returning deployed bytecode in ``CREATE(2)`` | ||
| ============================================ | ||
|
|
||
| All constructor logic for initcode is prefixed to the bytecode to be deployed, and this prefix runs ``CODECOPY(suffixToDeploy), ..., RETURN`` during ``CREATE(2)``. If constructor logic is empty (i.e. no ``constructor()`` function specified in Solidity) this prefix is quite simple but still exists. This ``CODECOPY`` simply puts the prefix into memory so that the deployed byetcode can be deployed. So, what we need to do is increase the ``length`` input both to ``CODECOPY`` and the ``RETURN``. The ``CODECOPY, RETURN`` pattern seems to appear in the following format: | ||
|
|
||
| .. code-block:: none | ||
|
|
||
| PUSH2 // codecopy's and RETURN's length | ||
| DUP1 // DUPed to use twice, for RETURN and CODECOPY both | ||
| PUSH2 // codecopy's offset | ||
| PUSH1 codecopy's destOffset | ||
| CODECOPY // copy | ||
| PUSH1 0 // RETURN offset | ||
| RETURN // uses above RETURN offset and DUP'ed length above | ||
|
|
||
| So by adding to the consumed bytes of the first ``PUSH2`` above, in accordance to the extra bytes added by transpilation, we make sure the correct length is both ``CODECOPY``ed and ``RETURN`` ed. Note that, if we have constructor logic which gets transpiled, this will require modifying the ``// codecopy's offset`` line above as well. | ||
|
|
||
| Constructor Parameters | ||
| ====================== | ||
|
|
||
| Constructor parameters are passed as bytecode and then are ``CODECOPY`` ed to memory before being treated like calldata. This is because the EVM execution which is initiated by ``CREATE(2)`` does not have a calldata parameter, so the inputs must be passed in a different way. For more discussion, check out `this discussion`_ on stack exchange. | ||
|
|
||
| We handle this similarly to how we handle constants, by changing the ``codeOffset`` input appropriately. Both constants used in the constructor and constructor inputs are at the end of the file. | ||
|
|
||
| The pattern it uses is: | ||
|
|
||
| .. code-block:: none | ||
|
|
||
| ... | ||
| [PC 0000000015] PUSH2: 0x01cf // should be initcode.length + deployedbytecode.length | ||
| [PC 0000000018] CODESIZE | ||
| [PC 0000000019] SUB // subtract however big the code is from the amount pushed above to get the length of constructor input | ||
| [PC 000000001a] DUP1 | ||
| [PC 000000001b] PUSH2: 0x01cf // should also be initcode.length + deployedbytecode.length | ||
| [PC 000000001e] DUP4 | ||
| [PC 000000001f] CODECOPY | ||
|
|
||
| .. _`this gist`: https://gist.github.com/ben-chain/677457843793d7c6c7feced4e3b9311a | ||
| .. _`this discussion`: https://ethereum.stackexchange.com/questions/58866/how-does-a-contracts-constructor-work-and-load-input-values |
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,14 +12,21 @@ Pure Opcodes | |
| ============ | ||
|
|
||
| The following opcodes perform stack operations which are constant in terms of L1/L2 state, and do not require modification: | ||
|
|
||
| - Arithmetic/pure-math opcodes: | ||
| <<<<<<< HEAD | ||
| - ``ADD, MUL, SUB, DIV, SDIV, MOD, SMOD, ADDMOD, MULMOD, EXP, SIGNEXTEND, LT, GT, SLT, SGT, EQ, ISZERO, AND, OR, XOR, NOT, BYT, SHL, SHR, SAAR, SHA3``. | ||
| - \"Pure\" code execution operations: | ||
| - ``PUSH1....PUSH32, DUP1...DUP16, SWAP1...SWAP16, POP, LOG0...LOG4, STOP, REVERT, RETURN, PC, GAS, JUMPDEST*``. \* NOTE: `See section <https://github.com/op-optimism/optimistic-rollup/wiki/JUMP-Transpilation>`_ which involves ``JUMPDEST`` s. | ||
| ======= | ||
| - ``ADD, MUL, SUB, DIV, SDIV, MOD, SMOD, ADDMOD, MULMOD, EXP, SIGNEXTEND, LT, GT, SLT, SGT, EQ, ISZERO, AND, OR, XOR, NOT, BYT, SHL, SHR, SAAR, SHA3``. | ||
| - "Pure" code execution operations: | ||
| - ``PUSH1....PUSH32, DUP1...DUP16, SWAP1...SWAP16, POP, LOG0...LOG4, STOP, REVERT, RETURN, PC, GAS, JUMPDEST*``. \* NOTE: `See section <https://github.com/op-optimism/optimistic-rollup/wiki/JUMP-Transpilation>`_ which involves ``JUMPDEST``s. | ||
| >>>>>>> newrepo/master | ||
| - "Pure" memory modifying operations: | ||
| - ``MLOAD, MSTORE, MSTORE8, MSIZE``. | ||
| - Permitted execution-context-dependent operations: | ||
| - ``CALLVALUE*, CALLDATALOAD, CALLDATASIZE, CALLDATACOPY, CODESIZE, RETURNDATASIZE, RETURNDATACOPY`` \*Note: ``CALLVALUE`` will always be 0 because we enforce that all ``CALL``s always pass 0 in our purity checking. | ||
| - ``CALLVALUE*, CALLDATALOAD, CALLDATASIZE, CALLDATACOPY, CODESIZE, RETURNDATASIZE, RETURNDATACOPY`` \*Note: ``CALLVALUE`` will always be 0 because we enforce that all ``CALL`` s always pass 0 in our purity checking. | ||
|
|
||
| Replaced Opcodes | ||
| ================ | ||
|
|
@@ -87,6 +94,8 @@ To replace Call-type opcodes, we have to pass an existing slice of ``calldata`` | |
| .. list-table:: | ||
| :widths: 50 50 | ||
| :header-rows: 1 | ||
| <<<<<<< HEAD | ||
| ======= | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This looks like an unresolved conflict. Choose one or the other and get rid of the metadata (<<<<<<< HEAD, ========, >>>>>>>). |
||
|
|
||
| * - Opcode | ||
| - ``stackPositionOfCallArgsMemOffset`` | ||
|
|
@@ -96,13 +105,24 @@ To replace Call-type opcodes, we have to pass an existing slice of ``calldata`` | |
| - 2 | ||
| * - ``DELEGATECALL`` | ||
| - 2 | ||
| >>>>>>> newrepo/master | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This looks like an unresolved conflict. Choose one or the other and get rid of the metadata (<<<<<<< HEAD, ========, >>>>>>>). |
||
|
|
||
| Special cases: ``CODECOPY`` and ``JUMP``s | ||
| ----------------------- | ||
| * - Opcode | ||
| - ``stackPositionOfCallArgsMemOffset`` | ||
| * - ``CALL`` | ||
| - 3 | ||
| * - ``STATICCALL`` | ||
| - 2 | ||
| * - ``DELEGATECALL`` | ||
| - 2 | ||
|
|
||
| Special cases: ``CODECOPY`` and ``JUMP`` s | ||
| ------------------------------------------ | ||
|
|
||
| There are two functions which are "Pure code execution operations" just like ``CODESIZE``, ``REVERT``, etc., however, they are used by the Solidity compiler in ways which the transpilation process affects, and need to be dealt with in the transpiler. | ||
| - Because we are inserting bytecode, we are changing the index of every ``JUMPDEST`` proceeding each insertion operation. This means our ``JUMP`` and ``JUMPI`` values need to be transpiled or they will fail/go to the wrong place. We handle this by making all ``JUMP``s go to new bytecode that we append at the end that simply contains a mapping from untranspiled ``JUMPDEST`` bytecode location to transpiled ``JUMPDEST`` bytecode location. The logic finds the new location and ``JUMP``s to it. See the `"JUMP Modification" page <https://github.com/op-optimism/optimistic-rollup/wiki/JUMP-Transpilation>`_ for more details. | ||
| - The opcode ``CODECOPY`` would work fine, in principle, in our code contracts, and its effect on execution is independent of L1 state. However, because ``CODECOPY`` is used to retrieve Solidity constants, we'll need to deal with it in the transpiler. We have not yet implemented this. If this is the only way in which ``CODECOPY`` is used by solidity, then this will be easy. If not... we'll cross that bridge then. | ||
|
|
||
| - Because we are inserting bytecode, we are changing the index of every ``JUMPDEST`` proceeding each insertion operation. This means our ``JUMP`` and ``JUMPI`` values need to be transpiled or they will fail/go to the wrong place. We handle this by making all ``JUMP`` s go to new bytecode that we append at the end that simply contains a mapping from untranspiled ``JUMPDEST`` bytecode location to transpiled ``JUMPDEST`` bytecode location. The logic finds the new location and ``JUMP`` s to it. See the `"JUMP Modification" page <https://github.com/op-optimism/optimistic-rollup/wiki/JUMP-Transpilation>`_ for more details. | ||
| - The opcode ``CODECOPY`` works fine, in principle, in our code contracts, as its effect on execution is independent of L1 state. However, because that code itself is modified by transpilation, we need to deal with it in the transpiler. See our ``CODECOPY`` `section`_ for how we handle these modifications. | ||
|
|
||
| Banned Opcodes | ||
| ============== | ||
|
|
@@ -138,3 +158,4 @@ Others | |
| - ``COINBASE`` -- since we don't have inflation in L2 | ||
| - ``DIFFICULTY`` -- since there is no sense of difficulty in L2. An analogous value in L2 is actually the MEVA price, but it's not so analogous that transpiling would make any sense. | ||
|
|
||
| .. _`section`: ./codecopy.html | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like an unresolved conflict. Choose one or the other and get rid of the metadata (<<<<<<< HEAD, ========, >>>>>>>).