Code Monkey home page Code Monkey logo

goteth's Introduction

GotEth

GotEth is a go-written client that indexes all validator-related duties and parameters from Ethereum's beaconchain by fetching the CL States from a node (preferable a locally running archival node).

The client indexes all the validator/epoch related metrics into a set of postgreSQL tables which later on can be used to monitor the performance of validators in the beaconchain.

This tool has been used to power the

Prerequisites

To use the tool, the following requirements need to be installed in the machine:

  • go preferably on its 1.21 version or above. Go also needs to be executable from the terminal.
  • Clickhouse DB
  • Access to an Ethereum CL beacon node (preferably an archive node to index the slots faster)
  • Access to an Ethereum execution node (optional)
  • Access to a Clickhouse server database (use native port, usually 9000)

Installation

The repository provides a Makefile that will take care of all your problems.

To compile locally the client, just type the following command at the root of the directory:

make build

Or if you prefer to install the client locally type:

make install

Metrics: database tables

  • block: downloads withdrawals, blocks and block rewards
  • epoch: download epoch metrics, proposer duties, validator last status,
  • rewards: persists validator rewards metrics to database (activates epoch metrics)
  • api_rewards (EXPERIMENTAL): block rewards (consensus layer) are hard to calculate, but they can be downloaded from the Beacon API. However, keep in mind this takes a few seconds per block when not at the head. Without this, reward cannot be compared to max_reward when a validator is a proposer (32/900K validators in an epoch). It depends on the Lighthouse API and we have registered some cases where the block reward was not returned.
  • transactions: requests transaction receipts from the execution layer (activates block metrics)

Download mode

  • Historical: this mode loops over slots between initSlot and finalSlot, which are configurable. Once all slots have been analyzed, the tool finishes the execution.
  • Finalized: initSlot and finalSlot are ignored. The tool starts the historical mode from the database last slot to the current head (beacon node) and then follows the chain head. To do this, the tool subscribes to head events. See here for more information.

Running the tool

To execute the tool, you can simply modify the .env file with your own configuration.

Running the tool (configurable in the .env file):

docker-compose up goteth

Available Commands:

COMMANDS:
   blocks   analyze the Beacon Block of a given slot range
   val-window Removes old rows from the validator rewards table according to given parameters
   help, h  Shows a list of commands or help for one command

Available Options (configurable in the .env file)


Blocks
OPTIONS:
   --bn-endpoint value     beacon node endpoint (to request the Beacon Blocks)
   --el-endpoint value 	   execution node endpoint (to request the Transaction Receipts, optional)
   --init-slot value       init slot from where to start (default: 0)
   --final-slot value      init slot from where to finish (default: 0)
   --log-level value       log level: debug, warn, info, error
   --db-url value          example: clickhouse://beaconchain:beaconchain@localhost:9000/beacon_states
   --workers-num value     example: 3 (default: 4)
   --db-workers-num value  example: 3 (default: 4)
   --download-mode value   example: hybrid,historical,finalized. Default: hybrid
   --metrics value         example: epoch,block,rewards,transactions,api_rewards. Empty for all (default: epoch,block)
   --prometheus-port value Port on which to expose prometheus metrics (default: 9081)
   --help, -h              show help (default: false)

Validator window (experimental)

Validator rewards represent 95% of the disk usage of the database. When activated, the database grows very big, sometimes becoming too much data. We have developed a subcommand of the tool which maintains the last n epochs of rewards data in the database, prunning from the defined threshold backwards. So, one can configure the tool to maintain the last 100 epochs of data in the database, while prunning the rest. The pruning only affects the t_validator_rewards_summary table.

Simply configure GOTETH_VAL_WINDOW_NUM_EPOCHS variable and run

docker-compose up val-window

Notes

Keep in mind api_rewards data also downloads block rewards from the Beacon API. This is very slow on historical blocks (3 seconds per block), but very fast on blocks near the head.

Database migrations

