Block fingerprinting for the beacon chain, for client identification & client diversity metrics

Overview

blockprint

This is a repository for discussion and development of tools for Ethereum block fingerprinting.

The primary aim is to measure beacon chain client diversity using on-chain data, as described in this tweet:

https://twitter.com/sproulM_/status/1440512518242197516

The latest estimate using the improved k-NN classifier for slots 2048001 to 2164916 is:

Getting Started

The raw data for block fingerprinting needs to be sourced from Lighthouse's block_rewards API.

This is a new API that is currently only available on the block-rewards-api branch, i.e. this pull request: https://github.com/sigp/lighthouse/pull/2628

Lighthouse can be built from source by following the instructions here.

VirtualEnv

All Python commands should be run from a virtualenv with the dependencies from requirements.txt installed.

python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt

k-NN Classifier

The best classifier implemented so far is a k-nearest neighbours classifier in knn_classifier.py.

It requires a directory of structered training data to run, and can be used either via a small API server, or in batch mode.

You can download a large (886M) training data set here.

To run in batch mode against a directory of JSON batches (individual files downloaded from LH), use this command:

./knn_classifier.py training_data_proc data_to_classify

Expected output is:

classifier score: 0.9886800869904645
classifying rewards from file slot_2048001_to_2050048.json
total blocks processed: 2032
Lighthouse,0.2072
Nimbus or Prysm,0.002
Nimbus or Teku,0.0025
Prysm,0.6339
Prysm or Teku,0.0241
Teku,0.1304

Training the Classifier

The classifier is trained from a directory of reward batches. You can fetch batches with the load_blocks.py script by providing a start slot, end slot and output directory:

./load_blocks.py 2048001 2048032 testdata

The directory testdata now contains 1 or more files of the form slot_X_to_Y.json downloaded from Lighthouse.

To train the classifier on this data, use the prepare_training_data.py script:

./prepare_training_data.py testdata testdata_proc

This will read files from testdata and write the graffiti-classified training data to testdata_proc, which is structured as directories of single block reward files for each client.

$ tree testdata_proc
testdata_proc
├── Lighthouse
│   ├── 0x03ae60212c73bc2d09dd3a7269f042782ab0c7a64e8202c316cbcaf62f42b942.json
│   └── 0x5e0872a64ea6165e87bc7e698795cb3928484e01ffdb49ebaa5b95e20bdb392c.json
├── Nimbus
│   └── 0x0a90585b2a2572305db37ef332cb3cbb768eba08ad1396f82b795876359fc8fb.json
├── Prysm
│   └── 0x0a16c9a66800bd65d997db19669439281764d541ca89c15a4a10fc1782d94b1c.json
└── Teku
    ├── 0x09d60a130334aa3b9b669bf588396a007e9192de002ce66f55e5a28309b9d0d3.json
    ├── 0x421a91ebdb650671e552ce3491928d8f78e04c7c9cb75e885df90e1593ca54d6.json
    └── 0x7fedb0da9699c93ce66966555c6719e1159ae7b3220c7053a08c8f50e2f3f56f.json

You can then use this directory as the first argument to ./knn_classifier.py.

Classifier API

With pre-processed training data installed in ./training_data_proc, you can host a classification API server like this:

gunicorn --reload api_server --timeout 1800

It will take a few minutes to start-up while it loads all of the training data into memory.

Initialising classifier, this could take a moment...
Start-up complete, classifier score is 0.9886800869904645

Once it has started up, you can make POST requests to the /classify endpoint containing a single JSON-encoded block reward. There is an example input file in examples.

curl -s -X POST -H "Content-Type: application/json" --data @examples/single_teku_block.json "http://localhost:8000/classify"

The response is of the following form:

{
  "block_root": "0x421a91ebdb650671e552ce3491928d8f78e04c7c9cb75e885df90e1593ca54d6",
  "best_guess_single": "Teku",
  "best_guess_multi": "Teku",
  "probability_map": {
    "Lighthouse": 0.0,
    "Nimbus": 0.0,
    "Prysm": 0.0,
    "Teku": 1.0
  }
}
  • best_guess_single is the single client that the classifier deemed most likely to have proposed this block.
  • best_guess_multi is a list of 1-2 client guesses. If the classifier is more than 95% sure of a single client then the multi guess will be the same as best_guess_single. Otherwise it will be a string of the form "Lighthouse or Teku" with 2 clients in lexicographic order. 3 client splits are never returned.
  • probability_map is a map from each known client label to the probability that the given block was proposed by that client.

