Code Monkey home page Code Monkey logo

juno's Introduction

Juno

banner

GitHub Workflow Status Go Report Card GitHub tag (latest SemVer)

Juno is a Cosmos Hub blockchain data aggregator and exporter that provides the ability for developers and clients to query for indexed chain data.

Table of Contents

Background

This version of Juno is a fork of FissionLabs's Juno.

The main reason behind the fork what to improve the original project by:

  1. allowing different databases types as data storage spaces;
  2. creating a highly modular code that allows for easy customization.

We achieved the first objective by supporting both PostgreSQL and MongoDB. We also reviewed the code design by using a database interface so that you can implement whatever database backend you prefer most.

On the other hand, to achieve a highly modular code, we implemented extension points through the worker.RegisterBlockHandler, worker.RegisterTxHandler and worker.RegisterMsgHandler methods. You can use those to extend the default working of the code (which simply parses and saves the data on the database) with whatever operation you want.

Compatibility table

Since the Cosmos SDK has evolved a lot, we have different versions of Juno available.

Cosmos SDK Version Juno branch
v0.43.x, v0.44.x, v0.45.1 cosmos/v0.44.x
v0.45.x cosmos/v0.45.x
v0.46.x cosmos/v0.46.x
v0.47.x cosmos/v0.47.x
v0.50.x cosmos/v0.50.x

Usage

To know how to setup and run Juno, please refer to the docs folder.

Testing

If you want to test the code, you can do so by running

$ make test-unit

Note: Requires Docker.

This will:

  1. Create a Docker container running a PostgreSQL database.
  2. Run all the tests using that database as support.

GraphQL integration

If you want to know how to run a GraphQL server that allows to expose the parsed data, please refer to the following guides:

Contributing

Contributions are welcome! Please open an Issues or Pull Request for any changes.

License

CCC0 1.0 Universal

juno's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

juno's Issues

gRPC timeout blocked context

Bug description

The chain may not respond when the resource is not ready. If you don't set a timeout to context, the context would possibly block forever.
Therefore, the parsing stops.

Steps to reproduce

Parse the latest block with only parse missing block option.

Expected behavior

The system should retry when there is a timeout.

Implementation Proposal

At https://github.com/forbole/juno/blob/3b5d944a0def1b47ae695422748c63d263833779/node/remote/node.go
It should set Exponential backoff for timeout and use a new context every time when the chain node grpc endpoint is called
Example:

ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
transaction, err := cp.flowClient.GetTransaction(ctx, txID)
cancel()

Juno keeps missing blocks without logging and enqueuing again

We keep experiencing miss blocks and those blocks were not logged and enqueued again meaning that those blocks were not in the queue from the beginning.

As new blocks are all enqueued to the worker's queue by listening NewBlock event, it is suspected that blocks will be not enqueued correctly if the node is not responding properly and the Tendermint event is not broadcasted correctly.

Can this be refactored so that JUNO optimistically enqueues all blocks not exist in the database? For example, if the largest block height in the database is H, and the latest block height on chain is H+10, it enqueues H+1 to H+10 in the queue without listening to the websocket event?

Bad handshake with Stargate

Description

As reported inside forbole/callisto#55, Juno seems to not work when trying to connect to Stargate.

Branch

cosmos-v0.39.x

Configuration

rpc_node = "http://rpc.stargate.bigdipper.live:80"
client_node = "http://api.stargate.bigdipper.live:443"

Log

{"level":"debug","time":"2020-10-08T09:28:50+02:00","message":"Reading config file"}
ERROR: websocket: bad handshake: failed to start RPC client

Replaces `involved_addresses` with JSONB queries inside `message` table

Feature description

Currently when parsing a message we put all the involved accounts addresses inside the involved_addresses column. This later allows to query the transactions inside which a specific account is involved. Although this works, there is a better way to allow such searches: search directly inside the raw JSON value of a message.

Implementation proposal

To do this, we could try:

  1. using GIN indexes to index the raw message value;
  2. using JSON operators.

Another alternative is to read the message value as a TEXT and then using the LIKE operator:

SELECT * FROM message WHERE (SELECT CAST(message AS TEXT) LIKE "%address%")

Allow to read the genesis from a file

Feature description