In case you encounter any issue with the database, you can force the database version using the golang-migrate command line. Please refer here for more information. More specifically, one could clean the migrations by forcing the version with
migrate -path / -database "postgresql://username:secretkey@localhost:5432/database_name?sslmode=disable" force <current_version>
If specific upgrades or downgrades need to be done manually, one could do this with
migrate -path database/migration/ -database "postgresql://username:secretkey@localhost:5432/database_name?sslmode=disable" -verbose up

From PostgreSQL to Clickhouse

During v3.0.0 we will migrate our database system from PostgreSQL to Clickhouse. If you wish to migrate your existing database, please follow this guide.

Maintainers

@cortze @tdahar

Contributing

The project is open for everyone to contribute!

goteth's People

Contributors

barnabasbusa avatar cortze avatar ocheja avatar santi1234567 avatar tdahar avatar

Stargazers

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

Watchers

 avatar  avatar  avatar  avatar

goteth's Issues

Transaction perissting issue when duplicated hash

Description

The issue is that if one persist fails , the whole batch (maybe 2000 persists from different types) will also rollback with it and they will not be executed.
I think the issue is that, as you already have a unique contraint, it is getting fired before the primary key constraint.

eth-state-analyzer-blocks | time="2023-05-08T07:00:14Z" level=error msg="Error executing batch, error: ERROR: duplicate key value violates unique constraint \"t_transactions_f_hash_key\" (SQLSTATE 23505)" module=postgres-db

Is it possible we add something so that this error is ignored as with the primary key?

Solution

This would be the code to change:
https://github.com/cortze/goteth/blob/018928b28095d8ccec620896e64940b1d389618a/pkg/db/transactions.go#L29

Basically we need to add something to do nothing when the unique constraint fires as well

Asignees

@ocheja

Reorg on epoch boundary

Reorgs happen very often in Goerli. However, it is not very common that the reorg involves redownloading a state again (only at the end of the epoch). Therefore, this is something we will be testing throughout the time, as the scenario does not happen for several days.

At the moment, we believe it is properly handled, but we are leaving this issue just in case someone comes across an exceptional case that was not handled yet.

Improve how three states are bundled together into metrics

Description

Right now, three consecutive states are downloaded from the beacon API. This allows to write validator metrics in the next state (3rd one) and epoch metrics in the current state (2nd one). Therefore, the tool writes different metrics in different epochs.

Goal

It would be nice if we could improve this so all metrics are written for the same epoch. This way, we don't have to handle evaluating metrics at different epoch, specially at the beginning and end of the process.

Proposal

Implement one object that stores three states and handles how states are updated in the queue. Right now every time a new state is downloaded the updates of previous, current and next state is done manually.

type StateQueue struct {
    prevState
    currentState
    nextState
}

func AddNewState(newState) {
    prevState <- currentState <- nextState <- newState
}

Reorg should redownload blocks of depth x wihtout counting missed blocks

When a reorg happens, the tool should redownload blocks of depth x without counting the missed ones
If there was a missed block before the reorg, the tool does not count an additional block to reorg

In the case below, head slot is 1063712, and the reorg occurs at slot 1063714 of depth 1
The tool then reorgs slots 1063713 and 1063714, but at this point 1063713 was missed, so the reorg actually points to 1063712.

