Streaming Fast on Ethereum

Overview

Streaming Fast on Ethereum

Stream Ethereum data like there's no tomorrow

https://streamingfast.io/

StreamingFast Demo

Impressed? Star the repo!

Getting started

  1. Get an API key from https://streamingfast.io
  2. Download a release from the releases
  3. Get streaming!

Install

Build from source:

go get -v github.com/streamingfast/streamingfast-client/cmd/sf

or download a statically linked binary for Windows, macOS or Linux.

Usage

$ export STREAMINGFAST_API_KEY="server_......................"

# Watch all calls to the UniswapV2 Router, for a single block and close
$ sf "to in ['0x7a250d5630b4cf539739df2c5dacb4c659f2488d']" 11700000 11700001

# Watch all calls to the UniswapV2 Router, include the last 100 blocks, and stream forever
$ sf "to in ['0x7a250d5630b4cf539739df2c5dacb4c659f2488d']" -100

# Continue where you left off, start from the last known cursor, stream forever
$ sf --start-cursor "10928019832019283019283" "to in ['0x7a250d5630b4cf539739df2c5dacb4c659f2488d']"

Programmatic access

Access is done through gRPC, supporting more than a dozen popular languages.

You will need those two protobuf definition files: bstream.proto and codec.proto.

Refer to the Authentication section of our docs for details.

Take inspiration from the main.go file in this repository.

Sample output

Here is a short peek into some output. Read a full sample output here.

