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

Stateless execution prototype #556

Closed
wants to merge 15 commits into from
Closed

Stateless execution prototype #556

wants to merge 15 commits into from

Conversation

s1na
Copy link
Contributor

@s1na s1na commented Jul 23, 2019

The goal of this PR is to prototype something akin to the stateless client concept. There are two "roles":

  • Verifier a light-client who wishes to process a future tx/block, but only has access to the current state root, and stores none of the actual state.
  • Prover a full-node who runs a tx/block and generates all the necessary merkle proofs for the verifier to execute the tx. This includes proofs for accounts that were read during execution, codes for executed contracts and proofs for contract storage keys that were read.

The prover currently works by hooking the StateManager and generating proofs on invocation of getAccount, getContractCode and getContractStorage.

The verifier currently works by storing all received trie nodes in a new trie's db (with their hashes as keys), and using that trie in a new StateManager, and then running the tx.

To test this, I'm running the GeneralStateTests suite, running each case twice. Once to generate all the proofs, and a second time to test the verifier given proofs generated during the first run. There are still some edge cases that need to be fixed (38 cases are failing).

This also depends on a merkle-patricia-tree release (specifically ethereumjs/merkle-patricia-tree#82, and probably ethereumjs/merkle-patricia-tree#94).

@s1na s1na changed the title Stateless execution prototype [WIP] Stateless execution prototype Jul 23, 2019
@lgtm-com
Copy link

lgtm-com bot commented Jul 23, 2019

This pull request introduces 1 alert when merging 8da663a into 4bbb6e3 - view on LGTM.com

new alerts:

  • 1 for Unused variable, import, function or class

@lgtm-com
Copy link

lgtm-com bot commented Jul 24, 2019

This pull request introduces 4 alerts when merging 5b309b5 into 4bbb6e3 - view on LGTM.com

new alerts:

  • 4 for Unused variable, import, function or class

@coveralls
Copy link

coveralls commented Jul 24, 2019

Coverage Status

Coverage remained the same at 95.087% when pulling deda4cc on stateless into 4bbb6e3 on master.

@s1na
Copy link
Contributor Author

s1na commented Jul 24, 2019

It turns out my initial approach was overly complicated and prone to edge cases. I managed to bring down the initial ~600 failing test cases to 18, but then realized there's a better approach:

Instead of hooking StateManager's methods (e.g. getAccount), we directly hook the underlying leveldb.get. The intuition is that every piece of state is stored in the db (e.g. accounts, contract codes, contract storage items) as a Buffer, with its keccak256 hash as the key. So every time the EVM tries to fetch something from the db, if that item existed in the db before starting the transaction, necessarily the verifier would need that item. Items that did not exist before starting the transaction have been created during the tx, and the verifier could re-create them on its own.

The prover then collects all the pre-existing state items fetched from the db and sends them to verifier. The verifier saves all of these items in a new leveldb with their keccak256 hash as key, and instantiates a Trie which uses this db and has the preStateRoot (correct state root prior to exeucting this tx) as root, and then runs the tx normally.

@s1na
Copy link
Contributor Author

s1na commented Jul 24, 2019

Currently all of the above is happening in the StatelessRunner test runner. I'm now wondering if we should add this feature to the library and if so what would be the best API. @holgerd77 @alcuadrado Any comments?

One option I can think of is to have a ProofGeneratingVM which does the hooking, and additionally returns all the proofs on runTx and runBlock; and a StatelessVM which should be instantiated with the proofs and then can do runTx and runBlock normally.

@holgerd77
Copy link
Member

@s1na My understanding of the whole process structure is still limited, but my first impression is that it makes very much sense to add some experimental API on this and therefore integrate as a feature.

Would these two new VM classes subclasses of the VM class?

@s1na
Copy link
Contributor Author

s1na commented Jul 25, 2019

Would these two new VM classes subclasses of the VM class?

Yeah probably. It's also possible to have a simpler API for now. For example a proveTx(vm, txOpts), and verifyStatelessTx(txOpts, proofs). Though I think sub-classing VM (at least for the verifying side) is more flexible and unlocks more use-cases.

@holgerd77
Copy link
Member

Yeah, let's do the subclassing. This is really inviting for experimentation, and can't hurt if we clearly mark this as experimental.

@holgerd77
Copy link
Member

Just to get a bit up-to-date: what's your plan on this? Do you want to get this out with v4.1?

@s1na
Copy link
Contributor Author

s1na commented Aug 8, 2019

I was testing the logic a bit more last week. I think I can get something ready for v4.1.

@evertonfraga evertonfraga changed the title [WIP] Stateless execution prototype Stateless execution prototype Jun 30, 2020
@evertonfraga evertonfraga marked this pull request as draft June 30, 2020 22:00
@codecov
Copy link

codecov bot commented Aug 15, 2020

Codecov Report

Merging #556 into master will increase coverage by 5.58%.
The diff coverage is n/a.

Impacted file tree graph

Flag Coverage Δ
#account 92.85% <ø> (ø)
#block 79.31% <ø> (ø)
#blockchain 82.88% <ø> (ø)
#common 94.14% <ø> (+0.15%) ⬆️
#ethash 81.93% <ø> (ø)
#tx 94.02% <ø> (ø)
#vm 92.49% <ø> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

@holgerd77
Copy link
Member

Rebased this, adopted this to the monorepo structure and updated the code to play well with changes within the test environment and directly use async functionality in several cases, so that test runs can now be executed again with npm run test:stateless.

Core logic itself needs still to be adopted.

@s1na
Copy link
Contributor Author

s1na commented Aug 17, 2020

@holgerd77 Thanks for updating it! I was just reading the thread and I'm thinking maybe as a first approach just merge this as a test runner so we can come up with a way of integrating it into the library? Potentially we could move the stateless logic to a package under the monorepo which depends on the VM.

In that case I'll have to look and see what's missing, if all tests pass etc. I don't remember what was the status of the PR last time I worked on it.

@holgerd77
Copy link
Member

@s1na Thanks, I was assuming we would be following this VM subclassing approach as discussed initially, but open for other ways of structural integration as well. Think there were some last test cases not working yet.

// Determine set of all node hashes in the database
// before running the tx.
const existingKeys = new Set()
const it = stateManager._trie.db.iterator()
Copy link
Member

@holgerd77 holgerd77 Aug 17, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you also give me a hint where this iterator() might have moved to? This was errored as not available when I last ran the code, got stock there to some extend.

Copy link
Contributor Author

@s1na s1na Aug 17, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was possibly a local change, can't find an iterator method in MPT too. Levelup has an iterator method which I probably used. Maybe just replacing that line with stateManager._trie.db._leveldb.iterator() would work.

Update: I don't seem to be the handling values, only keys. So maybe ..._leveldb.iterator({ keys: true, values: false })

Co-authored-by: Ryan Ghods <ryan@ryanio.com>
@acolytec3
Copy link
Contributor

Is there value in keeping this PR open now that we're looking towards verkle tries as the way forward on stateless execution?

@holgerd77
Copy link
Member

Yeah, let's maybe keep at least a bit more open. I've the impression we are still extremely early with our own efforts and this might serve and some point of reference and/or inspiration. Once we are a bit further down the road and can judge better on the efforts made here we can close.

@holgerd77
Copy link
Member

One of the most interesting experiments being run during the history of this repository and far ahead of its time. ⭐

Nevertheless getting a bit outdated. 😂

Will close. 🙂

@holgerd77 holgerd77 closed this Feb 20, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants