EIP-2330: EXTSLOAD and ABI for lower gas cost and off-chain apps

Thanks, I’ve updated both now in the EIP, higher gas cost (1500) and renamed to EXTSLOAD.

Proposal A new EVM instruction EXTSLOAD (0x5c) that works like SLOAD (0x54) with the gas cost of EXTCODE(700) + SLOAD(800) = 1500 and an additional parameter representing the contract that is to be read from.

Maybe you mean EXTCODEHASH instead of EXTCODE?

1 Like

I was referring to the Fee Schedule from the yellow paper:

There it is G_extcode_ = 700 and G_sload_ = 200 – just that EIP-1884 will update G_sload_ to 800 so I referenced that value.

1 Like

Love to see there is interest in this opcode! Please see this thread for an earlier discussion about it.

2 Likes

This constant misunderstanding is probably the biggest reason for why we definitely should introduce this new opcode. Any developer who currently codes Solidity assuming non-exposed storage variables are in any way private is creating attack surfaces today. The “private” is an artificial attribute that does not actually exist in any meaningful way and just leads to confusion as some people in fact believe that the data would be protected in some way – while it is not. It’s open today, readable by anyone who cares to. If there is an “attack” transaction that can only be created by knowing the internal storage state of a contract then it can be created today already. EXTSLOAD would wipe out this misunderstanding making it clear to every developer that their contract storage data is always in the open. This would clarify documentation and language around this whole topic.

meta
@anett is there a way to merge this and this thread?

5 Likes

Btw. I’ve added an Aleth implementation for this opcode https://github.com/ethereum/aleth/pull/5805

@dominic not sure what you mean by “merge threads” but I’m worried that’s not possible to merge thread on discourse :confused:

From a software-engineering perspective, giving access to private members of another object is considered bad design, as it by-passes state encapsulation. This is not about data protection, this is about software design.

For example, when using EXTSLOAD on an OpenZeppeling proxy contract, it might work for a while, but then suddenly brake once the proxy contract is upgraded because the calling contract might have made wrong assumption about the internal state of the proxy contract. When calling methods on other people’s contracts, one should use the official API exposed through the according methods.

If you want to save gas, you should propose lower costs for calls to other contracts in general.

External clients can already arbitrarily read contract storage slots.

Further, there is a big difference between “giving access to private members of another object is considered bad design” and “accessing private members of another object is considered bad design”.

In other words, giving software developers more tools/functionality is not bad, just because some might shoot themselves in the foot. However, shooting yourself in the foot is almost always a bad idea.

3 Likes

In the proposal it is mentioned cost of the proposed opcode EXTSLOAD = cost of EXTCODE + cost of SLOAD. Since if self contract knows which slot id it wants to read from which target contract, the bytecode of the target contract does not provide any useful information and I think the target contract address and slot id is enough for the geth node (and others) to fetch the slot value from the SSD, so the cost could be simply a cost of a SLOAD.

2 Likes

Thanks to @zemse this EIP just got updated with in the context of the upcoming EVM changes. Would love to discuss getting this EIP to the next stage at the Magicians meet-up in Berlin next month ETH Station upcoming event in Berlin [call for action] - #3 by 0xpApaSmURf so let me know if anyone is around then.

Ah I can’t go to that sadly, but this opcode seems intuitively like something that would be very good. I’m having a fleeting thought (without much testing on it) that some current smart contracts might rely on the fact that others can’t read their state right now?

I wonder if we can come up with an example where adding this opcode gives smart contracts the ability to do damage of some kind that you couldn’t already do off-chain with the sensitive data.

I came across a contract that prevents other contracts from directly reading the state on it. I think the benefit comes from charging money for whitelisting an address, probably to fund gas. Allowing EXTSLOAD would harm the oracle business (which is definitely bad). However, looking at the oracle’s business logic the read method loads the slot at location 0x03 which is not recorded in the same block (the read function uses cur feed and not the nxt feed), hence an external untrusted party can provide the oracle feed and proof to a smart contract, which can proceed to utilize the feed for its logic, without paying the oracle maintainer for being whitelisted. But oracles should get funding for gas otherwise it would be a problem. Not sure if it is difficult for open oracles to be economically sustainable through donations or if the whitelist is really worth it.