{
  // Indicator that this is a new block, could be IRREVERSIBLE or UNDO
  "step": "STEP_NEW",

  // Use this to continue *exactly* where you left off, guaranteeing linearity of your streaming
  // processes.
  "cursor": "PWxQqpUKpA64sLwiUK9I7aWwLpcyB1toUQvhKRJLhY2goSHD1JryAGZ8YE-DmKukiRToGFOljdvOFix7-8ZWuIPrkr426CMxTy95woDt-73mefKhPFsfc-9hVuqJatLbUQ=="

  // Obtain block-level information, filtered to keep only the transactions
  // that matched your filtering criterias.
  "block": {
    "hash": "06fac697d0798bc82dd13c99c432b09664b1a6b5299dea9309911c5a42d39078",
    "number": "11740433",
    "header": {
      "parentHash": "d9e47617a4b60c6466c82f979b80046f765dc3ac341c0db113ba7428d6b192f8",
      "uncleHash": "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
      "coinbase": "ea674fdde714fd979de3edf0f56aa9716b898ec8",
      "stateRoot": "9a35f4e8dd255e63d9fadc21796b7b9eb5e77deec8d3c553156ecd3bf8299ab9",
      "transactionsRoot": "c822a62db0ac0fee7b3ee5c5c774de6541050d0fe62a0ea8cd5389b0156e622a",
      "receiptRoot": "72a07569c369fc073b374a9f930e37fbf2aa52400f7d9b47c17375211a15b1c1",
      "logsBloom": "16ba440e4d1623d1e0ab05a28c019a82d0409011b86e59f04cf9580e12f755816b3c97242ea1122651acdbda300429d89b2964c21b42c8808759180bb07c3850551d2ceaa790987a5a71ca1c1149e1e97f5400362556f455151239489a473215dd4094562ef5c0042888c08813108fcacea8119167891496a6778851d71275ec8906c975df09a0309841316c4c806acbc8312f992172d0ea5122b16f255954e3279926464d1739f70492ffd8b599b0ea0a0100d5619ad89850b34c393c9662459cbb9d43292fc0000e00b60104de054cc31c8f0215cb10981240d876b34068a4901b6e0134e4d5ac7186364e0b97e3a5842d231e01cd32795ae8f85481920c21",
      "difficulty": "10489a91f1e9e1",
      "number": "11740433",
      "gasLimit": "12481378",
      "gasUsed": "12477353",
      "timestamp": "2021-01-27T21:58:38Z",
      "extraData": "65746865726d696e652d6575312d35",
      "mixHash": "744e2e38ed64d84bf393c8535478587eea7957cd12ec68a43b0deae14136c3c1",
      "nonce": "8789940137479893166",
      "hash": "06fac697d0798bc82dd13c99c432b09664b1a6b5299dea9309911c5a42d39078"
    },

    // Execution traces of matching transactions, along withj
    // LOTS of data and details.
    "transactionTraces": [
      {
        "hash": "3ef815c7b531ca2c9da824bc9daa322edbc1ae7ba99548f2498d7ecc4279b934",
        "to": "582b409cbf6c026a639f065641f910e9d2d7f482",
        "from": "ea674fdde714fd979de3edf0f56aa9716b898ec8",
        "nonce": "30654932",
        "gasPrice": "3b9aca00",       // Gas price, hex-encoded.
        "gasLimit": "50000",
        "value": "0164732a08272565",  // ETH value being transfered, hex-encoded.
        "v": "25", "r": "c355c........a515", "s": "4b04e........c314",
        "gasUsed": "21000",
        "receipt": {
          "cumulativeGasUsed": "21000",
          "logsBloom": "00000...."
        },
        "calls": [

          // This is where it gets interesting:

          {
            "index": 1,
            "callType": "CALL",
            "caller": "ac844b604d6c600fbe55c4383a6d87920b46a160",
            "address": "d9e1ce17f2641f24ae83637ab66a2cca9c378b9f",
            "value": "",              // This would be value == 0
            "gasLimit": "476928",
            "gasConsumed": "128974",

            // You get return data between each calls
            "returnData": "00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000130feb5cd4e3ad00000000000000000000000000000000000000000000000000001bf019b3165faeed7",

            // You're also privy to the input that was given to each call in the callgraph.
            "input": "18cbafe5000000000000000000000000000000000000000000000130feb5cd4e3ad00000000000000000000000000000000000000000000000000001bec863b0fd5a700000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000ac844b604d6c600fbe55c4383a6d87920b46a160000000000000000000000000000000000000000000000000000000006011e28b00000000000000000000000000000000000000000000000000000000000000020000000000000000000000006b3595068778dd592e39a122f4f5a5cf09c90fe2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
            "executedCode": true,

            // You can observe all the internal ETH transfers, and their
            // previous and next balance.  Can't do that anywhere else!

            "balanceChanges": [
              {
                "address": "ac844b604d6c600fbe55c4383a6d87920b46a160",
                "oldValue": "1a85cdf3216e9f3c14",
                "newValue": "1a850c4f1f2f5abd34",
                "reason": "REASON_GAS_BUY"
              },
              {
                "address": "ac844b604d6c600fbe55c4383a6d87920b46a160",
                "oldValue": "1c440dea509555ac0b",
                "newValue": "1c449dbbd79f460b71",
                "reason": "REASON_GAS_REFUND"
              },

              // [... snip ...]

              {
                "address": "ea674fdde714fd979de3edf0f56aa9716b898ec8",
                "oldValue": "4fc1fd62ca11ec8278",
                "newValue": "4fc22f35454740a1f2",
                "reason": "REASON_REWARD_TRANSACTION_FEE"
              }
            ],

            // Self explanatory I guess, but pretty useful to avoid calling nodes all the time.

            "nonceChanges": [
              {
                "address": "ac844b604d6c600fbe55c4383a6d87920b46a160",
                "oldValue": "25310",
                "newValue": "25311"
              }
            ],
            "gasChanges": [
              {
                "oldValue": "500000",
                "newValue": "476928",
                // You've got all the reasons why gas is charged or refunded
                "reason": "REASON_INTRINSIC_GAS"
              },
              {
                // [... snip ...]
                "reason": "REASON_CALL_DATA_COPY"
              },
              {
                // [... snip ...]
                "reason": "REASON_REFUND_AFTER_EXECUTION"
              },

              // [... snip ...]

            ],

            // These allow you to rebuild a full graph of consumption and trace
            // gas consumption even between EVM calls
            "gasEvents": [
              {
                "id": "ID_BEFORE_CALL",
                "gas": "473893",
                "linkedCallIndex": "2"
              },
              {
                "id": "ID_AFTER_CALL",
                "gas": "471970",
                "linkedCallIndex": "2"
              },

              // [... snip ...]

            ]
          },

          // The following call is an internal transaction, a call initiated by the previous
          // one.

          {
            // 1-based index of the call within the transaction.
            "index": 2,

            // This is a 1-based index, where the value 0 would mean "no parent", or top-level
            "parentIndex": 1,

            // Can easily represent the call tree with depth
            "depth": 1,

            // This is a static call, mostly to get data out of the other contract.
            "callType": "STATIC",
            "caller": "d9e1ce17f2641f24ae83637ab66a2cca9c378b9f",
            "address": "795065dcc9f64b5614c407a6efdc400da6221fb0",
            "value": "",
            "gasLimit": "465794",
            "gasConsumed": "1217",

            // Also useful to debug or understand what's happening
            "returnData": "0000000000000000000000000000000000000000000f2484783460e8ff44c235000000000000000000000000000000000000000000001644567a439aadc9a3ea000000000000000000000000000000000000000000000000000000006011e1b4",
            "input": "0902f1ac",
            "executedCode": true
          },

          // Seems we made a third call here:

          {
            "index": 3,
            "parentIndex": 1,
            "depth": 1,
            "callType": "CALL",

            [... snip ...]

            "logs": [
             {
                "address": "6b3595068778dd592e39a122f4f5a5cf09c90fe2",
                "topics": [

                  // Yes, that's an ERC-20 transfer

                  "ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",

                  // From address

                  "000000000000000000000000ac844b604d6c600fbe55c4383a6d87920b46a160",

                  // To address
                  "000000000000000000000000795065dcc9f64b5614c407a6efdc400da6221fb0"
                ],

                // And the amount is in here:
                "data": "000000000000000000000000000000000000000000000130feb5cd4e3ad00000",

                // This is the index of this log event within the whole block.

                "blockIndex": 5
              },
              {
                "address": "6b3595068778dd592e39a122f4f5a5cf09c90fe2",
                "topics": [
                  "8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925",
                  "000000000000000000000000ac844b604d6c600fbe55c4383a6d87920b46a160",
                  "000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"
                ],
                "data": "ffffffffffffffffffffffffffffffffffffffffffbe614b550e4dc2b786ffff",
                "index": 1,
                "blockIndex": 6
              }
            ]

            // This should be helpful: you get the BALANCES (previous and next) for the
            // updated ERC-20 accounts.  This avoids hundreds of `getBalance()` calls afterward.

            "erc20BalanceChanges": [
              {
                "holderAddress": "164e948cb069f2008bda69d89b5bbdc0639f6783",
                "oldBalance": "0000000000000000000000000000000000000000028427eec9781a19c7b19ac0",
                "newBalance": "0000000000000000000000000000000000000000028427ee6162bfd660439ac0"
              },
              {
                "holderAddress": "703052a1ef835dd5842190e53896672b8f9249f1",
                "oldBalance": "00000000000000000000000000000000000000000000000068155a43676e0000",
                "newBalance": "000000000000000000000000000000000000000000000000d02ab486cedc0000"
              }
            ],
            "erc20TransferEvents": [
              {
                "from": "164e948cb069f2008bda69d89b5bbdc0639f6783",
                "to": "703052a1ef835dd5842190e53896672b8f9249f1",
                "amount": "00000000000000000000000000000000000000000000000068155a43676e0000"
              }
            ]

            // You can use this data to reverse the changes to the storage below
            // and understand which Externally Owned Address's balance is being
            // modified.. Avoid costly, and difficult to sync `getBalance()`
            // eth_calls, by using the State directly (see below)

            "keccakPreimages": {
              "0490a33f730091720d4c0d29bd2bf6a18ca8c44a423a64002ff24115dd8b8381": "000000000000000000000000ac844b604d6c600fbe55c4383a6d87920b46a1600000000000000000000000000000000000000000000000000000000000000001",

              // Take note of this one, and read below:

              "a60c07f2aed92cf0e2ca94448542cb8f5cc91bf932d411877ec1850bf66a155f": "000000000000000000000000795065dcc9f64b5614c407a6efdc400da6221fb00000000000000000000000000000000000000000000000000000000000000000",
              "b995e795ef3cc8a80fd42d092cd13c326fe2a42885cee30593e77e4b404db0e3": "000000000000000000000000ac844b604d6c600fbe55c4383a6d87920b46a1600000000000000000000000000000000000000000000000000000000000000000",
              "d7e11f80431dbe8f8fe4aba8c8c50b6b80718ea5764ac29e9b9b6e5b537bc944": "000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f0490a33f730091720d4c0d29bd2bf6a18ca8c44a423a64002ff24115dd8b8381"
            },

            // These are the *actual* values that are modified by the contract, with their balances.
            // What you usually only found on Etherscan can now be used by your algorithms
            // and apps, to speed up things and make things more consistent.

            "storageChanges": [
              {
                "address": "6b3595068778dd592e39a122f4f5a5cf09c90fe2",
                "key": "b995e795ef3cc8a80fd42d092cd13c326fe2a42885cee30593e77e4b404db0e3",
                "oldValue": "00000000000000000000000000000000000000000000062a350284837151aee9",
                "newValue": "0000000000000000000000000000000000000000000004f9364cb7353681aee9"
              },
              {
                "address": "6b3595068778dd592e39a122f4f5a5cf09c90fe2",

                // Noticed that the `keccakPreimages` above has data associated with the key
                // that follows (a60c07...)?
                // It happens to hold the address of the user's balance we're changing here:
                //   0x795065dcc9f64b5614c407a6efdc400da6221fb
                // Without the keccakPreimages, those state changes are admittedly pretty
                // opaque :)

                "key": "a60c07f2aed92cf0e2ca94448542cb8f5cc91bf932d411877ec1850bf66a155f",
                "oldValue": "0000000000000000000000000000000000000000000f2484783460e8ff44c235",
                "newValue": "0000000000000000000000000000000000000000000f25b576ea2e373a14c235"
              },
              {
                "address": "6b3595068778dd592e39a122f4f5a5cf09c90fe2",
                "key": "d7e11f80431dbe8f8fe4aba8c8c50b6b80718ea5764ac29e9b9b6e5b537bc944",
                "oldValue": "ffffffffffffffffffffffffffffffffffffffffffbe627c53c41b10f256ffff",
                "newValue": "ffffffffffffffffffffffffffffffffffffffffffbe614b550e4dc2b786ffff"
              }
            ]
          }
        ]
      }
    ],

    // These are transaction-level balance changes (not caused by an EVM Call):

    "balanceChanges": [
      {
        "address": "ea674fdde714fd979de3edf0f56aa9716b898ec8",
        "oldValue": "4fcdc5db9057ea8285",
        "newValue": "4fe98748f7a6b28285",
        "reason": "REASON_REWARD_MINE_BLOCK"
      }
    ]
  }
}