TODO

  • Improve the classification algorithm using better stats or machine learning (done, k-NN).
  • Decide on data representations and APIs for presenting data to a frontend (done).
  • Implement a web backend for the above API (done).
  • Polish and improve all of the above.
Comments
  • Measure DB accuracy with graffiti guess

    Measure DB accuracy with graffiti guess

    • Add a graffiti_guess column to the database
    • Estimate the confusion matrix for each client by comparing classifier results against the graffiti guess
    • When running the API server, disable the (slow) classifier load if the DISABLE_CLASSIFIER environment variable is set

    I think this is quite prone to overfitting, as in my most recent training data set there are very few misclassifications, even for Nimbus and Lodestar (very suspicious)

    curl "http://localhost:8000/confusion/Lighthouse/0/10000000"
    {"true_pos": 21925, "true_neg": 7931, "false_pos": 16, "false_neg": 0}                                                                                                                                                         
    
    curl "http://localhost:8000/confusion/Prysm/0/10000000"
    {"true_pos": 279, "true_neg": 29584, "false_pos": 0, "false_neg": 9}
    
    curl "http://localhost:8000/confusion/Teku/0/10000000"
    {"true_pos": 6684, "true_neg": 23188, "false_pos": 0, "false_neg": 0}
    
    curl "http://localhost:8000/confusion/Nimbus/0/10000000"
    {"true_pos": 928, "true_neg": 28944, "false_pos": 0, "false_neg": 0}
    
    curl "http://localhost:8000/confusion/Lodestar/0/10000000"
    {"true_pos": 40, "true_neg": 29825, "false_pos": 0, "false_neg": 7}
    
    opened by michaelsproul 2
  • Modularise feature selection

    Modularise feature selection

    It would be cool to have features named and capable of being toggled on and off from the CLI.

    It would also be nice to include feature names on the matplotlib graphs, with a 2D cross-section for each pair of features.

    opened by michaelsproul 2
  • Pin click version

    Pin click version

    The version of click in black is unpinned. A recent click upgrade caused widespread frustration in the world of Python. This PR pins click. For more context: https://github.com/dask/distributed/issues/6013

    opened by ariskk 1
  • Fix gap calculation

    Fix gap calculation

    Fixes the calculation of gaps in the presence of re-orgs and missing blocks.

    Blockprint was getting stuck when block n - 2 was missing, which was parent to both n - 1 and n. The gap calculator was calculating an invalid gap with bounds [n, n - 1].

    The new calculator takes care to fetch the oldest prior block with slot less than the missing parent n - 2, which yields the correct gap [n - 2, n - 1].

    opened by michaelsproul 0
  • Add on-demand classification without storage

    Add on-demand classification without storage

    Add a new /classify/no_store endpoint that classifies block rewards and returns their classification without storing anything in the database. I am using this in blockgauge.

    opened by michaelsproul 0
  • Add `validators/blocks/latest` API endpoint

    Add `validators/blocks/latest` API endpoint

    This PR adds an API endpoint at validators/blocks/latest. This endpoint returns a list of each validator, their most recently proposed block and the best_guess_single for that block.

    Usage examples can be seen in docs/validator_api.md

    opened by macladson 0
  • Features based on AttestationData ordering

    Features based on AttestationData ordering

    This PR improves the cross validation score to around 0.95 by computing new features based on the ordering of AttestationData within blocks. Previously we relied entirely on the ordering of attestation rewards, but several clients seem to order based on attestation slot instead.

    From now on, to use blockprint with these new difflib features will require a version of Lighthouse containing this commit: https://github.com/sigp/lighthouse/commit/53b2b500dbb9f00b5d6dd4da065e52d7ba186f9a (at time of writing, no release includes this commit but it will be in v2.3.2/v2.4.0).

    Finally, the graffiti regex were also updated to support recent versions of RocketPool which include an extra letter like RP-NL for Nethermind-Lighthouse.

    opened by michaelsproul 0
  • Fix handling of blocks with 0 attestations

    Fix handling of blocks with 0 attestations

    Blockprint backfill is stuck on this block with 0 attestations: https://beaconcha.in/block/3952526

    This PR unblocks it by not panicking in statistics.median on the 0-length array.

    opened by michaelsproul 0
  • Implement graffiti override (for Lodestar)

    Implement graffiti override (for Lodestar)

    Add an option to the KNN classifier to exclude some clients from the classifier itself, instead classifying them based only on their graffiti matches.

    opened by michaelsproul 0
  • Add new features and interactive notebook

    Add new features and interactive notebook

    • Add interactive Jupyter notebook for exploring plots of the feature space more easily
    • Add several new features with better performance than the previous set:
      • percent_redundant_boost: the same as percent_redundant but adds +0.2 to any non-zero measurement to create separation between the blocks with no-redundancy and the blocks with redundancy
      • mean_density: same as median_density but using the mean to allow the measurement to be influenced by outliers
      • difflib_sorted_distance: based on the same idea as percent_pairwise_ordered but taking into account more of the ordering characteristics. Python's difflib is part of the standard library and provides a metric for sequence similarity in the range 0-1.
      • spearman_correlation: similar to difflib_sorted_distance, calculates Spearman's rank correlation coefficient for the list of per attestation rewards relative to its sorted version.
    • Updates the default feature set to [percent_redundant_boost, percent_pairwise_ordered, spearman_correlation, mean_density]. This feature set performed the best during cross validation on slots 3481601 to 3702784, with the training data balanced using balance.py to a max-imbalance of 2x. This improved CV performance also carried over into improved performance when classifying the most recent portion of the chain, with a minimum sensitivity of 0.80 (Prysm) and a min precision of 0.62 (Prysm). See run 13 in the spreadsheet here: https://docs.google.com/spreadsheets/d/1ly8dT8ngWeU0KQFm3Ec_SKcyxs_jzEGopQYRCGt8NXc.
    opened by michaelsproul 0
  • Enable Lodestar with option to disable

    Enable Lodestar with option to disable

    • Add graffiti regex for Lodestar
    • Add a proper arg parser to prepare_training_data. This changes the syntax for the parallel workers flag from a positional arg to an optional --num-workers flag
    • Add a --disable flag to prepare_training_data that causes training data not to be produced for the listed clients
    • Add a --disable flag to knn_classifier that ignores training data for the listed clients

    I don't think we urgently need a --disable flag on build_db because it can be used with training data that simply omits certain clients, and that will be handled gracefully.

    opened by michaelsproul 0
  • Return 404s when database contains gaps

    Return 404s when database contains gaps

    Currently blockprint's API will return 0 values when querying a section of the database for which history is missing. This can occur if the beacon node backing blockprint has been falling in and out of sync or is re-syncing and lacks a portion of history.

    At the moment these gaps can be detected via the /sync/gaps API, but this is error-prone and not obvious. It would be better if blockprint detected queries affected by the gaps and failed them explicitly so that the user doesn't have to check /sync/gaps manually. E.g. if there is a gap from slot 3623682 to 3687456 (as there is currently) then blockprint should 404 on queries like /blocks_per_client/113625/113850 rather than returning a response with 0 blocks per client for all clients.

    The reason the API is the way it is currently is that the SQL query to detect the gaps takes several seconds to evaluate, because it scans the entire table. If this query can be made to run quickly, then it will be feasible to run it for every query.

    opened by michaelsproul 0
  • Make training graffiti configurable

    Make training graffiti configurable

    Some graffiti regex should only be enabled on e.g. Prater. The ./prepare_training_data.py script should take a --prater or --mainnet flag to switch regex on/off, or a path to a file containing the regex.

    opened by michaelsproul 0
