Prototyping a Mina Blockchain Explorer
Since writing this post, Coda has rebranded to Mina Protocol. I’ve left the article in its original form but all references to Coda are equivalent to Mina.
If you are unfamiliar with the Coda protocol or the Coda GraphQL API see my previous article for an overview.
A block explorer is a tool typically used to visualise the current and historical state of a blockchain including all transaction information. Coda, a succinct blockchain, presents some interesting challenges in this regard as this prior state information is not required to be stored by end-users or even block producers, but rather the protocol relies on cryptographic proofs to prove the current chain state (and thus everything preceding it).
Coda currently provides an option for users to run an archive node that persists block data. This data is then exportable via the GraphQL API and it is this data that has been used to produce a prototype block explorer to help users become better acquainted with the testnet and Coda’s functionality.
The homepage of the explorer provides summary information as to the current state of the blockchain together with the latest blocks received. The homepage also allows users to search via public key or a block state hash.
On the current testnet, blocks are produced in a slot that is five minutes in duration (though not every slot has a block and some slots have more than one block proposed). Each block has a block producer, chosen via a proof-of-stake mechanism, who are responsible for proposing blocks comprising transactions currently in the transaction pool.
Each block may have zero or more transactions, which are simple transfers between two accounts. Each block may also contain zero or more SNARK jobs, comprising the work completed by SNARK producers in generating the proofs to compress the transaction data to a single proof. SNARK producers are paid by the block producer for completing this work with the block producers receiving transaction fees along with the coinbase transaction.
Developing the prototype
The explorer was developed as a simple Flask app using the Coda Python client. The basic front-end is an edited version of a Bootstrap template. While initially developed exclusively using the Coda GraphQL API it now persists the blocks data it receives through the GraphQL API to MongoDB. This allows for more efficient queries (more later) and means the data isn’t lost if the node is unrecoverable.
The explorer is still very experimental and brittle, not least as it is currently dependent on the Coda daemon to be running.
Some further views available via the explorer include details for each block:
The wallet page details all historical transactions for a wallet, as well as the current state of the wallet. The state of the wallet is provided directly from the GraphQL API as this account state is required to be stored for block-producing nodes, whereas the transaction data is obtained from the persisted database as this would typically be eventually dropped.
As well as incoming and outgoing payments, this wallet also demonstrates a pending transaction that is in the transaction pool but not yet been included in a block by a block producer.
Limitations of the current GraphQL API
With the knowledge that the GraphQL is still very much in active development and there are plans to make client data storage easier a few areas caused issues during development:
- Blocks are returned in an inconsistent order, so taking the last x blocks isn’t as simple as returning the last items in a list. Blocks need to be ordered by date, which is very deeply nested within the returned blocks data:
data["blocks"]["nodes"]["protocolState"]["blockchainState"]["date"]
- There is very primitive filtering available for the blocks query. While there are arguments for
first
andlast
they don’t behave as you would expect. This presents a major challenge as pretty much every operation involves taking the entire block data and then filtering locally. This, of course, becomes progressively worse over time and slow even for a chain of fewer than 1000 blocks. - Memo data is returned as a base58 encoded string that needs to be parsed by the client. Additionally, it is currently padded and some other characters that require some hacks as below to parse. Simply returning this as a (UTF-8) formatted string would simplify this implementation detail.
Persisting data with MongoDB
To overcome most of these limitations, rather than rely on the GraphQL API the block data is persisted to a MongoDB instance. Now, for example, to determine any transaction that contained the “Hello World” memo, rather than loop through every transaction the node has seen, the following sample query can be used:
Similar queries can be used to extract individual block state hashes or transactions involving a public key. It also allows simple sorting based on the block timestamp data, which means only the blocks required need to be returned, which improves performance dramatically even at this small scale.
Known issues with the explorer
The first image of the explorer homepage shows that Blocks Seen by Node exceeds the Blockchain Length indicating that all blocks are being stored regardless if they are on the longest chain. Multiple blocks are frequently proposed for the same slot, and the winner is decided upon via consensus. The explorer needs to be updated to remove, or otherwise indicate, blocks not on the current chain.
Next Steps
- The front-end of the explorer currently requires a manual refresh to load the latest blocks. In addition, in the backend, blocks are loaded into MongoDB on a fixed interval (with the block hash as a unique index to prevent duplicates). To improve this, Coda provides a
newBlock
GraphQL subscription type. This event can be used to update the MongoDB datastore in addition to updating the frontend in realtime. - As the block data is stored in the format it is received, it is trivial to create a simple API to export filtered block data for those wishing to experiment on the testnet and potentially fill missing block data of other nodes taking a similar approach.
- Add some tooltips to explain some key terminology of Coda for educating new users (and myself).
- Update the wallet page to display completed SNARK jobs and block production for a public key.
- Add the ability to search for the transaction status of a payment id. This method of the GraphQL API is currently absent from the Coda Python library but a simple addition.
- Update the UI particularly relating to the pagination of results, so more block data can be easily browsed.
Finally, the hope is to include some more visual feedback for all testnet challenges on an ongoing basis. For example, users who have completed the current “Hello Memo” challenge are shown below. Note that this page is provided for reference only and results are determined by the Coda team using their nodes which may have seen a differing number of blocks.