goteth_1      | time="2024-02-23T05:42:23Z" level=info msg="checked states until slot 1063584, epoch 33237" module=analyzer
goteth_1      | time="2024-02-23T05:42:30Z" level=info msg="New event: slot 1063712, epoch 33241. 32 pending slots for new epoch" module=Events routine=head-event
goteth_1      | time="2024-02-23T05:42:47Z" level=info msg="block at slot 1063712 downloaded in 16.780930 seconds" module=api-cli
goteth_1      | time="2024-02-23T05:42:55Z" level=info msg="New event: slot 1063714, epoch 33241. 30 pending slots for new epoch" module=Events routine=head-event
goteth_1      | time="2024-02-23T05:42:55Z" level=info msg="New event: slot 1063714 of depth 1" module=Events routine=reorg-event
goteth_1      | time="2024-02-23T05:42:55Z" level=warning msg="reorging from 1063713 to 1063714 (included)" module=analyzer
goteth_1      | time="2024-02-23T06:14:23Z" level=info msg="New event: epoch 33244, state root: 0xafb6fbd2ca92406a21bb6152f33bacae85fb6bd7634a9c3fe48c176387e84a49" module=Events routine=checkpoint-event
goteth_1      | time="2024-02-23T06:14:23Z" level=error msg="history block root: 0x54a4dbba6a20b741c2cf55d021efc578734d1d384012b8d1fecca8994f286482\nfinalized block root: 0x0000000000000000000000000000000000000000000000000000000000000000" module=analyzer
goteth_1      | time="2024-02-23T06:14:23Z" level=fatal msg="block root for block (slot=1063712) incorrect, redownload" module=analyze

Gather Execution Layer data

Starting with transactions, it is the first aim to start gathering data about the execution layer. Consensus Layer already stores the bytecodes of transactions and this could be decoded. Thisis only the first step to continue gathering data from the Execution Node.

TBD.

Improve logging

This is not an urgent task.
It would be nice to improve the log objects and levels, as right now executing the tool in trace mode becomes impossible to trace any routine.
We would need to identify which logs need to be in debug mode, which in trace and which in debug mode

Also, this is a good opportunity to store genesis time and double check the network is correct
Also show which client the tool is connected to

Crash when processing phase 0 slots

Description

Developing the feature of storing the inclusion delay of attestations in the DB, I encountered a bug that occurs while processing phase 0 slots:

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x11ee2da]

goroutine 152 [running]:
github.com/migalabs/goteth/pkg/clientapi.(*APIClient).RequestStateRoot(0xc0000503c0, 0x7bd7c0)
	/home/sant/Nextcloud/Trabajo/Ubuntu/goteth/pkg/clientapi/state.go:77 +0x2fa
github.com/migalabs/goteth/pkg/clientapi.(*APIClient).RequestBeaconBlock(0xc0000503c0, 0x7bd7c0)
	/home/sant/Nextcloud/Trabajo/Ubuntu/goteth/pkg/clientapi/block.go:74 +0xffb
github.com/migalabs/goteth/pkg/clientapi.(*APIClient).RequestFinalizedBeaconBlock(0xc0000503c0)
	/home/sant/Nextcloud/Trabajo/Ubuntu/goteth/pkg/clientapi/block.go:99 +0x10d
github.com/migalabs/goteth/pkg/analyzer.(*ChainAnalyzer).runHistorical(0xc000294240, 0x231860, 0x231c40)
	/home/sant/Nextcloud/Trabajo/Ubuntu/goteth/pkg/analyzer/routines.go:163 +0x35e
created by github.com/migalabs/goteth/pkg/analyzer.(*ChainAnalyzer).Run in goroutine 150
	/home/sant/Nextcloud/Trabajo/Ubuntu/goteth/pkg/analyzer/chain_analyzer.go:152 +0x54d

Steps for replicating

Checkout to branch feature/add-inclusion-delay-column-to-rewards and run the script with following params:

"args": [
        "blocks",
        "--log-level",
        "info",
        "--bn-endpoint",
        "NODE ENDPOINT",
        "--init-slot",
        "2300000",
        "--final-slot",
        "2301000",
        "--db-url",
        "DB ENDPOINT",
        "--workers-num",
        "1",
        "--db-workers-num",
        "10",
        "--download-mode",
        "historical",
        "--prometheus-port",
        "5000",
        "--metrics",
        "block,epoch,rewards",
        ""
      ]

Transaction Details hardcoded to bellatrix

Description

Right now we request the transaction details using the bellatrix.Transaction. However, this structure might change in the future, so the details should be requested using a standard structure as a Hash.
#63 (review)

Proposal

In order to make the transaction request compatible with the rest of the tool, we intend to request the details inside the block, at the same time it is converted to an AgnosticBlock taking into account the current fork. Then, inside the block we would store an array of AgnosticTransaction.

