EVM Object Format (EOF)

No, current plan is to keep it as a collection of EIPs. But there is also unified spec at https://github.com/ipsilon/eof/blob/main/spec/eof.md

Just want to confirm because I’ve missed some discussions on this, but it looks like the changes previously meant to be in EOF2 are all merged into EOF1, is this correct?

I like the gas parameters for security because I can use them to prevent re-entrancy for eth payments. Without them I would need the PAY opcode for the same level of security.

This pattern breaks some contract wallet recipients and shows why (IMO) we need to remove GAS parameters. A wallet should be able to do internal accounting when it receives ETH.

If we believe that contracts should not be able to do internal accounting on receipt of ETH then we should make that explicit at the EVM layer by providing a mechanism to send ETH without the recipient getting an opportunity to execute code. This used to be possible in a very hacky way with self destructing, but if we feel that pattern is good we should just have an ETH_SEND opcode that doesn’t transfer execution over to the destination.

1 Like

I can imagine another solution. There could be a new type of call (PAYCALL) that allows sub-frames to delegatecall and staticcall but not call and paycall. It would be more powerful than PAY because the recipient can update their own storage, but they can’t cause mischief in other accounts. It would differ from staticcall in that it would allow storage and log for the recipient account.

But I don’t think recipient reaction and right of refusal are important (see ERC20) and I prefer PAY for simplicity. The only accounts with good eth recipient action without calldata are WETH and UniswapV1, and I wouldn’t use PAY in those circumstances. The others I’ve seen are just wasting my gas or trying to steal my money.

1 Like

Yes! Let’s do PAY! (and/or EIP-7609)

(removed, meant to reply to the whole thread as opposed to any specific comment)

I have been providing feedback to the ipsilon team over the last year and have helped to draft / improve some of the EOF proposals. I am in general in favor of any changes to the EVM which improve execution efficiency, provide features for compilers and make it more future proof. That being said, I think there are two areas in the design (current: eof/spec/eof.md at 890ef566b86e8f25215f5cad65e171e2c1de71d4 · ipsilon/eof · GitHub) which I think could benefit from more work before mainlining it.

  1. VLQ. Using variable length quantities instead of fixed-size quantities, both in headers and as instruction immediates. This is a nice-to-have, but I think it will save significant pain if any limits (e.g. codesize limits) need to be upgraded in the future, since they can be implemented in a “soft” limits change, rather than needing a format change. It also can provide some codesize savings (I estimate 2-5% improvement), as well as potentially save opcodes (e.g., SWAP_N vs EXCHANGE) since we don’t need to optimize opcodes for different immediates sizes anymore. I wrote about this more here: update EOF container specs with variable-length encodings by charles-cooper · Pull Request #37 · ipsilon/eof · GitHub. Again, I think it could be ok if EOF shipped without VLQs since it can theoretically be changed later, but the cost of changing this later after mainlining would be high since it would require a format change. Therefore I think the benefit to changing it now (which, per feedback on the above PR, the only downside of which is needing to redo some testing work) outweighs the cost.
  2. Global code section. Right now EOF provides subroutine functionality mainly through code sections. However, to my knowledge an EIP-2315 style design which has a single global code section (effectively allowing cross jumping between routines, which EOF does not allow) was not seriously considered. The benefit of a global code section is mainly about efficiency of compiler-generated code; there are, by definition, some code-sharing optimizations available to a global code section which are not available to the nonglobal code section design. This is a deeper and more permanent(!) design issue that I’m not sure it would be possible to easily fix in a future hard fork. It may be that the benefit of disallowing cross-jumping outweighs the cost to compilers / code generators, at this stage I’m not sure, in any case I don’t think the analysis has been done yet. But in my mind this is a serious issue that should at least be investigated and addressed in the rationale section of the EOF proposals.
1 Like

I agree technically on VLQs – you get better code size now and you future-proof a system that in principle will run forever. I can’t speak to schedule issues, but I imagine they are tight. If it helps – and I’ve forgotten the details of the VLQ scheme you are using and of the EOF immediate size issues – but some schemes would let you specify a fixed-size field with unused bits now which could become variable length later when those bits start getting used.

If someone wants to pick up the 2315 ideas in the future I don’t think that EOF forecloses them. Somewhere there is a old PR of mine proposing that EOF code sections not be functions, but modules with multiple EOF-defined entry points and no cross-module jumps, but with EOF-2315 supported inside of modules. We never discussed it much, but something along those lines should still be doable.

EIP-2315 wasn’t seriously considered in part because it I never seriously proposed it again. It’s last-minute rejection simply set my research back too far, and I became content to join a startup doing other VM work and in my spare time get the proposal to where I wanted it and make sure that EOF functions provide at least the same level of init-time validation, which earlier versions did not.

1 Like