Query language

The language used as the search query is a Common Expression Language expression, as defined here:

https://github.com/google/cel-spec/blob/master/doc/langdef.md

Queries match on individual CALLs (so called internal transactions are matched individually), and any transaction with at least one matching Call will be returned.

Fields available for filtering:

  • from: string, signer or originator of the Call
  • to: string, target contract or address of the Call
  • nonce: number, the name of the action being executed
  • input: string, "0x"-prefixed hex of the input; the string will be empty if input is empty.
  • gas_price_gwei: number, gas price for the transaction, in GWEI.
  • gas_limit: number, gas limit, in units of computation.
  • erc20_from: string, the from field of an ERC20 Transfer; string empty when not an ERC20 Transfer.
  • erc20_to: string, the to field of an ERC20 Transfer; string empty when not an ERC20 Transfer.

NOTE: all string comparisons of hex characters are in lower case, so make sure to normalize your query before sending it.

Sample queries

to == '0x7a250d5630b4cf539739df2c5dacb4c659f2488d'

License

Apache 2.0

You might also like...
Go implementation of Ethereum proof of stake

Prysm: An Ethereum Consensus Implementation Written in Go This is the core repository for Prysm, a Golang implementation of the Ethereum Consensus spe

Ethereum Dapp Go API

Web3 Go Ethereum Dapp Go API, inspired by web3.js. Report Bug · Pull Request Introduction This is the Ethereum Golang API which connects to the Generi