Owner
Sigma Prime
Blockchain & Information Security Services
Sigma Prime
Tool for working with Direct System Calls in Cobalt Strike's Beacon Object Files (BOF) via Syswhispers2

Tool for working with Direct System Calls in Cobalt Strike's Beacon Object Files (BOF) via Syswhispers2

null 150 Dec 31, 2022
Python: Wrangled and unpivoted gaming datasets. Tableau: created dashboards - Market Beacon and Player’s Shopping Guide.

Created two information products for GameStop. Using Python, wrangled and unpivoted datasets, and created Tableau dashboards.

Zinaida Dvoskina 2 Jan 29, 2022
Beacon Object File (BOF) to obtain a usable TGT for the current user.

Beacon Object File (BOF) to obtain a usable TGT for the current user.

Connor McGarr 109 Dec 25, 2022
A python implementation of differentiable quality diversity.

Differentiable Quality Diversity This repository is the official implementation of Differentiable Quality Diversity.

ICAROS 41 Nov 30, 2022
Improving the Transferability of Adversarial Examples with Resized-Diverse-Inputs, Diversity-Ensemble and Region Fitting

Improving the Transferability of Adversarial Examples with Resized-Diverse-Inputs, Diversity-Ensemble and Region Fitting

Junhua Zou 7 Oct 20, 2022
These are the scripts used for the project of ‘Assembly of a pan-genome for global cattle reveals missing sequence and novel structural variation, providing new insights into their diversity and evolution history’

