ethereum / interfaces

Interface Specifications inside Ethereum
36 stars 175 forks source link

Specify blockchain testing methods in RPC #4

Open axic opened 7 years ago

axic commented 7 years ago

With the availability of various test tools, different methods for accomplishing the same testing features were implemented.

cpp-ethereum (complete list):

go-ethereum (complete list and probably outdated here):

It has a lot more under debug.

parity: ?

testrpc:

It would be nice defining a common set implemented by the clients.

axic commented 7 years ago

Similarities:

axic commented 6 years ago

Testeth filling process (for "state tests"):

  1. retrieve client signature (name, version, etc?)
  2. set genesis block
  3. start chain with said genesis
  4. submit 1 (or more) transaction
  5. mine 1 block without proof of work
  6. retrieve state result (state hash and list of all accounts)
axic commented 6 years ago

Some proposals from the call with @karalabe @winsvega @pirapira @cdetrio:

axic commented 6 years ago

Current genesis formats:

axic commented 6 years ago

Current work in progress changes from @winsvega (https://github.com/ethereum/cpp-ethereum/pull/4859):

Also a more detailed list for all the methods porposed by @winsvega: https://github.com/ethereum/retesteth/issues

winsvega commented 6 years ago

the method formats are not final.

pipermerriam commented 6 years ago

We'd like to propose the following spec which I believe is a superset of all if not most of the functionality exposed by the endpoints so far discussed in this issue.

Use cases which are explicitly intended to be supported.

Existing JSON-RPC endpoints

The test_ endpoints would be expected to be used in conjunction with the existing JSON-RPC endpoints, specifically, those in the eth_ namespace, but likely others such as web3_clientVersion. The test_ endpoints allow meta operations which cannot be performed over the traditional JSON-RPC APIs.

Anything like normal transaction sending, reading account balances or storage can and should still be done over the traditional endpoints.

Endpoints

test_resetGenesis

Resets the chain to its genesis state, or the genesis state provided in the JSON-RPC params.

We propose using the format from the BlockchainTest fixtures for the genesis_info. This should also allow specifying of the network parameter.

test_importBlock

Imports the given block to the chain. This does not bypass any chain validation rules so blocks must be valid according to the active fork rules.

We propose block_data be the RLP encoded block as this is unambiguous, and allows for submission of invalid blocks to check that they are rejected.

test_snapshot and test_revert

test_snapshot would perform an exact copy of state and chain databases up to last mined/finalized block, returning an identifier which can be later used with test_revert to revert back to this saved snapshot.

We propose that any pending state like unmined transactions would not be preserved in these operations.

test_mineBlocks

Used for instant block mining. Accepts a list of header overrides (see below) and mines a block for each provided header, bypassing proof-of-work and some other validation checks (see below), allowing for instant on-demand mining.

We propose that the headers be supplied as a list of dictionaries. This endpoint should support the following fields to be overridden.

When provided, timestamp field should bypass normal validation rules to allow for arbitrary modification of newly mined block's timestamps.

Implementations may choose to allow other fields to be overridden.

In addition, we suggest an optional extra parameter to allow newly mined blocks to be properly sealed with proof-of-work via CPU mining. This allows for generation of valid blocks which can later be exported to generate fixture tests.

test_knownAccounts

Returns a list of account addresses which are present in the state database.

The intention behind this endpoint is that while it is possible to check the account state against a known state over the JSON-RPC, if the current account state has extra entries, it will not be possible to discover what they are without the ability to enumerate all account addresses.

test_exportFixture

Returns a BlockchainTest formatted fixture.

karalabe commented 6 years ago

@axic @winsvega we've been discussing the above interface with @pipermerriam yesterday. This spec doesn't allow concurrent chains and does overwrite the current chain of the node (so it requires a custom flag to start). The benefit however is that it reuses the same RPC interface as everything else uses. That might be a good idea long term since we would have constant regression tests against the RPC, opposed to testing via an isolated API.

I'd still like to retain some ability to run potentially multiple chains in the same binary. Perhaps we could add some form of test_startChain / test_stopChain which configures a new in-memory testing instance and also opens up new RPC interfaces for it. That would allow us to retain the exact same functionality RPC wise but still support multiple concurrent tests. Not sure exactly how much work that would involve, just dropping it as an idea.

winsvega commented 6 years ago

Speaking of different chains. Another way is to start two instances of a client with different configs and ask one client to provide a block then import it into another. But this could be done within one instance with chain index of some kind. (guess its harder to implement)

I am currently fixing existing state tests and developing a minimum set of rpc methods required to fill a state test. the state test format will be slightly changed. some fields from env section might not be needed.

after this I plan to rework blockchain test filling through RPC.

karalabe commented 6 years ago

The issue with starting instances is the long boot time. Maybe it's "just" 2-3 seconds, but if you want to run repeating tests, those will add up. Would be imho nicer not to have to spin up entire processes all the time.

The only two options I see it is:

A further problem with starting multiple processes is that then you either start a new process for each test to make it clean (but that's what hive does already, so there's no point); or you make some chain run in the host process and start secondary chains in new processes, but that will just be a sync/setup nightmare. I think we need to handle all test chains uniformly, so either all in the same process, or all in separate processes.

My fav for now is launching RPC endpoints.

winsvega commented 6 years ago

I was thinking to start different RPC. so multiple clients with multiple RPC sockets at the same time running tests in paralel. A setChainParams called once per test. if the config is not changed then rewindBlock method is used to disable transactions.

There should be options to optimize it. like use memoryDB for chain. starting the chain faster. cpp client has like 1-2 sec delay.

We have hive, but we don't have testeth anymore.

folsen commented 6 years ago

In Parity this isn't really how we do testing at all, which is why we don't have any test RPCs what-so-ever yet. I think the main worry from us is exposing test-stuff to the mainnet, so we'd probably try to hide these behind a compiler-flag so the default build doesn't include it at all.

The question then beyond that is just what we can do without significantly changing the codebase. We don't really want to code in a backdoor to skip block validation unless we can be 100% sure it can be excluded or at least isolated in such a way that we can guarantee that it can't be exploited.

Asked @tomusdrw about this and his off-the-top-of-his-head response was:

test_knownAccounts <- requires fat db test_exportFixture <- the format is pretty complex, might require some db-level capturing test_mineBlock <- means that we create some fake block without PoW and then disable seal checking in the entire client? test_snapshot <- seems fine test_revert <- will be troublesome in terms of caches test_resetGenesis <- nightmarish, since we load genesis state in constructors

With the additional comment that resetGenesis could probably just be done by restarting the client. There was even the idea floated to implement this by having a completely separate binary that just talks to parity to provide the abstraction layer (some stuff would probably still have to be added to parity itself).

This is all sort of speculation though until we actually try to do it.

gnidan commented 6 years ago

(cc @benjamincburns @seesemichaelj: we should follow along here for Ganache)