A phoenix Chain client based on the go-ethereum fork,the new PoA consensus engine is based on the VRF algorithm.

Phoenix Official Golang implementation of the Phoenix protocol. !!!The current version is for testing and developing purposes only!!! Building the sou

Ethereum on StreamingFast

Ethereum on StreamingFast Requirements (clone repos, build stuff...) Install Geth git clone [email protected]:streamingfast/go-ethereum.git cd go-ethereu

Evmos is a scalable, high-throughput Proof-of-Stake blockchain that is fully compatible and interoperable with Ethereum.

Evmos Evmos is a scalable, high-throughput Proof-of-Stake blockchain that is fully compatible and interoperable with Ethereum. It's built using the Co

Monorepo implementing the Optimistic Ethereum protocol
Monorepo implementing the Optimistic Ethereum protocol

The Optimism Monorepo TL;DR This is the primary place where Optimism works on stuff related to Optimistic Ethereum. Documentation Extensive documentat

Tool for monitoring your Ethereum clients. Client-agnostic as it queries the standardized JSON-RPC APIs
Tool for monitoring your Ethereum clients. Client-agnostic as it queries the standardized JSON-RPC APIs

e7mon Tool for monitoring your Ethereum clients. Client-agnostic as it queries the standardized JSON-RPC APIs. However, the execution client should be

Ethereum 2.0 node multiplexer between consensus and execution

The Minority Client Run the minority client! ~Danny Ryan and/or Tim Beiko As of writing, Ethereum has multiple client implementations, but Geth / go-e

A Commander for Go implementation of official Ethereum Client