// This Wrapper is meant to include all common objects across Ethereum Hard Fork Specs
type AgnosticExecutionPayload struct {
	FeeRecipient  bellatrix.ExecutionAddress
	GasLimit      uint64
	GasUsed       uint64
	Timestamp     uint64
	BaseFeePerGas [32]byte
	BlockHash     phase0.Hash32
	Transactions  []local_spec.AgnosticTransaction
	BlockNumber   uint64
	Withdrawals   []*capella.Withdrawal
}

Weird reorg handling when several reach so close

We have detected a reorg weird issue that when several of them reach, the tool does not properly handle all of them, resulting in some blocks being incorrect

Logs

goteth_1  | time="2023-12-09T08:34:39Z" level=info msg="New event: slot 7940571, epoch 248142. 5 pending slots for new epoch" module=Events routine=head-event
goteth_1  | time="2023-12-09T08:34:39Z" level=info msg="New event: slot 7940571 of depth 1" module=Events routine=reorg-event
goteth_1  | time="2023-12-09T08:34:39Z" level=warning msg="reorging from 7940570 to 7940571 (not included)" module=analyzer
goteth_1  | time="2023-12-09T08:34:40Z" level=info msg="block at slot 7940571 downloaded in 0.579643 seconds" module=api-cli
goteth_1  | time="2023-12-09T08:34:40Z" level=warning msg="the beacon block at slot 7940570 does not exist, missing block" module=api-cli
goteth_1  | time="2023-12-09T08:34:41Z" level=info msg="rewriting metrics for slot 7940570" module=analyzer
goteth_1  | time="2023-12-09T08:34:47Z" level=info msg="New event: slot 7940570, epoch 248142. 6 pending slots for new epoch" module=Events routine=head-event
goteth_1  | time="2023-12-09T08:34:47Z" level=info msg="New event: slot 7940570 of depth 2" module=Events routine=reorg-event
goteth_1  | time="2023-12-09T08:34:47Z" level=warning msg="reorging from 7940568 to 7940570 (not included)" module=analyzer
goteth_1  | time="2023-12-09T08:34:47Z" level=info msg="block at slot 7940568 downloaded in 0.521489 seconds" module=api-cli
goteth_1  | time="2023-12-09T08:34:48Z" level=info msg="rewriting metrics for slot 7940568" module=analyzer
goteth_1  | time="2023-12-09T08:34:49Z" level=info msg="block at slot 7940569 downloaded in 0.375533 seconds" module=api-cli
goteth_1  | time="2023-12-09T08:34:50Z" level=info msg="rewriting metrics for slot 7940569" module=analyzer
goteth_1  | time="2023-12-09T08:34:52Z" level=info msg="New event: slot 7940572, epoch 248142. 4 pending slots for new epoch" module=Events routine=head-event
goteth_1  | time="2023-12-09T08:34:52Z" level=info msg="block at slot 7940572 downloaded in 0.323017 seconds" module=api-cli
goteth_1  | time="2023-12-09T08:35:01Z" level=info msg="New event: slot 7940573, epoch 248142. 3 pending slots for new epoch" module=Events routine=head-event
goteth_1  | time="2023-12-09T08:35:01Z" level=info msg="block at slot 7940573 downloaded in 0.291509 seconds" module=api-cli
goteth_1  | time="2023-12-09T08:35:12Z" level=info msg="New event: slot 7940574, epoch 248142. 2 pending slots for new epoch" module=Events routine=head-event
goteth_1  | time="2023-12-09T08:35:13Z" level=info msg="block at slot 7940574 downloaded in 0.144095 seconds" module=api-cli

Database

image

This should be further investigated as some blocks should be orphaned and they are not:

  • 7940570 should be proposed and ok
  • 7940571 should be orphaned

Separate transactions in a separate channel

Separate transaction processing into a separate channel.
Right now transactions are requested sequentially with the block, which is slowing down the overall performance.

The idea is that transactions are passed on to a different gorroutine which requests data about transactions, while blocks can keep being downloaded and processed faster.

