EIP-1352: Restricted address range for precompiles/system contracts

I was thinking managing the precompile space could work along the lines of the OpenGL extension registry. Addresses are allocated and have a specification attached.

From an old blog post

OpenGL (a cross-platform, low-level graphic library controlled by the Khronos group) offers a useful precedent on how this can be managed. OpenGL has included an extension mechanism since the mid 1990’s: a registry is managed by the Architecture Review Board (ARB) where any member of the ARB can propose an extension (which if accepted) is allocated a number in the registry). Different classes of extension exist: single vendor; EXT for older generic or multiple vendor extensions; and ARB for more modern extensions supported by a number of vendors.

2 Likes

and just to make things more explicit. If i was writing that blog post today. I would suggest the EVM evolution working group as the natural home for the registry

1 Like

Would they, though? The address space is enormous. If you, say, hash the binary, or the name of the pro-compile + the deployer’s name (or something along these lines), you get a deterministic address that is unlikely to conflict, no?

1 Like

hashing the binary is nice because you don’t expect a different binary to be able to conflict. If you add names, then it becomes easier to create a conflict which seems less helpful.
But precompiles that do the same thing might actually have a different binary across different clients (or even not be actual precompiles, but plain smart contracts), no?

What I like about a reserved range instead of a hash of whatever is that code analysis tools or manual inspection can easily identify what is a precompile contract.

Some of these contracts will in essence become “system calls” that can do things regular EVM cannot do, such as a lot of things EEA finds precompiles interesting to do. So that would present a different attack surface, and audits/tools would want to know when the attack surface grows.

2 Likes

Would it be within the scope of this EIP to also define how much gas is used when the CALL, CALLCODE, DELEGATECALL and STATICCALL opcodes are used to call contracts within the precompile address range?

It seems like, if a precompile address range is defined at the protocol level, we have the opportunity to more formally define the semantics of calling these precompiles.

Right now, the 700 gas cost of the call opcodes is to reflect the time required to fetch these contracts from disk, but this is not relevant for precompiles. For some precompiles, this 700 cost is a substantial overhead (e.g. ECADD only costs 500 gas, but the actual cost is 1,200 because of this).

A gas cost of 50 might be more suitable? (or even 0? the time taken to run the pre-compile should be factored into its gas formula, no?).

Can you change the title to “EIP 1352: Restricted address range for precompiles/system contracts”?

I scanned all the addresses below and including 0xffff, and found none with code nor any with a non-zero nonce. I did find, however, that these addresses have ether balances totaling 12,517.53127 eth (that’s around 2.5 million dollars US). 99.5% of that is in a single account (0x000…dead).

The core devs should make a donation of this money to the MolachDAO on behalf of the entire community. While the money is already locked and lost, it feels wasted otherwise (especially in an underfunded open source community).

I understand that burning money is a way to increase the value of the coin, and that’s a totally valid position. I also understand that this idea is a very slippery slope. That point of view is also totally valid.

But, It costs nothing to share an idea, and I had this one, and I didn’t really need it anymore, so I thought I’d give it away for free.

IIRC this address is used by ENS as a burn address. @Arachnid is that correct?

1 Like

That’s correct.

:unicorn: to meet length requirements.

Due to the extremely low probability (and lack of adequate testing possibilities) no explicit checks should be added to ensure that external transaction signing or the invoking of the CREATE instruction can result in a precompile address.

Of course the probability is extremely low, but if this happens we will all be confused which chain has the right chain if there is one chain which overwrites the precompile and another chain which uses the precompile at this address. If this happens, then the chance is very high that we get a consensus issue. I propose that in any case a new contract is created (e.g. call to null, CREATE or CREATE2 in a smart contract) code is not deployed in the same way as you try to deploy code using CREATE2 when re-using the same seed.

1 Like

These are the points I raised at the allcoredev-call today…

It’s currently possible to configure a genesis with code at arbitrary addresses. For example, to place a faucet at 0x00...0010.
So if we accept 1352, then implement some other EIP which makes calls to precompiles cheaper, the question is of calls to 0x00...10 should, or should not, be included in that (I think they shouldn’t be, since they are stored on disk like any other code, whereas ‘true’ precompiles are already in-memory)