Young A Commander for Go implementation of official Ethereum Client by zhong-my. Overview Young Dependencies Young stands on the shoulder of many grea

Comments
  • Bounty Program: Build an Airdrop Honoring System with StreamingFast (on any of the network supported by StreamingFast)

    Bounty Program: Build an Airdrop Honoring System with StreamingFast (on any of the network supported by StreamingFast)

    Problem: Any airdrop that is based around anything other than just "which address held a token in their wallet at blockheight X" often leads to confusion and missed addresses.

    Bounty Details:

    • Build an Airdrop Honoring System.
    • Select a project that could be doing an airdrop soon.
    • Stream data from StreamingFast, analyse it to create a list of addresses that should be honored in the airdrop, along with a distribution algorithm.
    • Best algo wins!
    opened by anthonyzzy 13
  • Feature/airdrop

    Feature/airdrop

    Bounty Program: Build an Airdrop Honoring System with StreamingFast (on any of the network supported by StreamingFast)

    A basic implementation of Airdrop Honoring System like UNI all historical users can be claimed at a specific block range.

    opened by linruigongzi 1
  • Allow authentication endpoint to be provided on the command line

    Allow authentication endpoint to be provided on the command line

    export STREAMINGFAST_API_KEY=xxxxxxxxxxxxxxxxxxx (from alternate authentication provider)

    ./sf eth -e alternate-firehose-provider:9000 1 1 2022-05-19T18:26:35.872-0400 (sf) starting stream {"range": "1 - 1", "cursor": "", "endpoint": "alternate-firehose-provider:9000", "handle_forks": false} Error: unable to retrieve StreamingFast API token: http request failure (code 400): {"code":"request_validation_error","trace_id":"00615704e1d3eccae8e5d4960ae1e48c","message":"The request is invalid.","details":{"errors":{"api_key":["The api_key field is not a valid API key, must start with either mobile, server or web."]}}}

    opened by matthewdarwin 0
Releases(v0.1.2)
Owner
StreamingFast
Stream Ethereum data like there's no tomorrow
StreamingFast
ConsenSys Software 9 Jan 7, 2023
LEO (Low Ethereum Orbit) is an Ethereum Portal Network client.

LEO LEO (Low Ethereum Orbit) is an Ethereum Portal Network client. What makes LEO different from other Portal Network clients is that it uses libp2p f

Valist, Inc. 10 Apr 19, 2022
Ethereum-vanity-wallet - A fork of https://github.com/meehow/ethereum-vanity-wallet but the key can be exported to a JSON keystore file

ethereum-vanity-wallet See https://github.com/meehow/ethereum-vanity-wallet This version: doesn't display the private key let's you interactively expo

null 0 Jan 2, 2022
Go-ethereum - Official Golang implementation of the Ethereum protocol

Go Ethereum Official Golang implementation of the Ethereum protocol. Automated b

i06 0 Jan 4, 2022
This library aims to make it easier to interact with Ethereum through de Go programming language by adding a layer of abstraction through a new client on top of the go-ethereum library.

Simple ethereum client Simple ethereum client aims to make it easier for the developers to interact with Ethereum through a new layer of abstraction t

Jero 3 May 1, 2022
Ethermint is a scalable and interoperable Ethereum library, built on Proof-of-Stake with fast-finality using the Cosmos SDK.

Ethermint Ethermint is a scalable and interoperable Ethereum library, built on Proof-of-Stake with fast-finality using the Cosmos SDK which runs on to

Tharsis 1.7k Jan 3, 2023
Powerful Blockchain streaming data engine, based on StreamingFast Firehose technology.

Substreams - A streaming data engine for The Graph - by StreamingFast DEVELOPER PREVIEW OF SUBSTREAMS Think Fluvio for deterministic blockchain data.

StreamingFast 59 Dec 30, 2022
Huobi Eco Chain client based on the go-ethereum fork

The Huobi Open Platform is a unified infrastructure platform based on the technical, traffic and ecological resources of the Huobi Group, and will be gradually open to the blockchain industry.

null 239 Dec 31, 2022
a Golang sdk for working with DeFi protocols, and ethereum compatible blockchains

A golang sdk for working with DeFi protocols and general utilities for working with ethereum-compatible blockchains. packages bclient bindings cli con

bonedaddy 74 Dec 15, 2022
run ABI encoded data against the ethereum blockchain

Run EVM code against a database at a certain block height - Note You can't run this against a running geth node - because that would share the db and

Edgar Aroutiounian 60 Nov 11, 2021