Skip to content
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

RFC: API method eth_watchCall #781

Closed
recmo opened this issue Nov 30, 2017 · 6 comments
Closed

RFC: API method eth_watchCall #781

recmo opened this issue Nov 30, 2017 · 6 comments
Labels

Comments

@recmo
Copy link
Contributor

recmo commented Nov 30, 2017

I propose an API for registering any view function call for monitoring. Whenever the value of the function call changes, the client is notified. Much like registering for log events.

Rationale: This functionality can be implemented efficiently. There are use cases for monitoring contracts for changes. Events cover this, but are not available when the need to monitor is discovered after deployment or by a third party.

Suggested Implementation:

  • On registration:

    1. execute the function as if it was a STATICCALL (see limitations).
    2. Trace and remember all the storage locations accessed with SLOAD.
  • When a new block arrives:

    1. Diff the Patricia trees to find altered storage locations.
    2. Find functions whose storage access is altered.
    3. Re-evaluate only those functions and compare for changes.
    4. Re-register those functions (as SLOAD locations may depend on other state).

Step 1 and 2 can be done fast and in time constant in the number of functions to monitor. Further steps are only executed for functions with a reasonable chance of being changed. False negatives are impossible. I expect false positive to be rare, but would love to see counterexamples.

Examples:

  • Register balanceOf(my_address) on a token contract that does not do implements appropriate events.

Limitations: The semantics of the function call to monitor are similar to that of STATICCALL, with the additional restriction that non-deterministic opcodes (BLOCKHASH, COINBASE, …) are also disallowed. (Alternatively, they could be allowed at a risk of false negatives.)

Potential extensions: Instead of an existing view method of the contract, any arbitrary piece of EVM code can be provided to be executed in the context of a given contract and monitored for changes.

@recmo recmo changed the title RFC: API method eth_watchView RFC: API method eth_watchCall Nov 30, 2017
@karalabe
Copy link
Member

Geth 1.8 (not yet released) has a debug.getModifiedAccountsByHash/Number API endpoint that can produce a list of accounts modified by a block (ethereum/go-ethereum#15512). It is based on state diffs as you suggested.

An important limitation of this approach however is that it cannot detect modifications that change a storage slot, and than change it back to its original value in the same block (e.g. either by the same transaction, subcalls, or even multiple transactions in the same block).

This is imho a problem from your perspective as it can result in modifications not being detected within a block.

@fabioberger
Copy link

fabioberger commented Apr 27, 2018

@karalabe thanks for linking to those RPC endpoints. Indeed the way it's implemented is similar to @recmo's suggestion. Unlike this RFC however, they only give account level granularity, not individual state change granularity.

I think it's important to plainly state the problem eth_watchCall is trying to solve:

Smart contract events != State changes

Currently Ethereum developers are expected to subscribe to smart contract events if they wish to be notified about a state change. This is inherently unreliable since events are merely proxies for the underlying state change, not emitted by the state change itself. This is not good enough for financial applications which require a very high degree of reliability.

Example: a 0x relayer wants to prune their orderbook of orders that become invalid. Many on-chain state changes can cause an order to become invalid.

order_state_deps

For a given 0x order, a relayer would like to watch for state changes to the order maker's balances and allowances of various tokens. This is currently not 100% possible with events (e.g ERC20 standard does not enforce TransferFrom events when tokens are minted/burned). If they could watch the maker's balance/allowance directly, it doesn't matter how a developer decides to implement their smart contract, either the balance/allowance changed or it didn't. The only way to currently do this is through polling over RPC which does not scale.

Apropos the limitation of not picking up intermediate state changes that occur within a block, I do not see this as an issue in many use-cases. In a lot of applications (including the relayer example above) what matters is the state of the world after a new blocks inclusion. I could see it being an issue in certain reporting use-cases, but this proposal remains a hugely valuable alternative to event watching for many applications requiring a high degree of reliability and performance.

@tjayrush
Copy link

For applications such as the ones we are working on (QuickBlocks), watching for events is inadequate. If you're trying to fully audit an Ethereum address, you need to watch everything. debug.getModifiedAccountsByHash/Number is okay (it's much better than what's available now), but what's really needed is debug.getInvolvedAccountsByHash/Number.

An example of where an address is 'involved' but does have its state modified is being involved in a token mint. Token mints modify the state of the token contract, not the address being granted ownership. If you're accounting for the recipient (the account being granted ownership) this will be missed with getModified... because that would hit on the token address which you're not watching.

@recmo
Copy link
Contributor Author

recmo commented May 10, 2018

@karalabe

Consider a popular ERC20 contract such as WETH. Assume for the moment that the WETH implementer forgot to include events. Let's say I have three accounts that I want to monitor the WETH balance of. I want to avoid calling balanceOf for all addresses after every block.

Monitoring the three addresses with getModifiedAccountsByHash has many false negatives. If someone sends me WETH, the state related to my account won't change. Neither will it change if some sends from these accounts using an allowance. In fact, it only works if the accounts transfer WETH directly. There is no good way to catch these false negatives, rendering this approach incorrect.

Ok, so obviously what is happening is that the state we are interested in is stored in WETH, so we need to monitor the WETH address with getModifiedAccountsByHash. This approach has many false positives. Any change of balances for any account will trigger a change in WETH. And these happen pretty much every block. So we will be calling balanceOf after every block anyway.

Any API needs to be agnostic to the internal workings of the smart contract. For example, it can not assume that an ERC20 contract stores a particular balance in a particular storage location. The method proposed above is agnostic, and should give accurate results without false negatives in many common cases.

As it stands, the proposal pushes most of the work to Geth. This should give better performance as false positives are filtered closer to the source. The proposal can be modified to move most of the heavy lifting to the caller. For that you would need something like "watchStorageSlots" instead. The client can then do most of the work.

@github-actions
Copy link

There has been no activity on this issue for two months. It will be closed in a week if no further activity occurs. If you would like to move this EIP forward, please respond to any outstanding feedback or add a comment indicating that you have addressed all required feedback and are ready for a review.

@github-actions github-actions bot added the stale label Dec 19, 2021
@github-actions
Copy link

github-actions bot commented Jan 2, 2022

This issue was closed due to inactivity. If you are still pursuing it, feel free to reopen it and respond to any feedback or request a review in a comment.

@github-actions github-actions bot closed this as completed Jan 2, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants