From 31f3fe0ba63c70dc8540dfa7186be75de117bddc Mon Sep 17 00:00:00 2001 From: Josh Date: Thu, 11 Feb 2021 13:47:09 -0800 Subject: [PATCH 01/19] add indexer concept --- docs/concepts/indexer.md | 17 +++++++++++++++++ website/sidebars.json | 1 + 2 files changed, 18 insertions(+) create mode 100644 docs/concepts/indexer.md diff --git a/docs/concepts/indexer.md b/docs/concepts/indexer.md new file mode 100644 index 00000000000..f60b119755b --- /dev/null +++ b/docs/concepts/indexer.md @@ -0,0 +1,17 @@ +--- +id: indexer +title: NEAR Indexer +sidebar_label: Indexer +--- + +> NEAR Indexer is a library included with [nearcore](https://github.com/near/nearcore) that allows you to run a node on the network which listens for targeted information on the blockchain. + +The [NEAR Indexer Framework](https://github.com/near/nearcore/tree/master/chain/indexer) provides the logic of polling a node for blocks produced in a network then aggregating and streaming these blocks to a listener. + +To better understand this, blockchain data is optimized for serialized writes, one block at a time, as the chain is being created. Querying the blockchain for data about a specific block or account is a fairly stragightforward or "narrow" query. However, querying data across many blocks can be cumbersome because we have to aggregate results from multiple single-block queries. We can consider these "wide" queries. + +An indexer listens to the stream of data as it's being written on chain and can then be immediately filtered and processed to detect interesting events or patterns. This same stream of data can then be written to a permanent database for later data analysis using a convenient query language like SQL. + +One example that highlights the need for a wide query is when you use a seed phrase to recover one or more accounts. Since a seed phrase essentially represents a signing key pair, the recovery is for **all** accounts that share the associated public key. Therefore, when a seed phrase is used to recover an account via [NEAR Wallet](https://wallet.near.org/), the query requires that **all accounts** with a matching public key are found and recovered. + +The easiest way to achieve this "wide query" is to utilize a database that has been filled by an indexing service. For this purpose we’ve built the [NEAR Indexer for wallet](https://github.com/near/near-indexer-for-wallet) which listens to all actions on chain that might create or delete [access keys](/docs/concepts/account#access-keys) and stores them into a relational database for easier querying of accounts. diff --git a/website/sidebars.json b/website/sidebars.json index 6c8bce5b3cf..feb48696f19 100644 --- a/website/sidebars.json +++ b/website/sidebars.json @@ -9,6 +9,7 @@ "concepts/storage-staking", "concepts/epoch", "concepts/gas", + "concepts/indexer", "concepts/networks", "concepts/transaction" ], From ce4125c27cefaa8610cc5527231c123d901a2b46 Mon Sep 17 00:00:00 2001 From: Josh Date: Thu, 11 Feb 2021 18:16:43 -0800 Subject: [PATCH 02/19] indexer project setup --- docs/concepts/indexer.md | 13 +++--- docs/tools/near-indexer.md | 96 ++++++++++++++++++++++++++++++++++++++ website/sidebars.json | 3 +- 3 files changed, 105 insertions(+), 7 deletions(-) create mode 100644 docs/tools/near-indexer.md diff --git a/docs/concepts/indexer.md b/docs/concepts/indexer.md index f60b119755b..0d7f82c7486 100644 --- a/docs/concepts/indexer.md +++ b/docs/concepts/indexer.md @@ -4,14 +4,15 @@ title: NEAR Indexer sidebar_label: Indexer --- -> NEAR Indexer is a library included with [nearcore](https://github.com/near/nearcore) that allows you to run a node on the network which listens for targeted information on the blockchain. - -The [NEAR Indexer Framework](https://github.com/near/nearcore/tree/master/chain/indexer) provides the logic of polling a node for blocks produced in a network then aggregating and streaming these blocks to a listener. +> NEAR Indexer is a library included with [nearcore](https://github.com/near/nearcore) that allows you to run a node on the network which listens for targeted information on the blockchain. The [NEAR Indexer Framework](https://github.com/near/nearcore/tree/master/chain/indexer) provides the logic of polling a node for blocks produced in a network then aggregating and streaming these blocks to a listener. To better understand this, blockchain data is optimized for serialized writes, one block at a time, as the chain is being created. Querying the blockchain for data about a specific block or account is a fairly stragightforward or "narrow" query. However, querying data across many blocks can be cumbersome because we have to aggregate results from multiple single-block queries. We can consider these "wide" queries. -An indexer listens to the stream of data as it's being written on chain and can then be immediately filtered and processed to detect interesting events or patterns. This same stream of data can then be written to a permanent database for later data analysis using a convenient query language like SQL. +- An indexer listens to the stream of data as it's being written on chain and can then be immediately filtered and processed to detect interesting events or patterns. +- This stream of data can then be written to a permanent database for later data analysis using a convenient query language like SQL. + +- One example that highlights the need for a "wide query" is when you use a seed phrase to recover one or more accounts. Since a seed phrase essentially represents a signing key pair, the recovery is for **all** accounts that share the associated public key. Therefore, when a seed phrase is used to recover an account via [NEAR Wallet](https://wallet.near.org/), the query requires that **all accounts** with a matching public key are found and recovered. -One example that highlights the need for a wide query is when you use a seed phrase to recover one or more accounts. Since a seed phrase essentially represents a signing key pair, the recovery is for **all** accounts that share the associated public key. Therefore, when a seed phrase is used to recover an account via [NEAR Wallet](https://wallet.near.org/), the query requires that **all accounts** with a matching public key are found and recovered. +- The easiest way to achieve a "wide query" is to utilize a database that has been filled by an indexing service. For this purpose we’ve built the [NEAR Indexer for wallet](https://github.com/near/near-indexer-for-wallet) which listens to all actions on chain that might create or delete [access keys](/docs/concepts/account#access-keys) and stores them into a relational database for easier querying of accounts. -The easiest way to achieve this "wide query" is to utilize a database that has been filled by an indexing service. For this purpose we’ve built the [NEAR Indexer for wallet](https://github.com/near/near-indexer-for-wallet) which listens to all actions on chain that might create or delete [access keys](/docs/concepts/account#access-keys) and stores them into a relational database for easier querying of accounts. +[ **[Click Here](/docs/tools/near-indexer)** ] For a walkthrough on creating an indexer. diff --git a/docs/tools/near-indexer.md b/docs/tools/near-indexer.md new file mode 100644 index 00000000000..36108c577de --- /dev/null +++ b/docs/tools/near-indexer.md @@ -0,0 +1,96 @@ +--- +id: near-indexer +title: NEAR Indexer +sidebar_label: NEAR Indexer +--- + +> The [NEAR Indexer Framework](https://github.com/near/nearcore/tree/master/chain/indexer) allows you to run a network node that listens for targeted information on the blockchain. For more information see [indexer](/docs/concepts/index) under our "Concepts" section. + +## Project Setup + +### Pre-requisites + +- If you haven't already, please [install Rust](https://docs.near.org/docs/tutorials/contracts/intro-to-rust#3-step-rust-installation) + +### Creating your project + +To create a new project with Rust, you will start by creating a new binary by running the following command in your terminal: + +```bash +cargo new --bin example-indexer +``` + +Now change directory into your newly created project: + +```bash +cd example-indexer +``` + +Inside this folder you will find: + +- `src` folder with a `main.rs` file inside +- `cargo.toml` + +### Create Rust Toolchain + +Next, you will need to create a Rust toolchain that mirrors the one in [`nearcore`](https://github.com/near/nearcore/blob/master/rust-toolchain): + +To do this, run the following command in the root of your project: _(be sure to check the link above for the correct `nightly` version)_ + +```bash +echo nightly-2020-10-08 > rust-toolchain +``` + +### Add dependencies + +**1) In your `cargo.toml` file add `near-indexer` under [dependencies]:** + +```toml +[dependencies] +near-indexer = { git = "https://github.com/near/nearcore" } +``` + +**Note:** While it is fine to omit specific commit hash for tutorial purpose we highly recommend to freeze near-indexer dependency for specific commit from `nearcore` repository. _(Example below)_ + +```toml +near-indexer = { git = "https://github.com/nearprotocol/nearcore", rev="29fcaf3b8c81a4c0371d105054ce251355382a77" } +``` + +**2) Add `actix`, `openssl-probe`, & `tokio`** + +```toml +actix = "0.11.0-beta.1" +openssl-probe = { version = "0.1.2" } +tokio = { version = "1.1", features = ["sync"] } +``` + +**3) Once complete your `cargo.toml` dependencies should look something like this:** + +```toml +[dependencies] +near-indexer = { git = "https://github.com/near/nearcore" } +actix = "0.11.0-beta.1" +openssl-probe = { version = "0.1.2" } +tokio = { version = "1.1", features = ["sync"] } +``` + +**4) Install and check dependencies** + +To install these dependencies and check to make sure everything works run: + +```bash +cargo check +``` + +
+heads up

+ +If the cargo check command fails with some errors it might be because of different versions of underlying dependencies. + +- A quick solution is to copy `Cargo.lock` from `nearcore` repository [ [here](https://raw.githubusercontent.com/near/nearcore/master/Cargo.lock) ] and replace it with the contents of your project's `Cargo.lock` file. +- After this is complete, rerun `cargo check` to see if this resolves your errors. + +
+ +--- + diff --git a/website/sidebars.json b/website/sidebars.json index feb48696f19..1a448333a8b 100644 --- a/website/sidebars.json +++ b/website/sidebars.json @@ -81,7 +81,8 @@ "Tools": [ "tools/near-cli", "tools/near-explorer", - "tools/near-wallet" + "tools/near-wallet", + "tools/near-indexer" ] }, "tutorials": { From ec5324a9b3b5f54f40ed23f670ee73e065c44980 Mon Sep 17 00:00:00 2001 From: Josh Date: Thu, 11 Feb 2021 20:01:57 -0800 Subject: [PATCH 03/19] constructing main.rs --- docs/tools/near-indexer.md | 60 +++++++++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/docs/tools/near-indexer.md b/docs/tools/near-indexer.md index 36108c577de..fc75ac790c3 100644 --- a/docs/tools/near-indexer.md +++ b/docs/tools/near-indexer.md @@ -6,11 +6,13 @@ sidebar_label: NEAR Indexer > The [NEAR Indexer Framework](https://github.com/near/nearcore/tree/master/chain/indexer) allows you to run a network node that listens for targeted information on the blockchain. For more information see [indexer](/docs/concepts/index) under our "Concepts" section. +--- + ## Project Setup ### Pre-requisites -- If you haven't already, please [install Rust](https://docs.near.org/docs/tutorials/contracts/intro-to-rust#3-step-rust-installation) +This project will require Rust. If not already installed, please [follow these instructions](https://docs.near.org/docs/tutorials/contracts/intro-to-rust#3-step-rust-installation). ### Creating your project @@ -94,3 +96,59 @@ If the cargo check command fails with some errors it might be because of differe --- +## Constructing `main.rs` + +> Now that we have our basic setup, we need to update `main.rs`. + +In your preferred IDE, navigate to and open `src/main.rs`. Here you'll notice a generic function `main()`: + +```rs +fn main() { + println!("Hello, world!"); +} +``` + +Clear the contents of this function and lets begin building your indexer logic! + +**1) First we will configure our indexer by defining `IndexerConfig` instance:** + +```rs +let indexer_config = near_indexer::IndexerConfig { + home_dir: std::path::PathBuf::from(near_indexer::get_default_home()), + sync_mode: near_indexer::SyncModeEnum::FromInterruption, + await_for_node_synced: near_indexer::AwaitForNodeSyncedEnum::WaitForFullSync, + }; +``` + +_Note that the NEAR Indexer Framework re-exports `get_default_home()` from `nearcore` and resolves its path to `.near` located in your home directory. ( ~/.near )_ + +**2) Next we need to define an `Indexer` instance and start it immediately:** + +```rs +actix::System::builder() + .stop_on_panic(true) + .run(move || { + let indexer = near_indexer::Indexer::new(indexer_config); + let stream = indexer.streamer(); + actix::spawn(listen_blocks(stream)); + }) + .unwrap(); +``` + +_The `Indexer` instance requires a runtime to work and because Rust does not have one by default, we use `actix` as a runtime dependency._ + +**3) Create `listen_blocks()`:** + +```rs +async fn listen_blocks(mut stream: tokio::sync::mpsc::Receiver) { + while let Some(streamer_message) = stream.recv().await { + eprintln!("{:#?}", streamer_message); + } +} +``` + +_This function listens for the creation of new blocks and prints details to the console each time one is discovered. This works by passing a mutable variable `stream` that has a `Receiver` type from `tokio::sync::mpsc`. The `stream` variable has a method `recv()` that we can use in our while loop that determine if a new block was "received" and what action we want to take when one is discovered. In this case we are simply printing to the console._ + +> Our example indexer is ready! Run `cargo check` to ensure you setup everything correctly. +> +> - Next is the tricky part, connecting it to a network... From d3cf6dbbddcc451d46dc5c2162cccb01e25fdb8b Mon Sep 17 00:00:00 2001 From: Josh Date: Thu, 11 Feb 2021 23:11:18 -0800 Subject: [PATCH 04/19] configure network / run indexer --- docs/tools/near-indexer.md | 351 ++++++++++++++++++++++++++++++++++++- 1 file changed, 343 insertions(+), 8 deletions(-) diff --git a/docs/tools/near-indexer.md b/docs/tools/near-indexer.md index fc75ac790c3..7e2a2a4b410 100644 --- a/docs/tools/near-indexer.md +++ b/docs/tools/near-indexer.md @@ -8,11 +8,15 @@ sidebar_label: NEAR Indexer --- -## Project Setup +## Setup -### Pre-requisites +### Requirements -This project will require Rust. If not already installed, please [follow these instructions](https://docs.near.org/docs/tutorials/contracts/intro-to-rust#3-step-rust-installation). +- [Rust.](https://www.rust-lang.org/) If not already installed, please [follow these instructions](https://docs.near.org/docs/tutorials/contracts/intro-to-rust#3-step-rust-installation). +- Minimunm hardware: + - 4 CPU cores + - 16GB RAM + - 100GB SSD _(HDD will **not** work)_ ### Creating your project @@ -110,7 +114,9 @@ fn main() { Clear the contents of this function and lets begin building your indexer logic! -**1) First we will configure our indexer by defining `IndexerConfig` instance:** +### Indexer Config + +- First we will configure our indexer by defining `IndexerConfig` instance: ```rs let indexer_config = near_indexer::IndexerConfig { @@ -122,6 +128,8 @@ let indexer_config = near_indexer::IndexerConfig { _Note that the NEAR Indexer Framework re-exports `get_default_home()` from `nearcore` and resolves its path to `.near` located in your home directory. ( ~/.near )_ +### Indexer Runtime + **2) Next we need to define an `Indexer` instance and start it immediately:** ```rs @@ -137,7 +145,9 @@ actix::System::builder() _The `Indexer` instance requires a runtime to work and because Rust does not have one by default, we use `actix` as a runtime dependency._ -**3) Create `listen_blocks()`:** +### Block Listener + +- Create `listen_blocks()`: ```rs async fn listen_blocks(mut stream: tokio::sync::mpsc::Receiver) { @@ -149,6 +159,331 @@ async fn listen_blocks(mut stream: tokio::sync::mpsc::Receiver Our example indexer is ready! Run `cargo check` to ensure you setup everything correctly. -> -> - Next is the tricky part, connecting it to a network... +### Code Review + +- `main.rs` should now look like the code block below with two separate functions: `main()` and `listen_blocks` + +```rs +fn main() { + let indexer_config = near_indexer::IndexerConfig { + home_dir: std::path::PathBuf::from(near_indexer::get_default_home()), + sync_mode: near_indexer::SyncModeEnum::FromInterruption, + await_for_node_synced: near_indexer::AwaitForNodeSyncedEnum::WaitForFullSync, + }; + + actix::System::builder() + .stop_on_panic(true) + .run(move || { + let indexer = near_indexer::Indexer::new(indexer_config); + let stream = indexer.streamer(); + actix::spawn(listen_blocks(stream)); + }) + .unwrap(); +} + +async fn listen_blocks(mut stream: tokio::sync::mpsc::Receiver) { + while let Some(streamer_message) = stream.recv().await { + eprintln!("{:#?}", streamer_message); + } +} +``` + +### Test + +- Run `cargo check` to ensure you setup everything correctly before proceeding to connecting to a network. + +--- + +## Configure Network + +> If you connect to `testnet` or `mainnet` your node will need to be fully synced with the network. This means your node will need to download **all the blocks** and apply **all the changes** to your instance of the blockchain state. Because this process can take anywhere from a few hours to a few days we will connect to a `localnet` so you can get your indexer up and running in a matter of minutes. + +### Setup + +The node will need three things: + +1) Configs +2) Network's genesis file +3) Key to run the node + +All of this can be generated via nearcore's `neard` crate, but an easier way to create this is to use the exposed `init_configs` from NEAR Indexer Framework. This will create a folder that keeps the database of the blockchain state and whenever you syncing your node this data folder will be the same as the other nodes on the network. + +
+heads up

+ +A regular node runs with the archival option disabled by default in its `config.json`. This means that the node has a "garbage collector" enabled which removes old data from storage after five [epochs](/docs/concepts/epoch) or approx. 2.5 days. An [archival node](/docs/roles/integrator/exchange-integration#running-an-archival-node) means that the garbage collector is disabled and **all** of the data is kept on the node. + +You don't necessarily need to have an archival node for your indexer. In most cases you can live a happy life along with the garbage collector while you store necessary data in a separate database (either relational or nosql) much like we do with [NEAR Indexer for Wallet](https://github.com/near/near-indexer-for-wallet). + +However, an archival node may be necessary if you want to build an indexer which needs to find and save all transactions related to specific accounts from the beginning of the chain (from genesis). + +
+ +### Generating Configs + +> A typical setup is to generate configs for `localnet` whenever you pass `init`, and start the indexer whenever you pass `run` as a command line argument. + +- To start, we will add the following line at the the beginning of the `main()` function: + +```rs +let args: Vec = std::env::args().collect(); +``` + +- Now let's make a `home_dir` variable that you will use in a few places. Add this line right after the previous one: + +```rs +let home_dir = std::path::PathBuf::from(near_indexer::get_default_home()); +``` + +- Next add a condition to check if you pass either `init` or `run` as an argument: + +```rs +match args[1].as_str() { + "init" => {}, + "run" => {}, + _ => panic!("ERROR: You have to pass `init` or `run` arg."), +} +``` + +- Inside the `init` code block add the `init_configs` function: + +```rs +match args[1].as_str() { + "init" => near_indexer::init_configs( + &home_dir, + Some("localnet"), + None, + None, + 1, + false, + None, + true, + None, + );, + "run" => {}, + _ => panic!("ERROR: You have to pass `init` or `run` arg."), +} + +``` + +- For the `run` code block move the previous indexer start logic like so: + +```rs +match args[1].as_str() { + "init" => near_indexer::init_configs( + &home_dir, + Some("localnet"), + None, + None, + 1, + false, + None, + true, + None, + );, + "run" => { + let indexer_config = near_indexer::IndexerConfig { + home_dir: std::path::PathBuf::from(near_indexer::get_default_home()), + sync_mode: near_indexer::SyncModeEnum::FromInterruption, + await_for_node_synced: near_indexer::AwaitForNodeSyncedEnum::WaitForFullSync, + }; + }, + _ => panic!("ERROR: You have to pass `init` or `run` arg."), +} + +``` + +- If you like, you can refactor the code a bit by creating a `command` variable leaving your final `main()` function looking something like this: + +```rs +fn main() { + let args: Vec = std::env::args().collect(); + let home_dir = std::path::PathBuf::from(near_indexer::get_default_home()); + + let command = args.get(1) + .map(|arg| arg.as_str()) + .expect("You need to provide a command: `init` or `run` as arg"); + + match command { + "init" => near_indexer::init_configs( + &home_dir, + Some("localnet"), + None, + None, + 1, + false, + None, + true, + None, + ), + "run" => { + let indexer_config = near_indexer::IndexerConfig { + home_dir: std::path::PathBuf::from(near_indexer::get_default_home()), + sync_mode: near_indexer::SyncModeEnum::FromInterruption, + await_for_node_synced: near_indexer::AwaitForNodeSyncedEnum::WaitForFullSync, + }; + + actix::System::builder() + .stop_on_panic(true) + .run(move || { + let indexer = near_indexer::Indexer::new(indexer_config); + let stream = indexer.streamer(); + actix::spawn(listen_blocks(stream)); + }) + .unwrap(); + } + _ => panic!("You have to pass `init` or `run` arg"), + }; +} +``` + +### Initialize configurations + +- Last step in in configuring your network is to initialize. To do this, simply run: + +```bash +cargo run --init +``` + +## Run the Indexer + +- You're ready to start the Indexer! To run enter the following command in your terminal: + +```bash +cargo run -- run +``` + +- Ouch! You most likely got the following error: + +```bash +thread 'main' panicked at 'Indexer should track at least one shard. +Tip: You may want to update /Users/joshford/.near/config.json with `"tracked_shards": [0]` + ', /Users/joshford/.cargo/git/checkouts/nearcore-5bf7818cf2261fd0/d7b0ca4/chain/indexer/src/lib.rs:65:9 +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +Panic in Arbiter thread, shutting down system. +``` + +- Don't worry, this one is an easy fix! + + - Open your `config.json` located in the `.near` folder in the root of your home directory. _( ~/.near/config.json )_ + - In this file, locate: `"tracked_shards": []` and change the value to [0]. + - Save the file and try running your indexer again. + +```bash +cargo run -- run +``` + +It’s alive! 🎉 + +You should now see print to your terminal of `StreamerMessage` structures like the example below. :) + +
+**Example Stream:** +

+ +```json +StreamerMessage { + block: BlockView { + author: "test.near", + header: BlockHeaderView { + height: 5, + epoch_id: `11111111111111111111111111111111`, + next_epoch_id: `4vf1hV5j63QLAPpiWQELXHAfJjHCgq1uooMrBNPMu5Uq`, + hash: `4LdFTm4TfSvAEQBARvQ28VQqXNBhWruhSvxnBWxvFfVr`, + prev_hash: `2QsMGwmLxg6QL615BPuX5nZttHnoGPDtKmmanxP92vBW`, + prev_state_root: `CHAfu2kedNvLMKmK7gFx3knAp7URPnzw7GcEEnZWqzSJ`, + chunk_receipts_root: `9ETNjrt6MkwTgSVMMbpukfxRshSD1avBUUa4R4NuqwHv`, + chunk_headers_root: `9MJ7Lp84Sk1ky78u8naJJcHCyFnv8DUrfirtaxHvoRbA`, + chunk_tx_root: `7tkzFg8RHBmMw1ncRJZCCZAizgq4rwCftTKYLce8RU8t`, + outcome_root: `7tkzFg8RHBmMw1ncRJZCCZAizgq4rwCftTKYLce8RU8t`, + chunks_included: 1, + challenges_root: `11111111111111111111111111111111`, + timestamp: 1612624576082671000, + timestamp_nanosec: 1612624576082671000, + random_value: `2bAoaYkYnBmvFtQCyu8VeE5JxfH8oTwYTrs5vZMtEZvF`, + validator_proposals: [], + chunk_mask: [ + true, + ], + gas_price: 1000000000, + rent_paid: 0, + validator_reward: 0, + total_supply: 2050000000000000000000000000000000, + challenges_result: [], + last_final_block: `7ZJzz48xYV4oU7kkXfK6UjX7ydE5pJGzShGJUV8TX2YY`, + last_ds_final_block: `2QsMGwmLxg6QL615BPuX5nZttHnoGPDtKmmanxP92vBW`, + next_bp_hash: `EcqXCDTULxNaDncsiVU165HW7gMQNafzz5qekXgA6QdG`, + block_merkle_root: `9yMLpVqRCSoFdB7ZvXRR344wcWBCodi6njCV95Vhqtfg`, + approvals: [ + Some( + ed25519:RoMpcZtLWToDS6DEHmJXZUCYW8SLVyo8ZFgYTQLfNegtJjEd6CMSohhTZWJX2gqU637w2Xyfksezitu51D1vyLQ, + ), + ], + signature: ed25519:3kpaw6bTxMRtxhhZQDqit9TCxaG6s4z91AgGN5Vp4fwkLcotUwVU7b1PivXKH361bj7kZ6wuhGsTLuvMd1HZraSN, + latest_protocol_version: 42, + }, + chunks: [ + ChunkHeaderView { + chunk_hash: `FosjAojVKDzPqH9q9jTPJR7KciJ1TkWTnhCtM6pe8c9s`, + prev_block_hash: `2QsMGwmLxg6QL615BPuX5nZttHnoGPDtKmmanxP92vBW`, + outcome_root: `11111111111111111111111111111111`, + prev_state_root: `HLi9RaXG8ejkiehaiSwDZ31zQ8gQGXJyf34RmXAER6EB`, + encoded_merkle_root: `79Bt7ivt9Qhp3c6dJYnueaTyPVweYxZRpQHASRRAiyuy`, + encoded_length: 8, + height_created: 5, + height_included: 5, + shard_id: 0, + gas_used: 0, + gas_limit: 1000000000000000, + rent_paid: 0, + validator_reward: 0, + balance_burnt: 0, + outgoing_receipts_root: `H4Rd6SGeEBTbxkitsCdzfu9xL9HtZ2eHoPCQXUeZ6bW4`, + tx_root: `11111111111111111111111111111111`, + validator_proposals: [], + signature: ed25519:2aBb9sjzcNgaceVftvPrQMFVtQxKCZBjC7aGToqhQcJtnQQD1y8iBHq8NxsynYiuiYxHd22Tsznjz7emT4yk4Rjx, + }, + ], + }, + chunks: [ + IndexerChunkView { + author: "test.near", + header: ChunkHeaderView { + chunk_hash: `FosjAojVKDzPqH9q9jTPJR7KciJ1TkWTnhCtM6pe8c9s`, + prev_block_hash: `2QsMGwmLxg6QL615BPuX5nZttHnoGPDtKmmanxP92vBW`, + outcome_root: `11111111111111111111111111111111`, + prev_state_root: `HLi9RaXG8ejkiehaiSwDZ31zQ8gQGXJyf34RmXAER6EB`, + encoded_merkle_root: `79Bt7ivt9Qhp3c6dJYnueaTyPVweYxZRpQHASRRAiyuy`, + encoded_length: 8, + height_created: 5, + height_included: 0, + shard_id: 0, + gas_used: 0, + gas_limit: 1000000000000000, + rent_paid: 0, + validator_reward: 0, + balance_burnt: 0, + outgoing_receipts_root: `H4Rd6SGeEBTbxkitsCdzfu9xL9HtZ2eHoPCQXUeZ6bW4`, + tx_root: `11111111111111111111111111111111`, + validator_proposals: [], + signature: ed25519:2aBb9sjzcNgaceVftvPrQMFVtQxKCZBjC7aGToqhQcJtnQQD1y8iBHq8NxsynYiuiYxHd22Tsznjz7emT4yk4Rjx, + }, + transactions: [], + receipts: [], + receipt_execution_outcomes: [], + }, + ], + state_changes: [], +} +``` + +

+ +## Indexer examples + +- [Flux Capacitor](https://github.com/fluxprotocol/flux-capacitor) +- [NEAR Explorer Indexer](https://github.com/near/near-indexer-for-explorer) +- [NEAR Wallet Indexer](https://github.com/near/near-indexer-for-wallet) + + +Did you create your own indexer? Submit a PR and add it to the list! From 2b249f3f02b96c60bf98ad038ea2fde06bb128ca Mon Sep 17 00:00:00 2001 From: Josh Date: Thu, 11 Feb 2021 23:20:33 -0800 Subject: [PATCH 05/19] fix indexer link --- docs/tools/near-indexer.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tools/near-indexer.md b/docs/tools/near-indexer.md index 7e2a2a4b410..2de002b2a7b 100644 --- a/docs/tools/near-indexer.md +++ b/docs/tools/near-indexer.md @@ -4,7 +4,7 @@ title: NEAR Indexer sidebar_label: NEAR Indexer --- -> The [NEAR Indexer Framework](https://github.com/near/nearcore/tree/master/chain/indexer) allows you to run a network node that listens for targeted information on the blockchain. For more information see [indexer](/docs/concepts/index) under our "Concepts" section. +> The [NEAR Indexer Framework](https://github.com/near/nearcore/tree/master/chain/indexer) allows you to run a network node that listens for targeted information on the blockchain. For more information see [indexer](/docs/concepts/indexer) under our "Concepts" section. --- From 7f097d88967aadd4d0c6c251c2b0021c858f6c35 Mon Sep 17 00:00:00 2001 From: Josh Date: Thu, 11 Feb 2021 23:31:20 -0800 Subject: [PATCH 06/19] minor edits --- docs/tools/near-indexer.md | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/docs/tools/near-indexer.md b/docs/tools/near-indexer.md index 2de002b2a7b..21501ced931 100644 --- a/docs/tools/near-indexer.md +++ b/docs/tools/near-indexer.md @@ -34,8 +34,8 @@ cd example-indexer Inside this folder you will find: -- `src` folder with a `main.rs` file inside - `cargo.toml` +- `src` folder with a `main.rs` file inside ### Create Rust Toolchain @@ -56,7 +56,7 @@ echo nightly-2020-10-08 > rust-toolchain near-indexer = { git = "https://github.com/near/nearcore" } ``` -**Note:** While it is fine to omit specific commit hash for tutorial purpose we highly recommend to freeze near-indexer dependency for specific commit from `nearcore` repository. _(Example below)_ +**Note:** While it is fine to omit specific commit hash for this tutorial we highly recommend to freeze near-indexer dependency for specific commit from the `nearcore` repository. _(Example below)_ ```toml near-indexer = { git = "https://github.com/nearprotocol/nearcore", rev="29fcaf3b8c81a4c0371d105054ce251355382a77" } @@ -70,7 +70,7 @@ openssl-probe = { version = "0.1.2" } tokio = { version = "1.1", features = ["sync"] } ``` -**3) Once complete your `cargo.toml` dependencies should look something like this:** +**3) Once complete, your `cargo.toml` dependencies should look something like this:** ```toml [dependencies] @@ -82,7 +82,7 @@ tokio = { version = "1.1", features = ["sync"] } **4) Install and check dependencies** -To install these dependencies and check to make sure everything works run: +Install and check dependencies by running: ```bash cargo check @@ -116,7 +116,7 @@ Clear the contents of this function and lets begin building your indexer logic! ### Indexer Config -- First we will configure our indexer by defining `IndexerConfig` instance: +- First we will configure our indexer by defining the `IndexerConfig` instance: ```rs let indexer_config = near_indexer::IndexerConfig { @@ -143,7 +143,7 @@ actix::System::builder() .unwrap(); ``` -_The `Indexer` instance requires a runtime to work and because Rust does not have one by default, we use `actix` as a runtime dependency._ +_The `Indexer` instance requires a runtime to work and because Rust does not have one by default, we will use `actix` as a runtime dependency._ ### Block Listener @@ -157,7 +157,7 @@ async fn listen_blocks(mut stream: tokio::sync::mpsc::Receiver If you connect to `testnet` or `mainnet` your node will need to be fully synced with the network. This means your node will need to download **all the blocks** and apply **all the changes** to your instance of the blockchain state. Because this process can take anywhere from a few hours to a few days we will connect to a `localnet` so you can get your indexer up and running in a matter of minutes. +> If you connect to `testnet` or `mainnet` your node will need to be fully synced with the network. This means the node will need to download **all the blocks** and apply **all the changes** to _your_ instance of the blockchain state. Because this process can take anywhere from a few hours to a few days we will connect to a `localnet` so you can get your indexer up and running in a matter of minutes. ### Setup @@ -206,16 +206,14 @@ The node will need three things: 2) Network's genesis file 3) Key to run the node -All of this can be generated via nearcore's `neard` crate, but an easier way to create this is to use the exposed `init_configs` from NEAR Indexer Framework. This will create a folder that keeps the database of the blockchain state and whenever you syncing your node this data folder will be the same as the other nodes on the network. +All of this can be generated via nearcore's `neard` crate, but an easier way is to use the exposed `init_configs` from NEAR Indexer Framework. This will create a folder that keeps the database of the blockchain state and whenever you sync your node this data folder will be the same as the other nodes on the network.
heads up

A regular node runs with the archival option disabled by default in its `config.json`. This means that the node has a "garbage collector" enabled which removes old data from storage after five [epochs](/docs/concepts/epoch) or approx. 2.5 days. An [archival node](/docs/roles/integrator/exchange-integration#running-an-archival-node) means that the garbage collector is disabled and **all** of the data is kept on the node. -You don't necessarily need to have an archival node for your indexer. In most cases you can live a happy life along with the garbage collector while you store necessary data in a separate database (either relational or nosql) much like we do with [NEAR Indexer for Wallet](https://github.com/near/near-indexer-for-wallet). - -However, an archival node may be necessary if you want to build an indexer which needs to find and save all transactions related to specific accounts from the beginning of the chain (from genesis). +You don't necessarily need to have an archival node for your indexer. In most cases you can live a happy life along with the garbage collector while you store necessary data in a separate database (either relational or nosql) much like we do with [NEAR Indexer for Wallet](https://github.com/near/near-indexer-for-wallet). However, an archival node may be necessary if you want to build an indexer which needs to find and save all transactions related to specific accounts from the beginning of the chain (from genesis).
@@ -223,13 +221,13 @@ However, an archival node may be necessary if you want to build an indexer which > A typical setup is to generate configs for `localnet` whenever you pass `init`, and start the indexer whenever you pass `run` as a command line argument. -- To start, we will add the following line at the the beginning of the `main()` function: +- To start, add the following line at the the beginning of the `main()` function: ```rs let args: Vec = std::env::args().collect(); ``` -- Now let's make a `home_dir` variable that you will use in a few places. Add this line right after the previous one: +- Now create a `home_dir` variable that you will use in a few places. Add this line right after the previous one: ```rs let home_dir = std::path::PathBuf::from(near_indexer::get_default_home()); From 3938fcbf2a46d172fbe64840d9330bb5b8af9bd5 Mon Sep 17 00:00:00 2001 From: Josh Ford Date: Fri, 12 Feb 2021 08:29:29 -0800 Subject: [PATCH 07/19] Update docs/tools/near-indexer.md Co-authored-by: Bohdan Khorolets --- docs/tools/near-indexer.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tools/near-indexer.md b/docs/tools/near-indexer.md index 21501ced931..77282f5a331 100644 --- a/docs/tools/near-indexer.md +++ b/docs/tools/near-indexer.md @@ -56,7 +56,7 @@ echo nightly-2020-10-08 > rust-toolchain near-indexer = { git = "https://github.com/near/nearcore" } ``` -**Note:** While it is fine to omit specific commit hash for this tutorial we highly recommend to freeze near-indexer dependency for specific commit from the `nearcore` repository. _(Example below)_ +> **Note:** While it is fine to omit specific commit hash for this tutorial we highly recommend to freeze near-indexer dependency for specific commit from the `nearcore` repository. _(Example below)_ ```toml near-indexer = { git = "https://github.com/nearprotocol/nearcore", rev="29fcaf3b8c81a4c0371d105054ce251355382a77" } From 7dfe958f4f4f9579a643530dd8781baa98692f1b Mon Sep 17 00:00:00 2001 From: Josh Ford Date: Fri, 12 Feb 2021 08:29:40 -0800 Subject: [PATCH 08/19] Update docs/tools/near-indexer.md Co-authored-by: Bohdan Khorolets --- docs/tools/near-indexer.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tools/near-indexer.md b/docs/tools/near-indexer.md index 77282f5a331..c304d57b6c0 100644 --- a/docs/tools/near-indexer.md +++ b/docs/tools/near-indexer.md @@ -34,7 +34,7 @@ cd example-indexer Inside this folder you will find: -- `cargo.toml` +- `Cargo.toml` - `src` folder with a `main.rs` file inside ### Create Rust Toolchain From c373ff73968f788e9929ffdcba77a34458edb6d3 Mon Sep 17 00:00:00 2001 From: Josh Ford Date: Fri, 12 Feb 2021 08:29:50 -0800 Subject: [PATCH 09/19] Update docs/tools/near-indexer.md Co-authored-by: Bohdan Khorolets --- docs/tools/near-indexer.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tools/near-indexer.md b/docs/tools/near-indexer.md index c304d57b6c0..f52935e3487 100644 --- a/docs/tools/near-indexer.md +++ b/docs/tools/near-indexer.md @@ -49,7 +49,7 @@ echo nightly-2020-10-08 > rust-toolchain ### Add dependencies -**1) In your `cargo.toml` file add `near-indexer` under [dependencies]:** +**1) In your `Cargo.toml` file add `near-indexer` under [dependencies]:** ```toml [dependencies] From 7ea8abc41dba8af93bd1d5788ec54a934cccb3cf Mon Sep 17 00:00:00 2001 From: Josh Ford Date: Fri, 12 Feb 2021 08:29:56 -0800 Subject: [PATCH 10/19] Update docs/tools/near-indexer.md Co-authored-by: Bohdan Khorolets --- docs/tools/near-indexer.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tools/near-indexer.md b/docs/tools/near-indexer.md index f52935e3487..4bb29af783c 100644 --- a/docs/tools/near-indexer.md +++ b/docs/tools/near-indexer.md @@ -70,7 +70,7 @@ openssl-probe = { version = "0.1.2" } tokio = { version = "1.1", features = ["sync"] } ``` -**3) Once complete, your `cargo.toml` dependencies should look something like this:** +**3) Once complete, your `Cargo.toml` dependencies should look something like this:** ```toml [dependencies] From e2f7e7220405c159dd4494572f869f8648206f21 Mon Sep 17 00:00:00 2001 From: Josh Ford Date: Fri, 12 Feb 2021 08:35:17 -0800 Subject: [PATCH 11/19] Update docs/tools/near-indexer.md Co-authored-by: Bohdan Khorolets --- docs/tools/near-indexer.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tools/near-indexer.md b/docs/tools/near-indexer.md index 4bb29af783c..30cd3244bb1 100644 --- a/docs/tools/near-indexer.md +++ b/docs/tools/near-indexer.md @@ -337,7 +337,7 @@ fn main() { ### Initialize configurations -- Last step in in configuring your network is to initialize. To do this, simply run: +- Last step is in configuring your network is to initialize. To do this, simply run: ```bash cargo run --init From 5284f32f721e864c500a7627e6f036271517b0b5 Mon Sep 17 00:00:00 2001 From: Josh Ford Date: Fri, 12 Feb 2021 08:43:21 -0800 Subject: [PATCH 12/19] Update docs/tools/near-indexer.md Co-authored-by: Bohdan Khorolets --- docs/tools/near-indexer.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tools/near-indexer.md b/docs/tools/near-indexer.md index 30cd3244bb1..b415abf1ce6 100644 --- a/docs/tools/near-indexer.md +++ b/docs/tools/near-indexer.md @@ -340,7 +340,7 @@ fn main() { - Last step is in configuring your network is to initialize. To do this, simply run: ```bash -cargo run --init +cargo run -- init ``` ## Run the Indexer From caee7062c4c9b56b7bb30f9372de481414cdc728 Mon Sep 17 00:00:00 2001 From: Bohdan Khorolets Date: Sun, 28 Feb 2021 10:19:54 +0200 Subject: [PATCH 13/19] Update near-indexer tutorial --- docs/tools/near-indexer.md | 247 +++++++++++++++---------------------- 1 file changed, 99 insertions(+), 148 deletions(-) diff --git a/docs/tools/near-indexer.md b/docs/tools/near-indexer.md index b415abf1ce6..8724a22c64f 100644 --- a/docs/tools/near-indexer.md +++ b/docs/tools/near-indexer.md @@ -62,12 +62,14 @@ near-indexer = { git = "https://github.com/near/nearcore" } near-indexer = { git = "https://github.com/nearprotocol/nearcore", rev="29fcaf3b8c81a4c0371d105054ce251355382a77" } ``` -**2) Add `actix`, `openssl-probe`, & `tokio`** +**2) Add `actix`, `openssl-probe`, `tokio` and `serde`** ```toml actix = "0.11.0-beta.1" openssl-probe = { version = "0.1.2" } tokio = { version = "1.1", features = ["sync"] } +serde = { version = "1", features = [ "derive" ] } +serde_json = "1.0.55" ``` **3) Once complete, your `Cargo.toml` dependencies should look something like this:** @@ -78,6 +80,8 @@ near-indexer = { git = "https://github.com/near/nearcore" } actix = "0.11.0-beta.1" openssl-probe = { version = "0.1.2" } tokio = { version = "1.1", features = ["sync"] } +serde = { version = "1", features = [ "derive" ] } +serde_json = "1.0.55" ``` **4) Install and check dependencies** @@ -91,7 +95,7 @@ cargo check
heads up

-If the cargo check command fails with some errors it might be because of different versions of underlying dependencies. +If the cargo check command fails with some errors it might be because of different versions of underlying dependencies. - A quick solution is to copy `Cargo.lock` from `nearcore` repository [ [here](https://raw.githubusercontent.com/near/nearcore/master/Cargo.lock) ] and replace it with the contents of your project's `Cargo.lock` file. - After this is complete, rerun `cargo check` to see if this resolves your errors. @@ -102,7 +106,7 @@ If the cargo check command fails with some errors it might be because of differe ## Constructing `main.rs` -> Now that we have our basic setup, we need to update `main.rs`. +> Now that we have our basic setup, we need to update `main.rs`. In your preferred IDE, navigate to and open `src/main.rs`. Here you'll notice a generic function `main()`: @@ -152,7 +156,7 @@ _The `Indexer` instance requires a runtime to work and because Rust does not hav ```rs async fn listen_blocks(mut stream: tokio::sync::mpsc::Receiver) { while let Some(streamer_message) = stream.recv().await { - eprintln!("{:#?}", streamer_message); + eprintln!("{}", serde_json::to_value(streamer_message).unwrap()); } } ``` @@ -183,7 +187,7 @@ fn main() { async fn listen_blocks(mut stream: tokio::sync::mpsc::Receiver) { while let Some(streamer_message) = stream.recv().await { - eprintln!("{:#?}", streamer_message); + println!("{}", serde_json::to_value(streamer_message).unwrap()); } } ``` @@ -243,21 +247,23 @@ match args[1].as_str() { } ``` -- Inside the `init` code block add the `init_configs` function: +- Inside the `init` code block we're going to instantiate structure with necessary arguments to generate configs and will pass it to the function to actually generate configs: ```rs match args[1].as_str() { - "init" => near_indexer::init_configs( - &home_dir, - Some("localnet"), - None, - None, - 1, - false, - None, - true, - None, - );, + "init" => { + let config_args = near_indexer::InitConfigArgs { + chain_id: Some("localnet".to_string()), + account_id: None, + test_seed: None, + num_shards: 1, + fast: false, + genesis: None, + download: true, + download_genesis_url: None, + }; + near_indexer::indexer_init_configs(&home_dir, config_args); + }, "run" => {}, _ => panic!("ERROR: You have to pass `init` or `run` arg."), } @@ -268,17 +274,19 @@ match args[1].as_str() { ```rs match args[1].as_str() { - "init" => near_indexer::init_configs( - &home_dir, - Some("localnet"), - None, - None, - 1, - false, - None, - true, - None, - );, + "init" => { + let config_args = near_indexer::InitConfigArgs { + chain_id: Some("localnet".to_string()), + account_id: None, + test_seed: None, + num_shards: 1, + fast: false, + genesis: None, + download: false, + download_genesis_url: None, + }; + near_indexer::indexer_init_configs(&home_dir, config_args); + }, "run" => { let indexer_config = near_indexer::IndexerConfig { home_dir: std::path::PathBuf::from(near_indexer::get_default_home()), @@ -303,32 +311,34 @@ fn main() { .expect("You need to provide a command: `init` or `run` as arg"); match command { - "init" => near_indexer::init_configs( - &home_dir, - Some("localnet"), - None, - None, - 1, - false, - None, - true, - None, - ), + "init" => { + let config_args = near_indexer::InitConfigArgs { + chain_id: Some("localnet".to_string()), + account_id: None, + test_seed: None, + num_shards: 1, + fast: false, + genesis: None, + download: false, + download_genesis_url: None, + }; + near_indexer::indexer_init_configs(&home_dir, config_args); + }, "run" => { let indexer_config = near_indexer::IndexerConfig { - home_dir: std::path::PathBuf::from(near_indexer::get_default_home()), - sync_mode: near_indexer::SyncModeEnum::FromInterruption, - await_for_node_synced: near_indexer::AwaitForNodeSyncedEnum::WaitForFullSync, - }; - - actix::System::builder() - .stop_on_panic(true) - .run(move || { - let indexer = near_indexer::Indexer::new(indexer_config); - let stream = indexer.streamer(); - actix::spawn(listen_blocks(stream)); - }) - .unwrap(); + home_dir: std::path::PathBuf::from(near_indexer::get_default_home()), + sync_mode: near_indexer::SyncModeEnum::FromInterruption, + await_for_node_synced: near_indexer::AwaitForNodeSyncedEnum::WaitForFullSync, + }; + + actix::System::builder() + .stop_on_panic(true) + .run(move || { + let indexer = near_indexer::Indexer::new(indexer_config); + let stream = indexer.streamer(); + actix::spawn(listen_blocks(stream)); + }) + .unwrap(); } _ => panic!("You have to pass `init` or `run` arg"), }; @@ -354,7 +364,7 @@ cargo run -- run - Ouch! You most likely got the following error: ```bash -thread 'main' panicked at 'Indexer should track at least one shard. +thread 'main' panicked at 'Indexer should track at least one shard. Tip: You may want to update /Users/joshford/.near/config.json with `"tracked_shards": [0]` ', /Users/joshford/.cargo/git/checkouts/nearcore-5bf7818cf2261fd0/d7b0ca4/chain/indexer/src/lib.rs:65:9 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace @@ -371,112 +381,53 @@ Panic in Arbiter thread, shutting down system. cargo run -- run ``` -It’s alive! 🎉 +It’s alive! 🎉 -You should now see print to your terminal of `StreamerMessage` structures like the example below. :) +You should now see print to your terminal of `StreamerMessage` as a JSON object structures like the example below. :)
**Example Stream:**

```json -StreamerMessage { - block: BlockView { - author: "test.near", - header: BlockHeaderView { - height: 5, - epoch_id: `11111111111111111111111111111111`, - next_epoch_id: `4vf1hV5j63QLAPpiWQELXHAfJjHCgq1uooMrBNPMu5Uq`, - hash: `4LdFTm4TfSvAEQBARvQ28VQqXNBhWruhSvxnBWxvFfVr`, - prev_hash: `2QsMGwmLxg6QL615BPuX5nZttHnoGPDtKmmanxP92vBW`, - prev_state_root: `CHAfu2kedNvLMKmK7gFx3knAp7URPnzw7GcEEnZWqzSJ`, - chunk_receipts_root: `9ETNjrt6MkwTgSVMMbpukfxRshSD1avBUUa4R4NuqwHv`, - chunk_headers_root: `9MJ7Lp84Sk1ky78u8naJJcHCyFnv8DUrfirtaxHvoRbA`, - chunk_tx_root: `7tkzFg8RHBmMw1ncRJZCCZAizgq4rwCftTKYLce8RU8t`, - outcome_root: `7tkzFg8RHBmMw1ncRJZCCZAizgq4rwCftTKYLce8RU8t`, - chunks_included: 1, - challenges_root: `11111111111111111111111111111111`, - timestamp: 1612624576082671000, - timestamp_nanosec: 1612624576082671000, - random_value: `2bAoaYkYnBmvFtQCyu8VeE5JxfH8oTwYTrs5vZMtEZvF`, - validator_proposals: [], - chunk_mask: [ - true, - ], - gas_price: 1000000000, - rent_paid: 0, - validator_reward: 0, - total_supply: 2050000000000000000000000000000000, - challenges_result: [], - last_final_block: `7ZJzz48xYV4oU7kkXfK6UjX7ydE5pJGzShGJUV8TX2YY`, - last_ds_final_block: `2QsMGwmLxg6QL615BPuX5nZttHnoGPDtKmmanxP92vBW`, - next_bp_hash: `EcqXCDTULxNaDncsiVU165HW7gMQNafzz5qekXgA6QdG`, - block_merkle_root: `9yMLpVqRCSoFdB7ZvXRR344wcWBCodi6njCV95Vhqtfg`, - approvals: [ - Some( - ed25519:RoMpcZtLWToDS6DEHmJXZUCYW8SLVyo8ZFgYTQLfNegtJjEd6CMSohhTZWJX2gqU637w2Xyfksezitu51D1vyLQ, - ), - ], - signature: ed25519:3kpaw6bTxMRtxhhZQDqit9TCxaG6s4z91AgGN5Vp4fwkLcotUwVU7b1PivXKH361bj7kZ6wuhGsTLuvMd1HZraSN, - latest_protocol_version: 42, - }, - chunks: [ - ChunkHeaderView { - chunk_hash: `FosjAojVKDzPqH9q9jTPJR7KciJ1TkWTnhCtM6pe8c9s`, - prev_block_hash: `2QsMGwmLxg6QL615BPuX5nZttHnoGPDtKmmanxP92vBW`, - outcome_root: `11111111111111111111111111111111`, - prev_state_root: `HLi9RaXG8ejkiehaiSwDZ31zQ8gQGXJyf34RmXAER6EB`, - encoded_merkle_root: `79Bt7ivt9Qhp3c6dJYnueaTyPVweYxZRpQHASRRAiyuy`, - encoded_length: 8, - height_created: 5, - height_included: 5, - shard_id: 0, - gas_used: 0, - gas_limit: 1000000000000000, - rent_paid: 0, - validator_reward: 0, - balance_burnt: 0, - outgoing_receipts_root: `H4Rd6SGeEBTbxkitsCdzfu9xL9HtZ2eHoPCQXUeZ6bW4`, - tx_root: `11111111111111111111111111111111`, - validator_proposals: [], - signature: ed25519:2aBb9sjzcNgaceVftvPrQMFVtQxKCZBjC7aGToqhQcJtnQQD1y8iBHq8NxsynYiuiYxHd22Tsznjz7emT4yk4Rjx, - }, - ], - }, - chunks: [ - IndexerChunkView { - author: "test.near", - header: ChunkHeaderView { - chunk_hash: `FosjAojVKDzPqH9q9jTPJR7KciJ1TkWTnhCtM6pe8c9s`, - prev_block_hash: `2QsMGwmLxg6QL615BPuX5nZttHnoGPDtKmmanxP92vBW`, - outcome_root: `11111111111111111111111111111111`, - prev_state_root: `HLi9RaXG8ejkiehaiSwDZ31zQ8gQGXJyf34RmXAER6EB`, - encoded_merkle_root: `79Bt7ivt9Qhp3c6dJYnueaTyPVweYxZRpQHASRRAiyuy`, - encoded_length: 8, - height_created: 5, - height_included: 0, - shard_id: 0, - gas_used: 0, - gas_limit: 1000000000000000, - rent_paid: 0, - validator_reward: 0, - balance_burnt: 0, - outgoing_receipts_root: `H4Rd6SGeEBTbxkitsCdzfu9xL9HtZ2eHoPCQXUeZ6bW4`, - tx_root: `11111111111111111111111111111111`, - validator_proposals: [], - signature: ed25519:2aBb9sjzcNgaceVftvPrQMFVtQxKCZBjC7aGToqhQcJtnQQD1y8iBHq8NxsynYiuiYxHd22Tsznjz7emT4yk4Rjx, - }, - transactions: [], - receipts: [], - receipt_execution_outcomes: [], - }, - ], - state_changes: [], -} +{"block":{"author":"test.near","header":{"height":75,"epoch_id":"11111111111111111111111111111111","next_epoch_id":"4vf1hV5j63QLAPpiWQELXHAfJjHCgq1uooMrBNPMu5Uq","hash":"4kSDb7bnK2vYFkWnCUwLk6V24ZemGoejZQFXM4L5op5A","prev_hash":"Bi618Wbu7NAuxH5cqkXkBd1iH7Lue5YmQj16Xf3A2vTb","prev_state_root":"CHAfu2kedNvLMKmK7gFx3knAp7URPnzw7GcEEnZWqzSJ","chunk_receipts_root":"9ETNjrt6MkwTgSVMMbpukfxRshSD1avBUUa4R4NuqwHv","chunk_headers_root":"CDY1cuGvzr2YTM57ST7uVqEDX27rbgCauXq1hjHo9jjW","chunk_tx_root":"7tkzFg8RHBmMw1ncRJZCCZAizgq4rwCftTKYLce8RU8t","outcome_root":"7tkzFg8RHBmMw1ncRJZCCZAizgq4rwCftTKYLce8RU8t","chunks_included":1,"challenges_root":"11111111111111111111111111111111","timestamp":1614356082504891000,"timestamp_nanosec":"1614356082504891000","random_value":"CVNoqr7nXckRhE8dHGYHn8H49wT4gprM8YQhhZSj3awx","validator_proposals":[],"chunk_mask":[true],"gas_price":"1000000000","rent_paid":"0","validator_reward":"0","total_supply":"2050000000000000000000000000000000","challenges_result":[],"last_final_block":"Fnzr8a91ZV2UTGUgmuMY3Ar6RamgVQYTASdsiuHxof3n","last_ds_final_block":"Bi618Wbu7NAuxH5cqkXkBd1iH7Lue5YmQj16Xf3A2vTb","next_bp_hash":"EcqXCDTULxNaDncsiVU165HW7gMQNafzz5qekXgA6QdG","block_merkle_root":"6Wv8SQeWHJcZpLKKQ8sR7wnHrtbdMpfMQMkfvbWBAKGY","approvals":["ed25519:2N4HJaBCwzu1F9jMAKGYgUTKPB4VVvBGfZ6e7qM3P4bkFHkDohfmJmfvQtcEaRQN9Q8dSo4iEEA25tqRtuRWf1N3"],"signature":"ed25519:4c9owM6uZb8Qbq2KYNXhmpmfpkKX4ygvvvFgMAy1qz5aZu7v3MmHKpavnJp7eTYeUpm8yyRzcXUpjoCpygjnZsF4","latest_protocol_version":42},"chunks":[{"chunk_hash":"62ZVbyWBga6nSZixsWm6KAHkZ6FbYhY7jvDEt3Gc3HP3","prev_block_hash":"Bi618Wbu7NAuxH5cqkXkBd1iH7Lue5YmQj16Xf3A2vTb","outcome_root":"11111111111111111111111111111111","prev_state_root":"HLi9RaXG8ejkiehaiSwDZ31zQ8gQGXJyf34RmXAER6EB","encoded_merkle_root":"79Bt7ivt9Qhp3c6dJYnueaTyPVweYxZRpQHASRRAiyuy","encoded_length":8,"height_created":75,"height_included":75,"shard_id":0,"gas_used":0,"gas_limit":1000000000000000,"rent_paid":"0","validator_reward":"0","balance_burnt":"0","outgoing_receipts_root":"H4Rd6SGeEBTbxkitsCdzfu9xL9HtZ2eHoPCQXUeZ6bW4","tx_root":"11111111111111111111111111111111","validator_proposals":[],"signature":"ed25519:3XDErgyunAmhzaqie8uNbjPhgZMwjhTXADmfZM7TtdMKXaqawfRJhKCeavsmEe2rrMKeCuLk6ef8uhZT1952Vffi"}]},"chunks":[{"author":"test.near","header":{"chunk_hash":"62ZVbyWBga6nSZixsWm6KAHkZ6FbYhY7jvDEt3Gc3HP3","prev_block_hash":"Bi618Wbu7NAuxH5cqkXkBd1iH7Lue5YmQj16Xf3A2vTb","outcome_root":"11111111111111111111111111111111","prev_state_root":"HLi9RaXG8ejkiehaiSwDZ31zQ8gQGXJyf34RmXAER6EB","encoded_merkle_root":"79Bt7ivt9Qhp3c6dJYnueaTyPVweYxZRpQHASRRAiyuy","encoded_length":8,"height_created":75,"height_included":0,"shard_id":0,"gas_used":0,"gas_limit":1000000000000000,"rent_paid":"0","validator_reward":"0","balance_burnt":"0","outgoing_receipts_root":"H4Rd6SGeEBTbxkitsCdzfu9xL9HtZ2eHoPCQXUeZ6bW4","tx_root":"11111111111111111111111111111111","validator_proposals":[],"signature":"ed25519:3XDErgyunAmhzaqie8uNbjPhgZMwjhTXADmfZM7TtdMKXaqawfRJhKCeavsmEe2rrMKeCuLk6ef8uhZT1952Vffi"},"transactions":[],"receipts":[],"receipt_execution_outcomes":[]}],"state_changes":[]} ```

+You can use [`jq`](https://stedolan.github.io/jq/) and running your indexer like + +```bash +cargo run -- run | jq +``` + +to make pretty print JSON and you can do different stuff with JSON with `jq` + +For example if you're interest only in transactions you can run indexer like: + +```bash +cargo run -- run | jq '{block_height: .block.header.height, transactions: .chunks[0].transactions}' +``` + +And you'll get + +```json +{ + "block_height": 145, + "transactions": [] +} +{ + "block_height": 146, + "transactions": [] +} +{ + "block_height": 147, + "transactions": [] +} +``` + +You can play around with the data easily because it is returned as a JSON object. + ## Indexer examples - [Flux Capacitor](https://github.com/fluxprotocol/flux-capacitor) From bbbe2badad0b8d353aed1aa829ee253eb4e5d1b4 Mon Sep 17 00:00:00 2001 From: Bohdan Khorolets Date: Mon, 1 Mar 2021 20:44:53 +0200 Subject: [PATCH 14/19] Add the link to final code of example-indexer --- docs/tools/near-indexer.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/tools/near-indexer.md b/docs/tools/near-indexer.md index 8724a22c64f..10bb030f75a 100644 --- a/docs/tools/near-indexer.md +++ b/docs/tools/near-indexer.md @@ -18,6 +18,8 @@ sidebar_label: NEAR Indexer - 16GB RAM - 100GB SSD _(HDD will **not** work)_ +All the code written in this tutorial can be found [here](https://github.com/near-examples/indexer-tutorials/tree/master/example-indexer) + ### Creating your project To create a new project with Rust, you will start by creating a new binary by running the following command in your terminal: @@ -428,6 +430,8 @@ And you'll get You can play around with the data easily because it is returned as a JSON object. +You can find the code we've written in this tutorial in [this repository](https://github.com/near-examples/indexer-tutorials/tree/master/example-indexer) + ## Indexer examples - [Flux Capacitor](https://github.com/fluxprotocol/flux-capacitor) From 3c4c7e09e9a37f32c188d40450d4b7d32487c1ec Mon Sep 17 00:00:00 2001 From: Bohdan Khorolets Date: Tue, 2 Mar 2021 16:41:32 +0200 Subject: [PATCH 15/19] Update example indexer code according to recent updated in nearcore --- docs/tools/near-indexer.md | 65 ++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 34 deletions(-) diff --git a/docs/tools/near-indexer.md b/docs/tools/near-indexer.md index 10bb030f75a..b04cbbc1bc5 100644 --- a/docs/tools/near-indexer.md +++ b/docs/tools/near-indexer.md @@ -67,7 +67,7 @@ near-indexer = { git = "https://github.com/nearprotocol/nearcore", rev="29fcaf3b **2) Add `actix`, `openssl-probe`, `tokio` and `serde`** ```toml -actix = "0.11.0-beta.1" +actix = "0.11.0-beta.2" openssl-probe = { version = "0.1.2" } tokio = { version = "1.1", features = ["sync"] } serde = { version = "1", features = [ "derive" ] } @@ -79,7 +79,7 @@ serde_json = "1.0.55" ```toml [dependencies] near-indexer = { git = "https://github.com/near/nearcore" } -actix = "0.11.0-beta.1" +actix = "0.11.0-beta.2" openssl-probe = { version = "0.1.2" } tokio = { version = "1.1", features = ["sync"] } serde = { version = "1", features = [ "derive" ] } @@ -139,14 +139,13 @@ _Note that the NEAR Indexer Framework re-exports `get_default_home()` from `near **2) Next we need to define an `Indexer` instance and start it immediately:** ```rs -actix::System::builder() - .stop_on_panic(true) - .run(move || { - let indexer = near_indexer::Indexer::new(indexer_config); - let stream = indexer.streamer(); - actix::spawn(listen_blocks(stream)); - }) - .unwrap(); +let sys = actix::System::new(); +sys.block_on(async move { + let indexer = near_indexer::Indexer::new(indexer_config); + let stream = indexer.streamer(); + actix::spawn(listen_blocks(stream)); +}); +sys.run().unwrap(); ``` _The `Indexer` instance requires a runtime to work and because Rust does not have one by default, we will use `actix` as a runtime dependency._ @@ -171,20 +170,19 @@ _This function listens for the creation of new blocks and prints details to the ```rs fn main() { - let indexer_config = near_indexer::IndexerConfig { + let indexer_config = near_indexer::IndexerConfig { home_dir: std::path::PathBuf::from(near_indexer::get_default_home()), sync_mode: near_indexer::SyncModeEnum::FromInterruption, await_for_node_synced: near_indexer::AwaitForNodeSyncedEnum::WaitForFullSync, }; - actix::System::builder() - .stop_on_panic(true) - .run(move || { + let sys = actix::System::new(); + sys.block_on(async move { let indexer = near_indexer::Indexer::new(indexer_config); let stream = indexer.streamer(); actix::spawn(listen_blocks(stream)); - }) - .unwrap(); + }); + sys.run().unwrap(); } async fn listen_blocks(mut stream: tokio::sync::mpsc::Receiver) { @@ -284,18 +282,18 @@ match args[1].as_str() { num_shards: 1, fast: false, genesis: None, - download: false, + download: true, download_genesis_url: None, }; near_indexer::indexer_init_configs(&home_dir, config_args); - }, + } "run" => { - let indexer_config = near_indexer::IndexerConfig { + let indexer_config = near_indexer::IndexerConfig { home_dir: std::path::PathBuf::from(near_indexer::get_default_home()), sync_mode: near_indexer::SyncModeEnum::FromInterruption, await_for_node_synced: near_indexer::AwaitForNodeSyncedEnum::WaitForFullSync, - }; - }, + }; + } _ => panic!("ERROR: You have to pass `init` or `run` arg."), } @@ -308,7 +306,8 @@ fn main() { let args: Vec = std::env::args().collect(); let home_dir = std::path::PathBuf::from(near_indexer::get_default_home()); - let command = args.get(1) + let command = args + .get(1) .map(|arg| arg.as_str()) .expect("You need to provide a command: `init` or `run` as arg"); @@ -321,29 +320,27 @@ fn main() { num_shards: 1, fast: false, genesis: None, - download: false, + download: true, download_genesis_url: None, }; near_indexer::indexer_init_configs(&home_dir, config_args); - }, + } "run" => { let indexer_config = near_indexer::IndexerConfig { home_dir: std::path::PathBuf::from(near_indexer::get_default_home()), sync_mode: near_indexer::SyncModeEnum::FromInterruption, await_for_node_synced: near_indexer::AwaitForNodeSyncedEnum::WaitForFullSync, }; - - actix::System::builder() - .stop_on_panic(true) - .run(move || { - let indexer = near_indexer::Indexer::new(indexer_config); - let stream = indexer.streamer(); - actix::spawn(listen_blocks(stream)); - }) - .unwrap(); + let sys = actix::System::new(); + sys.block_on(async move { + let indexer = near_indexer::Indexer::new(indexer_config); + let stream = indexer.streamer(); + actix::spawn(listen_blocks(stream)); + }); + sys.run().unwrap(); } _ => panic!("You have to pass `init` or `run` arg"), - }; + } } ``` From 9be3c1509e41aa475983480e91be1884773037a3 Mon Sep 17 00:00:00 2001 From: Bohdan Khorolets Date: Wed, 3 Mar 2021 10:04:57 +0200 Subject: [PATCH 16/19] Apply suggestions from code review Co-authored-by: Vlad Frolov --- docs/concepts/indexer.md | 2 +- docs/tools/near-indexer.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/concepts/indexer.md b/docs/concepts/indexer.md index 0d7f82c7486..bc2837f2e68 100644 --- a/docs/concepts/indexer.md +++ b/docs/concepts/indexer.md @@ -6,7 +6,7 @@ sidebar_label: Indexer > NEAR Indexer is a library included with [nearcore](https://github.com/near/nearcore) that allows you to run a node on the network which listens for targeted information on the blockchain. The [NEAR Indexer Framework](https://github.com/near/nearcore/tree/master/chain/indexer) provides the logic of polling a node for blocks produced in a network then aggregating and streaming these blocks to a listener. -To better understand this, blockchain data is optimized for serialized writes, one block at a time, as the chain is being created. Querying the blockchain for data about a specific block or account is a fairly stragightforward or "narrow" query. However, querying data across many blocks can be cumbersome because we have to aggregate results from multiple single-block queries. We can consider these "wide" queries. +To better understand this, blockchain data is optimized for serialized writes, one block at a time, as the chain is being created. Querying the blockchain for data about a specific block or account is a fairly straightforward or "narrow" query. However, querying data across many blocks can be cumbersome because we have to aggregate results from multiple single-block queries. We can consider these "wide" queries. - An indexer listens to the stream of data as it's being written on chain and can then be immediately filtered and processed to detect interesting events or patterns. - This stream of data can then be written to a permanent database for later data analysis using a convenient query language like SQL. diff --git a/docs/tools/near-indexer.md b/docs/tools/near-indexer.md index b04cbbc1bc5..073f8a8a992 100644 --- a/docs/tools/near-indexer.md +++ b/docs/tools/near-indexer.md @@ -13,7 +13,7 @@ sidebar_label: NEAR Indexer ### Requirements - [Rust.](https://www.rust-lang.org/) If not already installed, please [follow these instructions](https://docs.near.org/docs/tutorials/contracts/intro-to-rust#3-step-rust-installation). -- Minimunm hardware: +- Recommended hardware: - 4 CPU cores - 16GB RAM - 100GB SSD _(HDD will **not** work)_ From 14c38662c70a6dd86af4000851eaa8cbc6f4cd62 Mon Sep 17 00:00:00 2001 From: Josh Ford Date: Wed, 10 Mar 2021 06:47:52 -0800 Subject: [PATCH 17/19] Update docs/tools/near-indexer.md Co-authored-by: Vlad Frolov --- docs/tools/near-indexer.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tools/near-indexer.md b/docs/tools/near-indexer.md index 073f8a8a992..c921d2cb64c 100644 --- a/docs/tools/near-indexer.md +++ b/docs/tools/near-indexer.md @@ -112,7 +112,7 @@ If the cargo check command fails with some errors it might be because of differe In your preferred IDE, navigate to and open `src/main.rs`. Here you'll notice a generic function `main()`: -```rs +```rust fn main() { println!("Hello, world!"); } From 44cc5016a59f102e22fa85945124182c2029aab1 Mon Sep 17 00:00:00 2001 From: Josh Date: Wed, 10 Mar 2021 16:08:14 -0800 Subject: [PATCH 18/19] update rust tags --- docs/concepts/data-collections.md | 12 ++++++------ docs/faq/faq.md | 4 ++-- docs/tools/near-indexer.md | 20 ++++++++++---------- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/docs/concepts/data-collections.md b/docs/concepts/data-collections.md index 99f2094c020..bad7079388c 100644 --- a/docs/concepts/data-collections.md +++ b/docs/concepts/data-collections.md @@ -289,7 +289,7 @@ map.getSome(key) - To add data: -```rs +```rust pub fn add_lookup_map(&mut self, key: String, value: String) { self.lookup_map.insert(&key, &value); } @@ -297,7 +297,7 @@ pub fn add_lookup_map(&mut self, key: String, value: String) { - To get data: -```rs +```rust pub fn get_lookup_map(&self, key: String) -> String { match self.lookup_map.get(&key) { Some(value) => { @@ -326,7 +326,7 @@ pub fn get_lookup_map(&self, key: String) -> String { - To add data: -```rs +```rust pub fn add_unordered_map(&mut self, key: String, value: String) { self.unordered_map.insert(&key, &value); } @@ -334,7 +334,7 @@ pub fn add_unordered_map(&mut self, key: String, value: String) { - To get data: -```rs +```rust pub fn get_unordered_map(&self, key: String) -> String { match self.unordered_map.get(&key) { Some(value) => { @@ -365,7 +365,7 @@ pub fn get_unordered_map(&self, key: String) -> String { - To add data: -```rs +```rust pub fn add_tree_map(&mut self, key: String, value: String) { self.tree_map.insert(&key, &value); } @@ -373,7 +373,7 @@ pub fn add_tree_map(&mut self, key: String, value: String) { - To get data: -```rs +```rust pub fn get_tree_map(&self, key: String) -> String { match self.tree_map.get(&key) { Some(value) => { diff --git a/docs/faq/faq.md b/docs/faq/faq.md index a64b19016e6..9918b72b00c 100644 --- a/docs/faq/faq.md +++ b/docs/faq/faq.md @@ -18,7 +18,7 @@ Each method call on a contract is recorded as a transaction. This transaction ca **Rust** -```rs +```rust env::signer_account_pk() ``` @@ -52,7 +52,7 @@ See here for an [example in our Guestbook](https://github.com/near-examples/gues See here for an [example in our Rust library test fixtures](https://github.com/near/near-sdk-rs/blob/master/examples/cross-contract-high-level/src/lib.rs#L125) -```rs +```rust ext_status_message::set_status(message, &account_id, 0, SINGLE_CALL_GAS); ``` diff --git a/docs/tools/near-indexer.md b/docs/tools/near-indexer.md index c921d2cb64c..620b9871f9a 100644 --- a/docs/tools/near-indexer.md +++ b/docs/tools/near-indexer.md @@ -124,7 +124,7 @@ Clear the contents of this function and lets begin building your indexer logic! - First we will configure our indexer by defining the `IndexerConfig` instance: -```rs +```rust let indexer_config = near_indexer::IndexerConfig { home_dir: std::path::PathBuf::from(near_indexer::get_default_home()), sync_mode: near_indexer::SyncModeEnum::FromInterruption, @@ -138,7 +138,7 @@ _Note that the NEAR Indexer Framework re-exports `get_default_home()` from `near **2) Next we need to define an `Indexer` instance and start it immediately:** -```rs +```rust let sys = actix::System::new(); sys.block_on(async move { let indexer = near_indexer::Indexer::new(indexer_config); @@ -154,7 +154,7 @@ _The `Indexer` instance requires a runtime to work and because Rust does not hav - Create `listen_blocks()`: -```rs +```rust async fn listen_blocks(mut stream: tokio::sync::mpsc::Receiver) { while let Some(streamer_message) = stream.recv().await { eprintln!("{}", serde_json::to_value(streamer_message).unwrap()); @@ -168,7 +168,7 @@ _This function listens for the creation of new blocks and prints details to the - `main.rs` should now look like the code block below with two separate functions: `main()` and `listen_blocks` -```rs +```rust fn main() { let indexer_config = near_indexer::IndexerConfig { home_dir: std::path::PathBuf::from(near_indexer::get_default_home()), @@ -227,19 +227,19 @@ You don't necessarily need to have an archival node for your indexer. In most ca - To start, add the following line at the the beginning of the `main()` function: -```rs +```rust let args: Vec = std::env::args().collect(); ``` - Now create a `home_dir` variable that you will use in a few places. Add this line right after the previous one: -```rs +```rust let home_dir = std::path::PathBuf::from(near_indexer::get_default_home()); ``` - Next add a condition to check if you pass either `init` or `run` as an argument: -```rs +```rust match args[1].as_str() { "init" => {}, "run" => {}, @@ -249,7 +249,7 @@ match args[1].as_str() { - Inside the `init` code block we're going to instantiate structure with necessary arguments to generate configs and will pass it to the function to actually generate configs: -```rs +```rust match args[1].as_str() { "init" => { let config_args = near_indexer::InitConfigArgs { @@ -272,7 +272,7 @@ match args[1].as_str() { - For the `run` code block move the previous indexer start logic like so: -```rs +```rust match args[1].as_str() { "init" => { let config_args = near_indexer::InitConfigArgs { @@ -301,7 +301,7 @@ match args[1].as_str() { - If you like, you can refactor the code a bit by creating a `command` variable leaving your final `main()` function looking something like this: -```rs +```rust fn main() { let args: Vec = std::env::args().collect(); let home_dir = std::path::PathBuf::from(near_indexer::get_default_home()); From cc00f90360216b0fd2ac2835fbadf83914cf8948 Mon Sep 17 00:00:00 2001 From: Josh Date: Fri, 12 Mar 2021 11:55:06 -0800 Subject: [PATCH 19/19] final edits --- docs/tools/near-indexer.md | 127 +++++++++++++++++++++++++++++++------ 1 file changed, 109 insertions(+), 18 deletions(-) diff --git a/docs/tools/near-indexer.md b/docs/tools/near-indexer.md index 620b9871f9a..e7c8d776150 100644 --- a/docs/tools/near-indexer.md +++ b/docs/tools/near-indexer.md @@ -18,8 +18,6 @@ sidebar_label: NEAR Indexer - 16GB RAM - 100GB SSD _(HDD will **not** work)_ -All the code written in this tutorial can be found [here](https://github.com/near-examples/indexer-tutorials/tree/master/example-indexer) - ### Creating your project To create a new project with Rust, you will start by creating a new binary by running the following command in your terminal: @@ -99,7 +97,7 @@ cargo check If the cargo check command fails with some errors it might be because of different versions of underlying dependencies. -- A quick solution is to copy `Cargo.lock` from `nearcore` repository [ [here](https://raw.githubusercontent.com/near/nearcore/master/Cargo.lock) ] and replace it with the contents of your project's `Cargo.lock` file. +- A quick solution is to copy `Cargo.lock` from `nearcore` repository [ [here](https://raw.githubusercontent.com/near/nearcore/master/Cargo.lock) ] and replace it with the contents of your project's `Cargo.lock` file. - After this is complete, rerun `cargo check` to see if this resolves your errors.
@@ -206,9 +204,9 @@ async fn listen_blocks(mut stream: tokio::sync::mpsc::Receiver ```json -{"block":{"author":"test.near","header":{"height":75,"epoch_id":"11111111111111111111111111111111","next_epoch_id":"4vf1hV5j63QLAPpiWQELXHAfJjHCgq1uooMrBNPMu5Uq","hash":"4kSDb7bnK2vYFkWnCUwLk6V24ZemGoejZQFXM4L5op5A","prev_hash":"Bi618Wbu7NAuxH5cqkXkBd1iH7Lue5YmQj16Xf3A2vTb","prev_state_root":"CHAfu2kedNvLMKmK7gFx3knAp7URPnzw7GcEEnZWqzSJ","chunk_receipts_root":"9ETNjrt6MkwTgSVMMbpukfxRshSD1avBUUa4R4NuqwHv","chunk_headers_root":"CDY1cuGvzr2YTM57ST7uVqEDX27rbgCauXq1hjHo9jjW","chunk_tx_root":"7tkzFg8RHBmMw1ncRJZCCZAizgq4rwCftTKYLce8RU8t","outcome_root":"7tkzFg8RHBmMw1ncRJZCCZAizgq4rwCftTKYLce8RU8t","chunks_included":1,"challenges_root":"11111111111111111111111111111111","timestamp":1614356082504891000,"timestamp_nanosec":"1614356082504891000","random_value":"CVNoqr7nXckRhE8dHGYHn8H49wT4gprM8YQhhZSj3awx","validator_proposals":[],"chunk_mask":[true],"gas_price":"1000000000","rent_paid":"0","validator_reward":"0","total_supply":"2050000000000000000000000000000000","challenges_result":[],"last_final_block":"Fnzr8a91ZV2UTGUgmuMY3Ar6RamgVQYTASdsiuHxof3n","last_ds_final_block":"Bi618Wbu7NAuxH5cqkXkBd1iH7Lue5YmQj16Xf3A2vTb","next_bp_hash":"EcqXCDTULxNaDncsiVU165HW7gMQNafzz5qekXgA6QdG","block_merkle_root":"6Wv8SQeWHJcZpLKKQ8sR7wnHrtbdMpfMQMkfvbWBAKGY","approvals":["ed25519:2N4HJaBCwzu1F9jMAKGYgUTKPB4VVvBGfZ6e7qM3P4bkFHkDohfmJmfvQtcEaRQN9Q8dSo4iEEA25tqRtuRWf1N3"],"signature":"ed25519:4c9owM6uZb8Qbq2KYNXhmpmfpkKX4ygvvvFgMAy1qz5aZu7v3MmHKpavnJp7eTYeUpm8yyRzcXUpjoCpygjnZsF4","latest_protocol_version":42},"chunks":[{"chunk_hash":"62ZVbyWBga6nSZixsWm6KAHkZ6FbYhY7jvDEt3Gc3HP3","prev_block_hash":"Bi618Wbu7NAuxH5cqkXkBd1iH7Lue5YmQj16Xf3A2vTb","outcome_root":"11111111111111111111111111111111","prev_state_root":"HLi9RaXG8ejkiehaiSwDZ31zQ8gQGXJyf34RmXAER6EB","encoded_merkle_root":"79Bt7ivt9Qhp3c6dJYnueaTyPVweYxZRpQHASRRAiyuy","encoded_length":8,"height_created":75,"height_included":75,"shard_id":0,"gas_used":0,"gas_limit":1000000000000000,"rent_paid":"0","validator_reward":"0","balance_burnt":"0","outgoing_receipts_root":"H4Rd6SGeEBTbxkitsCdzfu9xL9HtZ2eHoPCQXUeZ6bW4","tx_root":"11111111111111111111111111111111","validator_proposals":[],"signature":"ed25519:3XDErgyunAmhzaqie8uNbjPhgZMwjhTXADmfZM7TtdMKXaqawfRJhKCeavsmEe2rrMKeCuLk6ef8uhZT1952Vffi"}]},"chunks":[{"author":"test.near","header":{"chunk_hash":"62ZVbyWBga6nSZixsWm6KAHkZ6FbYhY7jvDEt3Gc3HP3","prev_block_hash":"Bi618Wbu7NAuxH5cqkXkBd1iH7Lue5YmQj16Xf3A2vTb","outcome_root":"11111111111111111111111111111111","prev_state_root":"HLi9RaXG8ejkiehaiSwDZ31zQ8gQGXJyf34RmXAER6EB","encoded_merkle_root":"79Bt7ivt9Qhp3c6dJYnueaTyPVweYxZRpQHASRRAiyuy","encoded_length":8,"height_created":75,"height_included":0,"shard_id":0,"gas_used":0,"gas_limit":1000000000000000,"rent_paid":"0","validator_reward":"0","balance_burnt":"0","outgoing_receipts_root":"H4Rd6SGeEBTbxkitsCdzfu9xL9HtZ2eHoPCQXUeZ6bW4","tx_root":"11111111111111111111111111111111","validator_proposals":[],"signature":"ed25519:3XDErgyunAmhzaqie8uNbjPhgZMwjhTXADmfZM7TtdMKXaqawfRJhKCeavsmEe2rrMKeCuLk6ef8uhZT1952Vffi"},"transactions":[],"receipts":[],"receipt_execution_outcomes":[]}],"state_changes":[]} +{ + "block": { + "author": "test.near", + "header": { + "height": 75, + "epoch_id": "11111111111111111111111111111111", + "next_epoch_id": "4vf1hV5j63QLAPpiWQELXHAfJjHCgq1uooMrBNPMu5Uq", + "hash": "4kSDb7bnK2vYFkWnCUwLk6V24ZemGoejZQFXM4L5op5A", + "prev_hash": "Bi618Wbu7NAuxH5cqkXkBd1iH7Lue5YmQj16Xf3A2vTb", + "prev_state_root": "CHAfu2kedNvLMKmK7gFx3knAp7URPnzw7GcEEnZWqzSJ", + "chunk_receipts_root": "9ETNjrt6MkwTgSVMMbpukfxRshSD1avBUUa4R4NuqwHv", + "chunk_headers_root": "CDY1cuGvzr2YTM57ST7uVqEDX27rbgCauXq1hjHo9jjW", + "chunk_tx_root": "7tkzFg8RHBmMw1ncRJZCCZAizgq4rwCftTKYLce8RU8t", + "outcome_root": "7tkzFg8RHBmMw1ncRJZCCZAizgq4rwCftTKYLce8RU8t", + "chunks_included": 1, + "challenges_root": "11111111111111111111111111111111", + "timestamp": 1614356082504891000, + "timestamp_nanosec": "1614356082504891000", + "random_value": "CVNoqr7nXckRhE8dHGYHn8H49wT4gprM8YQhhZSj3awx", + "validator_proposals": [], + "chunk_mask": [true], + "gas_price": "1000000000", + "rent_paid": "0", + "validator_reward": "0", + "total_supply": "2050000000000000000000000000000000", + "challenges_result": [], + "last_final_block": "Fnzr8a91ZV2UTGUgmuMY3Ar6RamgVQYTASdsiuHxof3n", + "last_ds_final_block": "Bi618Wbu7NAuxH5cqkXkBd1iH7Lue5YmQj16Xf3A2vTb", + "next_bp_hash": "EcqXCDTULxNaDncsiVU165HW7gMQNafzz5qekXgA6QdG", + "block_merkle_root": "6Wv8SQeWHJcZpLKKQ8sR7wnHrtbdMpfMQMkfvbWBAKGY", + "approvals": [ + "ed25519:2N4HJaBCwzu1F9jMAKGYgUTKPB4VVvBGfZ6e7qM3P4bkFHkDohfmJmfvQtcEaRQN9Q8dSo4iEEA25tqRtuRWf1N3" + ], + "signature": "ed25519:4c9owM6uZb8Qbq2KYNXhmpmfpkKX4ygvvvFgMAy1qz5aZu7v3MmHKpavnJp7eTYeUpm8yyRzcXUpjoCpygjnZsF4", + "latest_protocol_version": 42 + }, + "chunks": [ + { + "chunk_hash": "62ZVbyWBga6nSZixsWm6KAHkZ6FbYhY7jvDEt3Gc3HP3", + "prev_block_hash": "Bi618Wbu7NAuxH5cqkXkBd1iH7Lue5YmQj16Xf3A2vTb", + "outcome_root": "11111111111111111111111111111111", + "prev_state_root": "HLi9RaXG8ejkiehaiSwDZ31zQ8gQGXJyf34RmXAER6EB", + "encoded_merkle_root": "79Bt7ivt9Qhp3c6dJYnueaTyPVweYxZRpQHASRRAiyuy", + "encoded_length": 8, + "height_created": 75, + "height_included": 75, + "shard_id": 0, + "gas_used": 0, + "gas_limit": 1000000000000000, + "rent_paid": "0", + "validator_reward": "0", + "balance_burnt": "0", + "outgoing_receipts_root": "H4Rd6SGeEBTbxkitsCdzfu9xL9HtZ2eHoPCQXUeZ6bW4", + "tx_root": "11111111111111111111111111111111", + "validator_proposals": [], + "signature": "ed25519:3XDErgyunAmhzaqie8uNbjPhgZMwjhTXADmfZM7TtdMKXaqawfRJhKCeavsmEe2rrMKeCuLk6ef8uhZT1952Vffi" + } + ] + }, + "chunks": [ + { + "author": "test.near", + "header": { + "chunk_hash": "62ZVbyWBga6nSZixsWm6KAHkZ6FbYhY7jvDEt3Gc3HP3", + "prev_block_hash": "Bi618Wbu7NAuxH5cqkXkBd1iH7Lue5YmQj16Xf3A2vTb", + "outcome_root": "11111111111111111111111111111111", + "prev_state_root": "HLi9RaXG8ejkiehaiSwDZ31zQ8gQGXJyf34RmXAER6EB", + "encoded_merkle_root": "79Bt7ivt9Qhp3c6dJYnueaTyPVweYxZRpQHASRRAiyuy", + "encoded_length": 8, + "height_created": 75, + "height_included": 0, + "shard_id": 0, + "gas_used": 0, + "gas_limit": 1000000000000000, + "rent_paid": "0", + "validator_reward": "0", + "balance_burnt": "0", + "outgoing_receipts_root": "H4Rd6SGeEBTbxkitsCdzfu9xL9HtZ2eHoPCQXUeZ6bW4", + "tx_root": "11111111111111111111111111111111", + "validator_proposals": [], + "signature": "ed25519:3XDErgyunAmhzaqie8uNbjPhgZMwjhTXADmfZM7TtdMKXaqawfRJhKCeavsmEe2rrMKeCuLk6ef8uhZT1952Vffi" + }, + "transactions": [], + "receipts": [], + "receipt_execution_outcomes": [] + } + ], + "state_changes": [] +} ``` -You can use [`jq`](https://stedolan.github.io/jq/) and running your indexer like +
+heads up

+ +You can find the all of the code we've written in this tutorial **[ [here](https://github.com/near-examples/indexer-tutorials/tree/master/example-indexer) ]**. + +
+ +## Formatting JSON Stream + +> [`./jq`](https://stedolan.github.io/jq/) is a lightweight command line tool you can use to process and format your JSON stream. + +- After you [install `jq` locally](https://stedolan.github.io/jq/download/) you can use it with your indexer by running: ```bash cargo run -- run | jq ``` -to make pretty print JSON and you can do different stuff with JSON with `jq` - -For example if you're interest only in transactions you can run indexer like: +- You can narrow your results down by adding arguments to your command. For example, if you want only transactions and the block height of those transactions run: ```bash cargo run -- run | jq '{block_height: .block.header.height, transactions: .chunks[0].transactions}' ``` -And you'll get +You should have a stream that looks similar to the example below: ```json { @@ -425,15 +520,11 @@ And you'll get } ``` -You can play around with the data easily because it is returned as a JSON object. +## Indexer examples -You can find the code we've written in this tutorial in [this repository](https://github.com/near-examples/indexer-tutorials/tree/master/example-indexer) +> Here is a list of NEAR indexer examples. If you created one and want to add it to the list, submit a [PR](https://github.com/near/docs/pulls) or click `Edit` in the upper right hand corner of this doc and add it to the list! -## Indexer examples - [Flux Capacitor](https://github.com/fluxprotocol/flux-capacitor) - [NEAR Explorer Indexer](https://github.com/near/near-indexer-for-explorer) - [NEAR Wallet Indexer](https://github.com/near/near-indexer-for-wallet) - - -Did you create your own indexer? Submit a PR and add it to the list!