eip: 5478
thatās a great idea. but instead of introducing a new opcode, did you try to implement this by creating a constructor that accepts an address (and parameters) and uses extcodecopy (instead of calldata)? you will still pay for memory expansion but I think it might be cheaper still. also this works around introducing a new opcode.
Thanks for the comment. We could definitively use extcodecopy
to exactly copy the code from another contract in init_code
of CREATE/CREATE2
, however, this means that for every byte in the code to be copied, the tx needs to pay 200 gas. For example, copying a contract with 10K bytes code will cost 200 * 10K = 2M gas!
The CREATE2COPY
opcode addresses this issue by charging only 2600 (for cold account access). This would save the gas cost from 2M to 2600.
I hope this could explain. Feel free to let me know if you have further question.
(correction in the posts below)
Iām not sure where you brought that 200 gas comes from.
I ran a test, please correct me if Iām wrong:
PUSH1 0x40 ; len
PUSH1 0x00 ; dst offset
PUSH1 0x00 ; src offset
ADDRESS ; addr to copy from (address(this))
EXTCODECOPY
PUSH1 0x00 ; just to verify it was copied properly
MLOAD
execute by the running the following:
evm --json --code 604060006000303c600051 run
{"pc":0,"op":96,"gas":"0x2540be400","gasCost":"0x3","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"PUSH1"}
{"pc":2,"op":96,"gas":"0x2540be3fd","gasCost":"0x3","memSize":0,"stack":["0x60"],"depth":1,"refund":0,"opName":"PUSH1"}
{"pc":4,"op":96,"gas":"0x2540be3fa","gasCost":"0x3","memSize":0,"stack":["0x60","0x0"],"depth":1,"refund":0,"opName":"PUSH1"}
{"pc":6,"op":48,"gas":"0x2540be3f7","gasCost":"0x2","memSize":0,"stack":["0x60","0x0","0x0"],"depth":1,"refund":0,"opName":"ADDRESS"}
{"pc":7,"op":60,"gas":"0x2540be3f5",**"gasCost":"0x70"**,"memSize":0,"stack":["0x60","0x0","0x0","0x7265636569766572"],"depth":1,"refund":0,"opName":"EXTCODECOPY"}
{"pc":8,"op":96,"gas":"0x2540be37f","gasCost":"0x3","memSize":96,"stack":[],"depth":1,"refund":0,"opName":"PUSH1"}
{"pc":10,"op":81,"gas":"0x2540be37c","gasCost":"0x3","memSize":96,"stack":["0x0"],"depth":1,"refund":0,"opName":"MLOAD"}
{"pc":11,"op":0,"gas":"0x2540be379","gasCost":"0x0","memSize":96,"stack":["0x604060006000303c600051000000000000000000000000000000000000000000"],"depth":1,"refund":0,"opName":"STOP"}
{"output":"","gasUsed":"0x87","time":128667}
I have marked in bold the gas used by EXTCODECOPY: 0x70 for 2 words (0x40). notice that for 3 words (0x41~0x60) the gas cost is increase by 6 to 0x76.
The 200 gas per byte is from CREATE2/CREATE2
, where the code here only copies the code in memory, but the code is not yet stored as a contract code. Hope this could explain.
Ah my mistake.
I understand now; I interpreted each byte to copy as the cost of EXTCODECOPY. you were talking about deposit gas price, hereās a reference:
Yes, that is exactly the EIP is optimizing for
My attempt at something like this was Skinniest CREATELINK by wjmelements Ā· Pull Request #2185 Ā· ethereum/EIPs Ā· GitHub
I think there are benefits to recognizing that many contracts might have identical code.
Agree! I think CREATE2COPY and CREATELINK can co-exist as they serve a bit different purposes:
- CREATE2COPY can be used to create a contract with a constructor, which initializes contract storage based on ctor logic;
- CREATELINK can be used to create a āblankā contract. The contract may be have a initialize() method to initialize the storage such as owner, initial parameters, etc.
This EIP seems very limited due fact of popularity of āimmutableā values, since they are part of the byte code.
If there are āimmutableā values, then the contract_code
will be generated by init_code
, which will be generally different even though most of the parts are the same. Yes, we cannot save any store cost of the contract anymore in this case.
However, it depends on which type of contract we want to copy, e.g., in the smart wallet case, if the operator wants to create millions of such smart wallet contracts with minimal storage cost, then the operator may optimize the contract so that all values are either const
or in local storage.