Currently the genesis file is retrieved from Tendermint using the /genesis endpoint. However, it is know that for Tendermint v0.34.x and previous this endpoint crashes if the genesis is too large (see tendermint/tendermint#6706). To fix this, we could allow the developers to parse a genesis file instead, so that if the chain starts with a very large genesis Juno is still able to read it without making the node crash.

Implementation proposal

Add a new genesis_file_path field inside the [parser] section, so that if it's not empty it represents the file from which to read the genesis instead of using the endpoint.

Update Cosmos to v0.40

Since the next Cosmos version has been released, we should update it to make sure that we can use Juno with any Stargate-ready testnet.

Allow modules to handle BeginBlock and EndBlock events

Feature description

Currently there is no way for modules to correctly handle BeginBlock and EndBlock events. This should be fixed in order to allow a better handling in the case of events that are not emitted by actions performed by the users (eg. slashing, rewards distribution, etc).

Implementation proposal

We can define a new interface:

type BlockEventsModule interface {
  HandleEvents(height int64, txsResults []ResponseDeliverTx, beginBlockEvents, endBlockEvents []abci.Event) error
}

Then, while parsing each block, we call the client.BlockResults module in order to get the info, and then we pass it to each module.

Allows a custom websocket address to be specified

Feature description

Currently the websocket endpoint is computed as <rpc.address>/websocket, however this might be reductive for some cases where people want to specify a custom websocket endpoint.

Implementation proposal

We can add a new field to the rpc section:

[rpc]
addres = ""
websocket = ""

If websocket is specified, use that one. Otherwise, use rpc.address/websocket as the websocket endpoint.

Better handle data de-serialization for custom chains

Feature description

Currently in order to properly parse the transaction messages, Juno de-serializes the data using the Cosmos SDK types, particularly the sdk.Msg interface. Although this works, it requires a lot of work when dealing with custom chains: to properly deserialize an sdk.Msg instance, the various implementations must be registered within the used codec instance. This often requires Juno to be forked and use the custom chain code as a dependency (since sdk.Msg instances are registered in the provided codec instance there). This makes it hard to maintain future versions of Juno, since more and more chains will most likely use their custom messages and thus more and more forks need to be created.

Implementation proposal

To fix this issue, we can attempt defining our own Transaction and Message instance with custom de-serialization. Such instances should contain only the values that we are interested in reading for our purposes, and nothing more. Then, we leave the various modules with the burden of de-serializing the original transaction/message bytes to whatever type they want if needed.

Failed to find validator by commit validator address desmosvalcons....

Bug description

Juno fails to store the block signatures and throws this error when the validator set size is larger than 100
re-enqueueing failed block err="failed to find validator by commit validator address desmosvalcons1wdw3n55z0ztfer2yw6rjtnyme7h54yu6qe75m7"

Steps to reproduce

Expected behavior

Enqueue stop at the block height that start juno

Bug description

for i := cfg.StartHeight; i <= latestBlockHeight; i++ {

Enqueue missing height stop at latestBlockHeight, which would not change when the loop start. So the loop stops after a while where i=latestBlockHeight
And when you call enqueueNewBlocks there may be a gap between latestBlockHeight and block height so there are missing blocks

Expected behavior

It should parse forever at that loop. Implementing suitable retry and timeout of node endpoint would also solve the problem.

Add block time to block table

Currently when storing a new block, we save the block timestamp only. However, some applications might want to get the block time as well. For this reason, we need to add a row computing the time as follows:

  • if no blocks exist, use the genesis time to compute the block time
  • if a previous block exists, use that block's timestamp to compute the block time

References forbole/callisto#39

Why fetching transactions when we have access to all the information in the block

Hello,
I have a question concerning the ingestion service.

In the following line:

res, err := cp.txServiceClient.GetTx(context.Background(), &tx.GetTxRequest{Hash: hash})

It is making an RPC request for every transaction in a block. However, I guess that we have access to all that information in the Block structure itself:
https://github.com/tendermint/tendermint/blob/a185163c5779faaaea9ea29c7c8626c7d26295ca/rpc/coretypes/responses.go#L50

The reason I am asking these questions is that I am having performance issues with Juno. It is slow and not able to follow up with the chain I am targeting: https://celestia.observer/
Currently, it is missing more than 18000 block...

Thanks,

The future of this project

Context

In the last days me and @angelorc have been working on this fork of Alexander's original Juno . The main differences between this tool and the original one are the following:

  • Support for multiple database drivers (PostgreSQL and MongoDB)
  • Easy customizazion thanks to the RegisterBlockHandler, RegisterTxHandler and RegisterMsgHandler methods

Aside from those features, this parser allows to get and store the following data of a Cosmos SDK chain:

  • Blocks
  • Transactions
  • Pre commits
  • Validators

GraphQL

The next idea me and Angelo had was to implement a Go-based GraphQL server so that with a single executable we could have started either the parser (juno parse) or the GQL server (juno start-gql).

Unfortunately, we've discovered that this might be a lot more complicated that it sounds like and could cost a lot of time. To overcome this problem, Angelo found some useful tools that might help us auto-generate a GraphQL server.

I've also asked Alexander an opinion and he said that if he would have to do it, he would use a generator (as he did with GaiaQL) to avoid having to do the heavy work.

So far, the best tools we have found are the following:

  • Mongoke, a tool that generates a custom GraphQL server based on a Mongo database.
  • Hasura, a tools that connects a PostgreSQL database and generates a GraphQL backend (this is the one used by GaiaQL)

Now, we need to decide what to do next. Our options are the following.

  1. Implement a custom Go-based GraphQL server.
    This might be the best option on the long run as we don't have to rely on third party tools, but it might also require us a lot more work to do as well as to maintain this heavily in the future.

  2. Use a GraphQL generator.
    This is the option we should take if we want to start playing with GraphQL in the short time, and that will require us less code maintenance and less work. The downside is that we might now have all the features we want.

Personally, I would go with the following strategy:

  1. Use a generator to build the first version of the GraphQL APIs.
    Particularly I would use Hasura as it has already been shown it works properly.

  2. Once we have a nice set of APIs, we can have @MonikaCat start building the new BigDipper on top of them. This would allow us to see if we need to tweak them or not.

  3. If they are all OK, we can think if we should implement them inside the Go binary or not.

What are your thoughts about it? @kwunyeung @MonikaCat @bragaz

Note

If we decide for the second option and choose Hasura, I'd like to point out what Alexander said to me:

You’ll have to tweak the relations a bit

We should further investigate this and see what he meant with it.

BuildExecutor method position

Currently we have BuildExecutor method placed inside main.go and this cause an error when we use juno as a library and try to import the method:
'github.com/desmos-labs/juno/cmd/juno' is a program, not an importable package.
That should be probably moved to another folder/file to avoid this problem.

Missing message parser for module `Staking` message `CancelUnbonding` for Cosmos SDK v0.46.x

Bug description

Bug related only for branch v0.46.x, as for this version of Cosmos SDK was added new message type MsgCancelUnbondingDelegation to staking module, and now Juno can't parse blocks that contain that message type.
Error message: failed to get transactions for block: error while unpacking message: no concrete type registered for type URL /cosmos.staking.v1beta1.MsgCancelUnbondingDelegation against interface *types.Msg"

Steps to reproduce

  1. Bootstrap network based on v0.46.x of Cosmos SDK with staking module and connect Juno to parse it.
  2. Create validator
  3. Delegate some funds
  4. Undelegate funds
  5. Execute transaction to cancel unbonding
  6. Check in Juno logs that block processing was failed (and whole block is lost, not saved to DB)

Expected behavior

Block with such message type should be stored to DB as it should

Automatic DB type recognition

Currently the database type is not recognized using the configuration, and so there are two branches:

  • master which contains the code for PostgreSQL-based databases
  • db-mongo which contains the code for Mongo-based databases

We should definitely merge those by either automatically adding database recognition (Mongo has uri while PostgreSQL has localhost, port, etc) or changing the configuration appropriately.

Support concurrent transaction handling

Feature description

Currently transactions that are stored inside a block are handled sequentially. Instead, order to improve the overall data parsing performances, we could handle them in parallel.

Implementation proposal

Use goroutines to concurrently call HandleTx multiple times.

Support binary upgrades

Feature description

Currently, Cosmos chains that Juno supports may be using the x/upgrade module in order to perform seamless on-chain upgrades from one binary version to the other. Due to the fact that a new binary version might present breaking changes, Juno operators need to remember when those upgrade happen and quickly replace the Juno binary with the new version that supports such changes. As more and more chains are managed by the same operator, handling such upgrades will be harder and harder.

To solve the problem, we should allow Juno to react to on-chain upgrades when they happen in a reactive way (only after the upgrade happened successfully).

Implementation proposal

One idea might be to leverage the x/upgrade itself: one an on-chain upgrade proposal passes, the upgrade details will be stored on the chain itself. Such details include also the upgrade height. What we could do is leveraging that upgrade height and the corresponding upgrade name to make sure that Juno panics when such upgrade happens. This, combined with something like Cosmovisor should make it fairly easy to implement a way to switch from one Juno binary to another after an on-chain upgrade is successful.

Can't parse IBC client update & IBC acks

Bug description

Running Callisto (using juno 5.3.0) I get this ERR logs:

9:41AM ERR re-enqueueing failed block err="failed to get transactions for block: error while unpacking message: no concrete type registered for type URL /ibc.core.client.v1.MsgUpdateClient against interface *types.Msg" height=94108
9:41AM ERR re-enqueueing failed block err="failed to get transactions for block: error while unpacking message: no concrete type registered for type URL /ibc.applications.transfer.v1.MsgTransfer against interface *types.Msg" height=94925
9:41AM DBG processing block height=94925
9:41AM DBG processing block height=94108
9:41AM ERR re-enqueueing failed block err="failed to get transactions for block: error while unpacking message: no concrete type registered for type URL /ibc.core.client.v1.MsgUpdateClient against interface *types.Msg" height=14532
9:41AM DBG processing block height=14532
9:41AM DBG enqueueing missing block height=95445
9:41AM ERR re-enqueueing failed block err="failed to get transactions for block: error while unpacking message: no concrete type registered for type URL /ibc.applications.transfer.v1.MsgTransfer against interface *types.Msg" height=95173
9:41AM DBG processing block height=95173
9:41AM ERR re-enqueueing failed block err="failed to get transactions for block: error while unpacking message: no concrete type registered for type URL /ibc.core.client.v1.MsgUpdateClient against interface *types.Msg" height=95169
9:41AM DBG processing block height=95169
9:41AM ERR re-enqueueing failed block err="failed to get transactions for block: error while unpacking message: no concrete type registered for type URL /ibc.applications.transfer.v1.MsgTransfer against interface *types.Msg" height=94090
9:41AM DBG processing block height=94090
9:41AM ERR re-enqueueing failed block err="failed to get transactions for block: error while unpacking message: no concrete type registered for type URL /ibc.core.client.v1.MsgUpdateClient against interface *types.Msg" height=94764

Steps to reproduce

Syncing the chain bitcanna-1 we get this errors with old blocks (SDK v044 to v046) and new blocks (v047 from height 12288420)

Expected behavior

The expected behavior is to parse the IBC update & ack messages or skip them after a configurable number of retries (or low amount like 2 or 3 times)

Support for Cosmos SDK v0.50.x

Feature description

Support for Cosmos SDK v0.50.x

Implementation proposal

  • Create a cosmos/v0.50.x branch
  • Bump module in go.mod to module github.com/forbole/juno/v6
  • Update go.mod to e.g. github.com/cosmos/cosmos-sdk v0.50.6
  • Fix dependency issues and compilation errors

I could help with the implementation if you like

No transactions obtained for Microtickzone-a1 Blockchain

Bug description

I tried indexing the Microtick blockchain, specifically the old microtickzone-a1 chain using an old Juno fork (Juno for v0.39.x Cosmos SDK blockchains) and managed to obtain all blocks but no transactions.

This issue was encountered on an Ubuntu Linux 64-bit 22.04 LTS VM running Golang v1.18.1 and PostgreSQL v12.10.

Steps to reproduce

Prerequisites: Linux VM, Golang and PostgreSQL installed.

  1. Fork this repo.
  2. Follow the setup instructions in the [README file].(https://github.com/forbole/juno/blob/ead810b0ed1e9a71973ba92e0eeb31e41af078a2/README.md).
  3. Setup the config file to point to a private node running a copy of microtickzone-a1 data. I am connected to a private node running this data, whose details unfortunately cannot be provided.
    Note: At the time, microtickzone-a1 was using Cosmos SDK v0.34.4-0.20200519133235-d7677e087117.
  4. Run juno start and the postgreSQL database should start populating with blocks, but not with transactions.

Expected behavior

I expect to receive all blocks and transactions for microtickzone-a1.

ERR re-enqueueing failed block err="failed to get block results from node"

Hi, I tried running juno (branch v2/cosmos-stargate) against a localnet using cosmos-sdk/mainline and am getting the following error.

ERR re-enqueueing failed block err="failed to get block results from node: error unmarshalling result: illegal base64 data at input byte 44" height=2
  • go version: go version go1.17.1 darwin/amd64
  • OS: macOS 10.15.7

Q: Am I doing something wrong? I'm not entirely sure about the juno branch, but I also tried running against v0.40.0 of cosmos-sdk and got the same error. If you could provide instructions on how to run juno against a localnet that would be great (or alternatively, a public remote RPC endpoint I could use instead).

Steps taken:

  1. start local testnet using build/simd testnet start
  2. followed juno setup instructions here
  3. run juno parse

Full error:

➜  juno  juno parse                                                                                                                                                                              [7:41:50]
7:41AM DBG starting worker... number=1
7:41AM INF listening for new block events...
7:41AM INF syncing missing blocks... latest_block_height=128
7:41AM DBG enqueueing missing block height=1
7:41AM DBG enqueueing missing block height=2
7:41AM DBG enqueueing missing block height=3
7:41AM DBG enqueueing missing block height=4
7:41AM DBG enqueueing missing block height=5
7:41AM DBG enqueueing missing block height=6
7:41AM DBG enqueueing missing block height=7
7:41AM DBG enqueueing missing block height=8
7:41AM DBG enqueueing missing block height=9
7:41AM DBG enqueueing missing block height=10
7:41AM DBG enqueueing missing block height=11
7:41AM DBG enqueueing missing block height=12
7:41AM DBG enqueueing missing block height=13
7:41AM DBG enqueueing missing block height=14
7:41AM DBG enqueueing missing block height=15
7:41AM DBG enqueueing missing block height=16
7:41AM DBG enqueueing missing block height=17
7:41AM DBG enqueueing missing block height=18
7:41AM DBG enqueueing missing block height=19
7:41AM DBG enqueueing missing block height=20
7:41AM DBG enqueueing missing block height=21
7:41AM DBG enqueueing missing block height=22
7:41AM DBG enqueueing missing block height=23
7:41AM DBG enqueueing missing block height=24
7:41AM DBG enqueueing missing block height=25
7:41AM DBG enqueueing missing block height=26
7:41AM DBG enqueueing missing block height=27
7:41AM DBG processing block height=1
7:41AM DBG enqueueing missing block height=28
7:41AM ERR re-enqueueing failed block err="failed to get block results from node: error unmarshalling result: illegal base64 data at input byte 44" height=2
<SNIPPED>

config.yaml:

chain:
    bech32_prefix: cosmos
    modules: []
node: 
  type: remote
  config: 
    rpc:
      client_name: juno
      address: tcp://localhost:26657
      max_connections: 20
    grpc:
      insecure: true
      address: localhost:9090
parsing:
    workers: 1
    listen_new_blocks: true
    parse_old_blocks: true
    parse_genesis: true
    start_height: 1
database:
    name: juno_cosmos
    host: localhost
    port: 5432
    user: <REDACTED>
    password: <REDACTED>
    schema: public
    max_open_connections: 1
    max_idle_connections: 1
logging:
    level: debug
    format: text

simd status:

➜  cosmos-sdk  ./build/simd status | jq                                                                                                                                                          [7:39:45]
{
  "NodeInfo": {
    "protocol_version": {
      "p2p": "8",
      "block": "11",
      "app": "0"
    },
    "id": "014087327cd3d8c910e5aeac24c0c737b14a1daf",
    "listen_addr": "tcp://0.0.0.0:60886",
    "network": "chain-QiaZfv",
    "version": "0.35.0-unreleased",
    "channels": "402021222330386061626300",
    "moniker": "node0",
    "other": {
      "tx_index": "on",
      "rpc_address": "tcp://0.0.0.0:26657"
    }
  },
  "SyncInfo": {
    "latest_block_hash": "515B749AE841F2ED8FD02595440D2D293716DD29B088723289F4321F713DE046",
    "latest_app_hash": "AFC907CC6D21A0E7E6446D7F5C40A95797045B09A8A817604C8CF97BDCB0A85A",
    "latest_block_height": "271",
    "latest_block_time": "2022-01-02T07:47:42.914668Z",
    "earliest_block_hash": "1DBC94BC887584899097C1079D121B2ABF9516C18B7B744A36C57756150BD91F",
    "earliest_app_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855",
    "earliest_block_height": "1",
    "earliest_block_time": "2022-01-02T07:36:17.395216Z",
    "max_peer_block_height": "0",
    "catching_up": false,
    "total_synced_time": "0",
    "remaining_time": "0",
    "total_snapshots": "0",
    "chunk_process_avg_time": "0",
    "snapshot_height": "0",
    "snapshot_chunks_count": "0",
    "snapshot_chunks_total": "0",
    "backfilled_blocks": "0",
    "backfill_blocks_total": "0"
  },
  "ValidatorInfo": {
    "Address": "E420BD19C497E72AEB573F3455E62E6EFDDF2103",
    "PubKey": {
      "type": "tendermint/PubKeyEd25519",
      "value": "rWIMw4FacZKmej+hs+xz5MfcDeLdFvIOPZ2s20lc2UI="
    },
    "VotingPower": "100"
  }
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.