Skip to content

Statediffing Geth code changes

Connor Mendenhall edited this page Dec 22, 2021 · 3 revisions

This page describes the core changes to Geth to enable statediff subscriptions that we maintain in the https://github.com/makerdao/go-ethereum/ repository. Our changes are relatively minimal: a few hundred lines of code, plus tests and some configuration changes. These changes fall into the following categories:

  • Changes to the state DB to return storage diffs.
  • Changes to the blockchain to add a storage diff event feed.
  • Changes that enable RPC subscriptions to the storage diff event feed.
  • Cascading changes due to the modified state DB interface.
  • Tests and configuration changes.

State DB changes

The central change in our fork is a modification to core/state/statedb.go that returns an extra StateChanges value from calls to statedb.Commit. The state DB implementation is deep in the internals of Geth, and fortunately has not proven to change very frequently. The extra return value from statedb.Commit cascades to other calls to this method in other areas of the codebase, but in most cases the value can be ignored.

Files:

  • core/state/statedb.go: Calculate and return a StateChanges map from calls to Commit.
  • core/state/stateobject.go: Add a diffStorage attribute to the StateObject struct.
  • core/state/statedb_test.go: Additional tests for our changes, plus cascading changes from the change to the statedb.Commit return values.

Blockchain changes

We add an additional event.Feed called stateChangeEventFeed in core/blockchain.go, similar to the existing event.Feed entries for logs and blocks. In addition, we add a SubscribeStateChangeEvent method to subscribe to state change events.

Files:

RPC subscription + filters

Adding an RPC subscription and filter query requires changing a number of files, but the pattern here is exactly the same implementation as filter queries for event logs: create a subscription, create a filter query, and expose these through the client interface.

Files:

  • core/events.go: Add StateChangeEvent.
  • eth/api_backend.go: Add SubscribeStateChangeEvent to subscribe to state diff events. (Same pattern as log subscriptions).
  • internal/ethapi/backend.go: Register state change subscription.
  • eth/filters/api.go: Add a filter for state change subscriptions. Like logs, this accepts specific contract addresses to filter and maintains the same API as log filter queries.
  • eth/filters/filter.go: Register the statediff subscription.
  • eth/filters/filter_system.go: Add state change payloads to subscription struct, add handler for state change events. Update usage of subscription struct to include state change payloads.
  • eth/filters/filter_system_test.go: Add tests for state change subscriptions.
  • eth/filters/statediff.go: Add custom statediff filter.
  • ethclient/ethclient.go: Expose statediff subscription in client interface.
  • light/lightchain.go: Expose statediff subscription in client interface.
  • les/api_backend.go: Expose statediff subscription in client interface.
  • accounts/abi/bind/backends/simulated.go: Expose statediff subscription in client interface.

Cascading changes

The updated state DB Commit return value cascades to a few additional places in the codebase. In each of these, we ignore the additional arg. Here's an example.

Files:

  • cmd/evm/internal/t8ntool/execution.go
  • core/chain_makers.go
  • core/state/state_test.go
  • core/state/sync_test.go
  • eth/state_accessor.go
  • tests/state_test_util.go

Configuration changes

  • Add a Docker compose and github workflow to smoke test diff subscriptions
  • Remove builders from .travis.yml (We don't need to build official images and cannot push them to the geth Docker hub)
  • Update a config parameter in rpc/client_test.go