fluxture

A crawling framework for blockchains and peer-to-peer systems


License
Apache-2.0
Install
pip install fluxture==0.0.1

Documentation

Fluxture

PyPI version Tests Slack Status

Fluxture is a lightweight crawler for peer-to-peer networks like Blockchains. It currently supports the latest version of the Bitcoin protocol: 70015. It implements the minimum amount of the Bitcoin protocol necessary to collect geographic and topological information.

Quickstart

pip3 install fluxture

Or, to install from source (e.g., for development):

$ git clone https://github.com/trailofbits/fluxture
$ cd fluxture
$ pip3 install -e '.[dev]'

Usage

To crawl the Bitcoin network, run:

fluxture crawl bitcoin --database crawl.db

The crawl database is a SQLite database that can be reused between crawls.

Geolocation

Fluxture uses the MaxMind GeoLite2 City database for geolocating nodes based upon their IP address. Various Fluxture commands will either require a path to the database, or a MaxMind license key (which will be used to automatically download the database). You can sign up for a free MaxMind license key, here.

A KML file (which can be imported to Google Maps or Google Earth) can be generated from a crawl using:

fluxture kml --group-by ip crawl.db output.kml

The geolocation database can be updated from MaxMind by running:

fluxture update-geo-db

An existing crawl database can be re-analyzed for missing or updated geolocations (e.g., from an updated MaxMind database) by running:

fluxture geolocate crawl.db

Topological Analysis

Fluxture can calculate topological statistics about the centrality of a crawled network by running:

fluxture topology crawl.db

Programmatic Interface

from fluxture.crawl_schema import CrawlDatabase

with CrawlDatabase("crawl.db") as db:
    for node in db.nodes:
        print(f"Node {node.ip}:{node.port} {node.state!s}")
        location = node.get_location()
        if location is not None:
            print(f"\tLocation:\t{location.continent_code}\t{location.country_code}\t{location.city}")
        else:
            print("\tLocation:\t?")
        version = node.get_version()
        if version is not None:
            print(f"\tVersion:\t{version.version!s}")
        else:
            print("\tVersion:\t?")
        print(f"\tOut-Edges:\t{', '.join(str(neighbor.ip) for neighbor in node.get_latest_edges())}")

License and Acknowledgements

This research was developed by Trail of Bits based upon work supported by DARPA under Contract No. HR001120C0084. Any opinions, findings and conclusions or recommendations expressed in this material are those of the authors and do not necessarily reflect the views of the United States Government or DARPA. It is licensed under the Apache 2.0 license. © 2020–2021, Trail of Bits.