Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "wvm-archiver"
version = "0.1.1"
version = "0.1.2"
edition = "2021"
description = "EL data pipeline for WVM testnet v0"
authors = ["charmful0x <rani@decent.land>"]
Expand Down
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,26 @@ The WeaveVM Archiver node operates as follows:

As mentioned, PlanetScale is used for cloud indexing, which allows a WeaveVM Archiver node to expose its WeaveVM data as a RESTful API.

### WeaveVM Archiver node instance info

```bash
curl -X GET https://your_app.shuttleapp.rs/info
```
**returns:**

```rs
pub struct InfoServerResponse {
first_block: Option<u64>,
last_block: Option<u64>,
total_archived_blocks: u64,
archiver_balance: U256,
archiver_address: String,
network_name: String,
network_chain_id: u32,
network_rpc: String,
}
```

### Retrieve the WVM archive TXID for a given EVM block ID

```bash
Expand Down
12 changes: 6 additions & 6 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use crate::utils::archive_block::archive;
use crate::utils::schema::Network;
use crate::utils::planetscale::{ps_archive_block, ps_get_latest_block_id};
use crate::utils::server_handlers::{handle_block, weave_gm};
use crate::utils::schema::Network;
use crate::utils::server_handlers::{handle_block, handle_info, handle_weave_gm};
use axum::{routing::get, Router};
use std::thread;
use std::time::Duration;
use axum::{routing::get, Router};
use tokio::task;

mod utils;
Expand All @@ -19,8 +19,9 @@ async fn main() -> shuttle_axum::ShuttleAxum {
println!("\n{:#?}\n\n", network);
// server routes
let router = Router::new()
.route("/", get(weave_gm))
.route("/block/:id", get(handle_block));
.route("/", get(handle_weave_gm))
.route("/info", get(handle_info))
.route("/block/:id", get(handle_block));

// poll blocks & archive in parallel
task::spawn(async move {
Expand All @@ -40,4 +41,3 @@ async fn main() -> shuttle_axum::ShuttleAxum {

Ok(router.into())
}

2 changes: 1 addition & 1 deletion src/utils/env_var.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ pub fn get_env_var(key: &str) -> Result<String, env::VarError> {
Ok(val) => Ok(val),
Err(e) => Err(e),
}
}
}
4 changes: 2 additions & 2 deletions src/utils/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
pub mod archive_block;
pub mod env_var;
pub mod get_block;
pub mod schema;
pub mod transaction;
pub mod planetscale;
pub mod schema;
pub mod server_handlers;
pub mod transaction;
70 changes: 46 additions & 24 deletions src/utils/planetscale.rs
Original file line number Diff line number Diff line change
@@ -1,34 +1,33 @@
use crate::utils::env_var::get_env_var;
use crate::utils::schema::{Network, PsGetBlockTxid};
use planetscale_driver::{PSConnection, query};
use crate::utils::schema::{Network, PsGetBlockTxid, PsGetExtremeBlock};
use anyhow::Error;
use planetscale_driver::{query, PSConnection};
use serde_json::Value;

async fn ps_init() -> PSConnection {

let host = get_env_var("DATABASE_HOST").unwrap();
let username = get_env_var("DATABASE_USERNAME").unwrap();
let password = get_env_var("DATABASE_PASSWORD").unwrap();

let conn: PSConnection = PSConnection::new(
&host,
&username,
&password,
);
let conn: PSConnection = PSConnection::new(&host, &username, &password);

conn
conn
}

pub async fn ps_archive_block(network_block_id: &u64, wvm_calldata_txid: &str) -> Result<(), Error> {
pub async fn ps_archive_block(
network_block_id: &u64,
wvm_calldata_txid: &str,
) -> Result<(), Error> {
// format to the table VAR(66) limitation
let wvm_calldata_txid = wvm_calldata_txid.trim_matches('"');
let wvm_calldata_txid = wvm_calldata_txid.trim_matches('"');
let conn = ps_init().await;

let res = query("INSERT INTO WeaveVMArchiver(NetworkBlockId, WeaveVMArchiveTxid) VALUES($0, \"$1\")")
.bind(network_block_id)
.bind(wvm_calldata_txid)
.execute(&conn)
.await;
let res =
query("INSERT INTO WeaveVMArchiver(NetworkBlockId, WeaveVMArchiveTxid) VALUES($0, \"$1\")")
.bind(network_block_id)
.bind(wvm_calldata_txid)
.execute(&conn)
.await;

match res {
Ok(result) => {
Expand All @@ -46,7 +45,11 @@ pub async fn ps_get_latest_block_id() -> u64 {
let network = Network::config();
let conn = ps_init().await;

let latest_archived: u64 = query("SELECT MAX(NetworkBlockId) AS LatestNetworkBlockId FROM WeaveVMArchiver;").fetch_scalar(&conn).await.unwrap_or(network.start_block);
let latest_archived: u64 =
query("SELECT MAX(NetworkBlockId) AS LatestNetworkBlockId FROM WeaveVMArchiver;")
.fetch_scalar(&conn)
.await
.unwrap_or(network.start_block);
// return latest archived block in planetscale + 1
// so the process can start archiving from latest_archived + 1
latest_archived + 1
Expand All @@ -55,13 +58,32 @@ pub async fn ps_get_latest_block_id() -> u64 {
pub async fn ps_get_archived_block_txid(id: u64) -> Value {
let conn = ps_init().await;

let query_formatted = format!("SELECT WeaveVMArchiveTxid FROM WeaveVMArchiver WHERE NetworkBlockId = {}", id);
let txid: PsGetBlockTxid =
query(&query_formatted)
.fetch_one(&conn)
.await
.unwrap();
let query_formatted = format!(
"SELECT WeaveVMArchiveTxid FROM WeaveVMArchiver WHERE NetworkBlockId = {}",
id
);
let txid: PsGetBlockTxid = query(&query_formatted).fetch_one(&conn).await.unwrap();

let res = serde_json::json!(txid);
res
}
}

pub async fn ps_get_blocks_extremes(extreme: &str) -> Value {
let conn = ps_init().await;

let query_type = match extreme {
"first" => "ASC",
"last" => "DESC",
_ => panic!("invalid extreme value. Use 'first' or 'last'."),
};

let query_formatted = format!(
"SELECT NetworkBlockId FROM WeaveVMArchiver ORDER BY NetworkBlockId {} LIMIT 1;",
query_type
);

let query: PsGetExtremeBlock = query(&query_formatted).fetch_one(&conn).await.unwrap();

let res = serde_json::json!(query);
res
}
81 changes: 60 additions & 21 deletions src/utils/schema.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
use crate::utils::env_var::get_env_var;
use crate::utils::transaction::get_archiver_balance;
use borsh::to_vec;
use borsh_derive::{BorshDeserialize, BorshSerialize};
use ethers::types::U256;
use ethers_providers::{Http, Provider};
use planetscale_driver::Database;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::convert::TryFrom;
use std::fs::File;
use std::io::{Read, Write};
use planetscale_driver::Database;

#[derive(Serialize, Deserialize, Debug)]
pub struct Network {
Expand Down Expand Up @@ -57,26 +59,26 @@ impl Network {
pub struct Block {
pub base_fee_per_gas: Option<String>, // "baseFeePerGas"
pub blob_gas_used: Option<String>, // "blobGasUsed"
pub difficulty: Option<String>, // "difficulty"
pub difficulty: Option<String>, // "difficulty"
pub excess_blob_gas: Option<String>, // "excessBlobGas"
pub extra_data: Option<String>, // "extraData"
pub gas_limit: Option<String>, // "gasLimit"
pub gas_used: Option<String>, // "gasUsed"
pub hash: Option<String>, // "hash"
pub logs_bloom: Option<String>, // "logsBloom"
pub miner: Option<String>, // "miner"
pub mix_hash: Option<String>, // "mixHash"
pub nonce: Option<String>, // "nonce"
pub number: Option<String>, // "number"
pub extra_data: Option<String>, // "extraData"
pub gas_limit: Option<String>, // "gasLimit"
pub gas_used: Option<String>, // "gasUsed"
pub hash: Option<String>, // "hash"
pub logs_bloom: Option<String>, // "logsBloom"
pub miner: Option<String>, // "miner"
pub mix_hash: Option<String>, // "mixHash"
pub nonce: Option<String>, // "nonce"
pub number: Option<String>, // "number"
pub parent_beacon_block_root: Option<String>, // "parentBeaconBlockRoot"
pub parent_hash: Option<String>, // "parentHash"
pub receipts_root: Option<String>, // "receiptsRoot"
pub parent_hash: Option<String>, // "parentHash"
pub receipts_root: Option<String>, // "receiptsRoot"
pub seal_fields: Vec<String>, // "sealFields" as an array of strings
pub sha3_uncles: Option<String>, // "sha3Uncles"
pub size: Option<String>, // "size"
pub state_root: Option<String>, // "stateRoot"
pub timestamp: Option<String>, // "timestamp"
pub total_difficulty: Option<String>, // "totalDifficulty"
pub sha3_uncles: Option<String>, // "sha3Uncles"
pub size: Option<String>, // "size"
pub state_root: Option<String>, // "stateRoot"
pub timestamp: Option<String>, // "timestamp"
pub total_difficulty: Option<String>, // "totalDifficulty"
pub transactions: Vec<String>, // "transactions" as an array of strings
}

Expand All @@ -94,8 +96,45 @@ impl Block {
}
}


#[derive(Database, Debug, Serialize)]
pub struct PsGetBlockTxid {
pub wvm_archive_txid : String
}
pub wvm_archive_txid: String,
}

#[derive(Database, Debug, Serialize)]
pub struct PsGetExtremeBlock {
pub block_id: u64,
}

#[derive(Debug, Serialize)]
pub struct InfoServerResponse {
first_block: Option<u64>,
last_block: Option<u64>,
total_archived_blocks: u64,
archiver_balance: U256,
archiver_address: String,
network_name: String,
network_chain_id: u32,
network_rpc: String,
}

impl InfoServerResponse {
pub async fn new(first_block: Option<u64>, last_block: Option<u64>) -> InfoServerResponse {
let network = Network::config();
let total_archived_blocks = last_block.unwrap_or(0) - first_block.unwrap_or(0);
let archiver_balance = get_archiver_balance().await;
let archiver_balance = Some(archiver_balance).unwrap();

let instance: InfoServerResponse = InfoServerResponse {
archiver_balance,
first_block,
last_block,
total_archived_blocks,
archiver_address: network.archiver_address,
network_name: network.name,
network_chain_id: network.network_chain_id,
network_rpc: network.network_rpc,
};
instance
}
}
21 changes: 15 additions & 6 deletions src/utils/server_handlers.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
use crate::utils::planetscale::ps_get_archived_block_txid;
use crate::utils::planetscale::{ps_get_archived_block_txid, ps_get_blocks_extremes};
use crate::utils::schema::InfoServerResponse;
use axum::{extract::Path, response::Json};
use serde_json::Value;
use axum::{
extract::Path,
response::Json
};

pub async fn weave_gm() -> &'static str {
pub async fn handle_weave_gm() -> &'static str {
"WeaveGM!"
}

Expand All @@ -14,3 +12,14 @@ pub async fn handle_block(Path(id): Path<u64>) -> Json<Value> {
Json(txid)
}

pub async fn handle_info() -> Json<Value> {
let first = ps_get_blocks_extremes("first").await;
let last = ps_get_blocks_extremes("last").await;

let first_block = first.get("block_id").unwrap().as_u64();
let last_block = last.get("block_id").unwrap().as_u64();
let stats_res = InfoServerResponse::new(first_block, last_block).await;

let res = serde_json::to_value(&stats_res).unwrap();
Json(res)
}
10 changes: 9 additions & 1 deletion src/utils/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ async fn assert_non_zero_balance(provider: &Provider<Http>, address: &Address) {
assert!(balance > 0.into());
}

pub async fn get_archiver_balance() -> U256 {
let network = Network::config();
let provider = Network::provider(&network, true).await;
let address = network.archiver_address.parse::<Address>().unwrap();
let balance = provider.get_balance(address, None).await.unwrap();
balance
}

async fn send_transaction(
client: &Client,
address_from: &Address,
Expand All @@ -51,4 +59,4 @@ async fn send_transaction(

println!("\nWeaveVM Archiving TXID: {}", txid);
Ok(txid)
}
}