Dangerous. Next you know, someone files a claim that their money should have been given back to them instead of being ‘donated’. I agree that it’s wasted money, but I also see difficulties in picking it up and using it, as opposed to shipping it back to wherever it came from (which would be a technical nightmare to implement)

Right, but the 700 might also already be factored in. If it was substantially lowered, perhaps the actual cost would also have to be raised (in some cases)?

1 Like

I don’t agree. The call should be cheaper for the whole range. Otherwise, the cost of the call depends on the current configuration (not only the EVM revision) and EVM is not able to compute the cost on its own.

From a technical standpoint, i don’t agree, since gas should correlate to work, and it’s more work to fetch the code from disk than invoke an actual compiled method.
From an architectural standpoint, I kind of agree it might be nicer.
From a practical standpoint, I don’t really care, since it’s not an issue for mainnet.

I’m really just saying that the EIP would do well to specify the behaviour.

More quirks:

  • What about extcodesize of a contract in this range? What about extcodehash? All normal precompile addresses return 0 and zerohash respectively.

I think these are really valuable comments. Before going through to answer them, I do have one simple question: how do you define what is a precompile?

Extended questions:
“Hardforks” have a list of precompiles, so does the Yellow Paper. But private chains are free to do whatever they wish with the address range. If they move sha256 from address 0x2 to 0x4242...4242, does it remain a precompile? How do you specify what a precompile is for example in EIP-1109? Would that specify the precompile addresses as 0x1 to 0x8? Would it specify that an address is a precompile when the client says so (because precompiles are not represented in the genesis)?

So the hard fork impact might be

  • Any contract that would wind up deploying to the reserved range fails with an out-of-gas exception.
  • Any TX “from” the reserved range is invalid and should not be seen in blocks.
    • “To” or beneficiary addresses are valid - that ship sailed with Spurious Dragon and ENS.
  • Any call into the reserved range is at the precompiled price (for EIP-2046/EIP-1109)

And this would be across all Istanbul compatible chains, regardless of what precompiles are configured.

Note that EEA now formally plans to require that precompiles in EEA clients are registered using this mechanism…

My thinking is that we might see people who want to note that they have used an address and provide zero information about what they put there, just letting everyone else know there is someone who expects something (so you reduce accidental collision risk). But others will quite probably put a specification.

EEA client spec mandates the presence of, and some requirements for a permissioning contract, which would be an example of something we might give an address and provide a specification of some kind (probably not an actual contract since there are things that can vary from chain to chain).

1 Like

Follow up to my discission on this from AllCore Devs #120 (https://github.com/ethereum/pm/blob/master/All%20Core%20Devs%20Meetings/Meeting%20120.md)

I brought this up as the scope of precompiles is growing for L2 and alt-eth chains. In particular all L2 chains have at least one system precompile to initiate exits back to L1.

The proposal was to make this proposal impactful by making the whole range “warm”. Martin pointed out this would re-open the broken metre attack.

After thinking about it for two weeks I think the way forward may be to re-open EIP-1109, which is a PRECOMPILEDCALL opcode, that would fail if it called anything but a precompile, and mix it with EIP-2046, which wanted to reduce precompile costs but not make them zero. The proposed fee would be the same as all other CALL series for warm calls, and any call to a non-precompile (as determined by the chain, so hard forks and other-chain additions like L1 exit precompiles would adjust that set) would fail consuming all gas.

As far as when… the next “open” hard fork. It’s not important enough to drive a hard fork and not essential to the merge.

I think making it warm while avoiding the issues with the tree could be accomplished with more drastic changes:

  1. Allocate the range 1…256 for “precompiles”.
  2. Remove these accounts from the tree.
  3. Any account access to this range would just return fixed values (i.e. the null code hash, 0 balance, 0 nonce, etc.)
  4. A call to this range outside of the activated precompiles instantly returns with empty bytes. (This in practice means that the behaviour is the same as today.)
  5. If a call has a value attached, allow the call to be successful, but do not change the account balance.

The critical part is point 5), which ensures that contracts which relied on using one of these addresses for burning can still operate. Important that I omitted the zero address (0x0000000000000000000000000000000000000000 ) as that was never a precompile and is the ultimate “burner address”. (Is this actually a problem worth solving?)

Point 2) is optional, but given point 3) would shadow them, it may as well make sense removing them.

I would be interested what are @holiman’s thoughts on the above?