As a side note, historically an EVM change did hurt businesses e.g. Gas tokens. However, those changes did come with benefits and interest from the community.

1 Like

WOW, Wow, may I ask what stage these proposals have reached now?

Here an example of why it is unsafe.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface Buyer {
  function price() external view returns (uint);
}

contract Shop {
  uint public price = 100;
  bool private isSold;

  function buy() public {
    Buyer _buyer = Buyer(msg.sender);

    if (_buyer.price() >= price && !isSold) {
      isSold = true;
      price = _buyer.price();
    }
  }
}

Here is a modified code from ethernaut.
The catch in this level is that originally the isSold field is public and therefore could be used by the Buyer contract to respond different prices in the two different calls.

Here it is private and still the attack could be possible. The merkle tree can be used to proove a storage but only the initial value of it.

With this instruction many attack vectors will be created.

This contract could query buyer only once, but still many other contracts already in the network would become vulnerable

The last thing we should do is shy away from giving developers options and increasing transparency of contracts because some businesses operating on-chain really on contract-to-contract privacy so they can set up paywalls. Seem antithetical to Ethereum.

Hey Renan but also @deluca-mike I think there is a misunderstanding here how Ethereum state actually works.

The “public” or “private” field markers are only architectural decorators inside Solidity, but in Ethereum all storage is always readable. Please have a look at the documentation and examples of the RPC call getStorageAt JSON-RPC API | ethereum.org

So in your example of price and isSold can be fetched using:

price in the first 0x0 position of the contract:

curl -X POST --data '{"jsonrpc":"2.0", "method": "eth_getStorageAt", "params": ["0x295a70b2de5e3953354a6a8344e616ed314d7251", "0x0000000000000000000000000000000000000000000000000000000000000000", "latest"], "id": 1}' localhost:8545
{"jsonrpc":"2.0","id":1,"result":"0x0000000000000000000000000000000000000000000000000000000000000064"}

isSold in the second 0x1 position of the contract:

curl -X POST --data '{"jsonrpc":"2.0", "method": "eth_getStorageAt", "params": ["0x295a70b2de5e3953354a6a8344e616ed314d7251", "0x0000000000000000000000000000000000000000000000000000000000000001", "latest"], "id": 1}' localhost:8545
{"jsonrpc":"2.0","id":1,"result":"0x0000000000000000000000000000000000000000000000000000000000000000"}

So in fact the keyword private is a false friend as many developers confuse this with meaning it’s not readable from the outside - when in fact anyone can read it using RPC calls - it is just inside Solidity where it’s impossible to access. This is a restriction in Solidity that you don’t have when writing e.g. a python script using RPC calls from the outside. This EIP-2330 is proposing the addition of EXTSLOAD so that this in-equality is fixed and you get the same powers inside Solidity that you have from the outside already.

Cheers!

1 Like

I think that Renan suggested that making isSold private could prevent attacks during EVM execution. However, this might not be effective. Even if isSold is set to private, it’s possible to manipulate the process. An attacker could record the initial price() call and modify the response.

Example of Buyer contract:

contract Buyer {
  bool invoked = false;
  uint price1 = 100;
  uint price2 = 0;

  function price() public returns (uint) {
    if (invoked == false) {
      invoked = true;
      return price1; 
    }
    
    return price2;
  }
}

P.S. The addition of this opcode in the EVM sounds interesting. It would enable practical on-chain checks of transaction execution.

Hey Neburo, this would fail because the buyer.price function is marked as external, so the Shop contract would make an staticcall and would revert if it tryed to store something in storage

hey @dominic , really sorry for the long time,

internal/private are indeed misleading words for state variables in smart contracts,

But as @neburo said, my concern is reading the state of a contract during EVM execution