script-SV-genotyping These are the scripts used for the project of ‘Assembly of a pan-genome for global cattle reveals missing sequence and novel stru

null 2 Aug 26, 2022
Decipher using Markov Chain Monte Carlo

Decipher using Markov Chain Monte Carlo

Science étonnante 43 Dec 24, 2022
chiarose(XCR) based on chia(XCH) source code fork, open source public chain

chia-rosechain 一个无耻的小活动 | A shameless little event 如果您喜欢这个项目,请点击star 将赠送您520朵玫瑰,可以去 facebook 留下您的(xcr)地址,和github用户名。 If you like this project, please

ddou123 376 Dec 14, 2022
A chain of stores wants a 3-month demand forecast for its 10 different stores and 50 different products.

Demand Forecasting Objective A chain store wants a machine learning project for a 3-month demand forecast for 10 different stores and 50 different pro

null 2 Jan 6, 2022
Markov Chain Composer

Markov Chain Composer Using Markov Chain to represent relationships between words in song lyrics and then generating new lyrics.. ahem interpretive po

Kylie 85 Dec 9, 2022
Automated rop chain generation

This is the accompanying code to the blog post talking about automated rop chain generation. Build the test file with: make Install the dependencies:

Christopher Roberts 14 Nov 22, 2022
Supply Chain will be a SAAS platfom to provide e-logistic facilites with most optimal

Shipp It Welcome To Supply Chain App [ Shipp It ] In "Shipp It" we are creating a full solution[web+app] for a entire supply chain from receiving orde

SAIKAT_CLAW 25 Dec 26, 2022
Probably the best way to simulate block scopes in Python

This is a package, as it says on the tin, to emulate block scoping in Python, the lack of which being a clever design choice yet sometimes a trouble.

null 88 Oct 26, 2022
Block the annoying Token Grabbers on your discord

General We have seen that in the last time many discord servers are infected by fake discord nitro links we want to put an end to this and have develo

BadTiger Network 2 Jul 16, 2022
Block when attacker want to bypass the limit of request

Block when attacker want to bypass the limit of request

iFanpS 1 Dec 1, 2021
Programming in Bioinformatics, Block 3

Programming in Bioinformatics - Block 3 I. Setting up Environment and Running the Code Create the environment using the pibi_block3.yml file with the

null 2 Dec 10, 2021
A collection of UIKit components that can be used as a Wagtail StreamField block.

Wagtail UIKit Blocks A collection of UIKit components that can be used as a Wagtail StreamField block. Available UIKit components Container Grid Headi

Krishna Prasad K 13 Dec 15, 2022
Push Prometheus metrics to VictoriaMetrics or other exporters

Push metrics from your periodic long-running jobs to existing Prometheus/VictoriaMetrics monitoring system.

olegm 14 Nov 4, 2022
fast_bss_eval is a fast implementation of the bss_eval metrics for the evaluation of blind source separation.

fast_bss_eval Do you have a zillion BSS audio files to process and it is taking days ? Is your simulation never ending ? Fear no more! fast_bss_eval i

Robin Scheibler 99 Dec 13, 2022