Improve configuration of tool

Right now the tool supports inserting arguments through the command line.
However, it would be a better model to have a base config and on top of that keep adding the user inputs.
This way, we could store a config object which can be shared with all the running routines that need it.

This should make the code cleaner.

Issue with 't_block_metrics' Table: Numerous Records with 'f_el_block_number' Set to 0

Description

I've noticed a significant issue in the t_block_metrics table, where a large number of records have their f_el_block_number field set to 0. This seems to indicate either a default value being used in place of actual data or a potential error in data collection or processing.

Suggested Solution

There are two possible solutions to address this issue:

  1. Avoid Creating Records with Incomplete Data: If the f_el_block_number is essential and the data is not available at the time of record creation, it might be better to avoid creating the record altogether. This approach would ensure that only complete and meaningful data is stored in the t_block_metrics table.

  2. Use a Different Placeholder for Missing Data: In scenarios where a record must be created despite missing f_el_block_number data, using a value of -1 might be more appropriate than 0. The -1 can act as a clearer indicator that the actual block number data is not available or does not exist, as opposed to 0, which can be ambiguous or misleading.

Impact

The presence of numerous records with f_el_block_number set to 0 can lead to confusion and may affect data integrity and analysis. By implementing one of the suggested solutions, we can enhance the clarity and reliability of the data in the t_block_metrics table.

Thank you for considering this issue. I believe addressing it will significantly improve the data handling and quality in our system.

Add unit testing

Motivation

The tool is absorbing a lot of new features and we need a way to check that the new features are not affecting the previous behaviour.

Description

The idea is to add some unit testing of a past epoch where we know that certain validators have earned a certain amount of rewards.
This could be done for all the metrics.

This way, every time we deploy a new feature we just need to run the tests and verify that metrics are still collected well.
We will need to add extreme scenarios and edgy cases to check all metrics properly.

Capella blocks download crashing

Description

Since #114, Capella blocks fail to be downloaded.

goteth-1  | panic: runtime error: invalid memory address or nil pointer dereference
goteth-1  | [signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0xc259fa]
goteth-1  | 
goteth-1  | goroutine 1267 [running]:
goteth-1  | github.com/migalabs/goteth/pkg/spec.NewCapellaBlock({_, _, _, _, _, _})
goteth-1  |     /app/pkg/spec/block.go:255 +0x1fa
goteth-1  | github.com/migalabs/goteth/pkg/spec.GetCustomBlock({_, _, _, _, _, _})
goteth-1  |     /app/pkg/spec/block.go:91 +0x2f0
goteth-1  | github.com/migalabs/goteth/pkg/clientapi.(*APIClient).RequestBeaconBlock(0xc0001c6a40, 0x2f5fe?)
goteth-1  |     /app/pkg/clientapi/block.go:62 +0x6c9
goteth-1  | github.com/migalabs/goteth/pkg/analyzer.(*ChainAnalyzer).DownloadBlock(0xc000650240, 0x5ec002?)
goteth-1  |     /app/pkg/analyzer/download.go:22 +0x45
goteth-1  | github.com/migalabs/goteth/pkg/analyzer.(*ChainAnalyzer).DownloadBlockCotrolled(0x7010a?, 0xc0010e2798?)
goteth-1  |     /app/pkg/analyzer/download.go:13 +0x2c
goteth-1  | created by github.com/migalabs/goteth/pkg/analyzer.(*ChainAnalyzer).runDownloadBlocks in goroutine 163
goteth-1  |     /app/pkg/analyzer/routines.go:30 +0x2c5
goteth-1  | GotEth v3.3.0

Goteth stuck when running on historical mode with init_slot being <32

When running in historical mode with init_slot being <32, there seems to be some sort of underflow which makes the script get stuck.

time="2024-07-03T15:37:49Z" level=debug msg="slot 0 waiting for state at slot 18446744073709551583 (epoch 18446744073709551614) to be downloaded or processed..." module=analyzer
`` 

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.