question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Database architecture refactor: Adapters and Wrappers

See original GitHub issue

Replaces https://github.com/ethereum/py-evm/issues/410

What is wrong?

The current architecture uses a single global ChainDB for each chain.

This is proving problematic because:

  • The ChainDB is not aware of different VM rules and thus cannot have it’s underlying business logic modified.
  • Some of the network syncing code needs to interact with the database in ways that aren’t currently supported. See #337
  • It has a lot of API surface area.

How can it be fixed

First, we establish the following new terminology.

  • Connection: The base database class used to connect to the underlying db. e.g. MemoryDB or the LevelDB. This object is treated as a key/value store.
  • Wrapper: A class which wraps a connection, adding some extra functionality. e.g. JournalDB, HashTrie
  • Adapter: A class which implements a high level API over top of an underlying database.

We also establish a new convention/rule regarding the APIs exposed by wrappers. Wrapper APIs may only be used at the same level that the wrapper is applied.

For Example:

Suppose the VM class applies the JournalDB wrapper to the database connection, and then passes the resulting object down to the VMState. The VMState is not allowed to interact with any of the APIs exposed by the JournalDB.

Now, we establish the following new Adapter classes.

  • MetadataDB:
    • Only deals with chain metadata (e.g. canonical head, mapping block numbers to canonical block hashes, mapping transaction hashes to canonical block hash in which it was mined).
    • Used by the Chain class.
    • Lets look into using SQLAlchemy + sqlite3 for storage of this data.
  • ChainDB:
    • Deals with storage of chain data (e.g. blocks, transactions, receipts)
    • Lets look into using SQLAlchemy + sqlite3 for storage of this data.
    • Each VM may specify their own ChainDB class.
  • AccountDB:
    • Replaces evm.db.state.AccountStateDB
    • Deals with VM state (e.g. account balances, nonces, storage, code)
    • each VMState may specify their own AccountDB class.

So, responsibility for databases is as follows.

  • Chain -> MetadataDB (replaces what we currently refer to as ChainDB
  • VM -> ChainDB (not to be confused with the existing ChainDB
  • VMState -> AccountDB (replaces the current AccountStateDB

With this structure in place, now we explore how wrappers come into play. Each level of the call stack will pass down it’s base database which might be the actual base connection, or might be a wrapped version of the base connection. Everything is to assume that the db object it receives only exposes the base database API.

In the event that a database connection needs to be wrapped, it should occur at the level at which the wrapper APIs will be used.

For example:

  • the AccountDB should be responsible for applying the HashTrie wrapper.
  • the VMState should be responsible for applying the JournalDB wrapper.

Issue Analytics

  • State:open
  • Created 5 years ago
  • Reactions:4
  • Comments:7 (5 by maintainers)

github_iconTop GitHub Comments

1reaction
carvercommented, Apr 13, 2018

Just checking in to say I’m reviewing this now. It’s probably going to be a little while before there’s new code, because I’m still piecing everything together. The direction outlined above looks solid.

I’m also interested in seeing how we can reduce the mutability of things further – specifics TBD.

I’m going to keep digging into designs offline with whiteboards and other contributors, and report back here with major updates.

1reaction
pipermerriamcommented, Apr 2, 2018

@carver assigned to you merely to suggest tackling this when you start into this codebase.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Adapter - Refactoring.Guru
An adapter wraps one of the objects to hide the complexity of conversion happening behind ... Structure of the Adapter design pattern (the...
Read more >
Introducing Clean Architecture by refactoring a Go project
My refactoring moved database-related code in trainings to a separate structure. Separating Ports and Adapters. Ports and Adapters can be called ...
Read more >
Hexagonal Architecture by example - a hands-on introduction
Outbound adapters handle outgoing traffic (e.g. database requests or messages sent to a broker) and decouple core from implementation details ( ...
Read more >
Ports & Adapters Architecture - @hgraca
The Ports & Adapters Architecture (aka Hexagonal Architecture) was thought of by Alistair Cockburn and written down on his blog in 2005.
Read more >
Refactoring to the Adapter Pattern - Techie Thoughts
Adapter lets classes work together that couldn't otherwise because of incompatible interfaces. Wrap an existing class with a new interface.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found