Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

starknet support #3

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
3 changes: 3 additions & 0 deletions crates/query/fixtures/starknet/chunk/blocks.parquet
Git LFS file not shown
3 changes: 3 additions & 0 deletions crates/query/fixtures/starknet/chunk/events.parquet
Git LFS file not shown
3 changes: 3 additions & 0 deletions crates/query/fixtures/starknet/chunk/transactions.parquet
Git LFS file not shown
25 changes: 25 additions & 0 deletions crates/query/fixtures/starknet/queries/basic/query.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"type": "starknet",
"fromBlock": 0,
"fields": {
"block": {
"parentHash": true,
"timestamp": true
},
"transaction": {
"transactionHash": true,
"signature": true
},
"event": {
"keys": true,
"data": true
}
},
"events": [
{
"fromAddress": ["0x22e45d94d5c6c477d9efd440aad71b2c02a5cd5bed9a4d6da10bb7c19fd93ba"],
"key0": ["0xe316f0d9d2a3affa97de1d99bb2aac0538e2666d0d8545545ead241ef0ccab"],
"transaction": true
}
]
}
3 changes: 3 additions & 0 deletions crates/query/fixtures/starknet/queries/basic/result.json
Git LFS file not shown
9 changes: 9 additions & 0 deletions crates/query/src/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use serde::{Deserialize, Serialize};
pub mod eth;
pub mod solana;
pub mod substrate;
pub mod starknet;
pub mod fuel;
mod util;

Expand All @@ -19,6 +20,8 @@ pub enum Query {
Solana(solana::SolanaQuery),
#[serde(rename = "substrate")]
Substrate(substrate::SubstrateQuery),
#[serde(rename = "starknet")]
Starknet(starknet::StarknetQuery),
#[serde(rename = "fuel")]
Fuel(fuel::FuelQuery)
}
Expand Down Expand Up @@ -50,6 +53,7 @@ impl Query {
Query::Eth(q) => q.validate(),
Query::Solana(q) => q.validate(),
Query::Substrate(q) => q.validate(),
Query::Starknet(q) => q.validate(),
Query::Fuel(q) => q.validate(),
}
}
Expand All @@ -59,6 +63,7 @@ impl Query {
Query::Eth(q) => q.from_block,
Query::Solana(q) => q.from_block,
Query::Substrate(q) => q.from_block,
Query::Starknet(q) => q.from_block,
Query::Fuel(q) => q.from_block,
}
}
Expand All @@ -68,6 +73,7 @@ impl Query {
Query::Eth(q) => q.from_block = block_number,
Query::Solana(q) => q.from_block = block_number,
Query::Substrate(q) => q.from_block = block_number,
Query::Starknet(q) => q.from_block = block_number,
Query::Fuel(q) => q.from_block = block_number,
}
}
Expand All @@ -77,6 +83,7 @@ impl Query {
Query::Eth(q) => q.to_block,
Query::Solana(q) => q.to_block,
Query::Substrate(q) => q.to_block,
Query::Starknet(q) => q.to_block,
Query::Fuel(q) => q.to_block,
}
}
Expand All @@ -86,6 +93,7 @@ impl Query {
Query::Eth(q) => q.to_block = block_number,
Query::Solana(q) => q.to_block = block_number,
Query::Substrate(q) => q.to_block = block_number,
Query::Starknet(q) => q.to_block = block_number,
Query::Fuel(q) => q.to_block = block_number,
}
}
Expand All @@ -95,6 +103,7 @@ impl Query {
Query::Eth(q) => q.compile(),
Query::Solana(q) => q.compile(),
Query::Substrate(q) => q.compile(),
Query::Starknet(q) => q.compile(),
Query::Fuel(q) => q.compile(),
}
}
Expand Down
234 changes: 234 additions & 0 deletions crates/query/src/query/starknet.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
use lazy_static::lazy_static;
use serde::{Deserialize, Serialize};

use crate::json::exp::Exp;
use crate::json::lang::*;
use crate::plan::{Plan, ScanBuilder, TableSet};
use crate::primitives::BlockNumber;
use crate::query::util::{compile_plan, ensure_block_range, ensure_item_count, field_selection, item_field_selection, request, PredicateBuilder};


lazy_static! {
static ref TABLES: TableSet = {
let mut tables = TableSet::new();

tables.add_table("blocks", vec![
"number"
]);

tables.add_table("transactions", vec![
"block_number",
"transaction_index"
])
.set_weight_column("calldata", "calldata_size")
.set_weight_column("signature", "signature_size")
.set_weight_column("constructor_calldata", "constructor_calldata_size");

tables.add_table("events", vec![
"block_number",
"transaction_index",
"event_index"
])
.set_weight_column("key0", "keys_size")
.set_weight("key1", 0)
.set_weight("key2", 0)
.set_weight("key3", 0)
.set_weight("rest_keys", 0)
.set_weight_column("data", "data_size");

tables
};
}


field_selection! {
block: BlockFieldSelection,
transaction: TransactionFieldSelection,
event: EventFieldSelection,
}


item_field_selection! {
BlockFieldSelection {
parent_hash,
status,
new_root,
timestamp,
sequencer_address,
}

project(this) json_object! {{
number,
hash,
[this.parent_hash],
[this.status],
[this.new_root],
[this.sequencer_address],
<this.timestamp>: TimestampSecond,
}}
}


item_field_selection! {
TransactionFieldSelection {
transaction_hash,
contract_address,
entry_point_selector,
calldata,
max_fee,
r#type,
sender_address,
version,
signature,
nonce,
class_hash,
compiled_class_hash,
contract_address_salt,
constructor_calldata,
}

project(this) json_object! {{
transaction_index,
[this.transaction_hash],
[this.contract_address],
[this.entry_point_selector],
[this.calldata],
[this.max_fee],
[this.r#type],
[this.sender_address],
[this.version],
[this.signature],
[this.nonce],
[this.class_hash],
[this.compiled_class_hash],
[this.contract_address_salt],
[this.constructor_calldata],
}}
}


item_field_selection! {
EventFieldSelection {
from_address,
keys,
data,
}

project(this) json_object! {{
transaction_index,
event_index,
[this.from_address],
[this.data],
|obj| {
if this.keys {
obj.add("keys", roll(Exp::Value, vec![
"key0",
"key1",
"key2",
"key3",
"rest_keys"
]));
}
}
}}
}


type Bytes = String;


request! {
pub struct EventRequest {
pub from_address: Option<Vec<Bytes>>,
pub key0: Option<Vec<Bytes>>,
pub key1: Option<Vec<Bytes>>,
pub key2: Option<Vec<Bytes>>,
pub key3: Option<Vec<Bytes>>,
pub transaction: bool,
}
}


impl EventRequest {
fn predicate(&self, p: &mut PredicateBuilder) {
p.col_in_list("from_address", self.from_address.clone());
p.col_in_list("key0", self.key0.clone());
p.col_in_list("key1", self.key1.clone());
p.col_in_list("key2", self.key2.clone());
p.col_in_list("key3", self.key3.clone());
}

fn relations(&self, scan: &mut ScanBuilder) {
if self.transaction {
scan.join(
"transactions",
vec!["block_number", "transaction_index"],
vec!["block_number", "transaction_index"]
);
}
}
}


request! {
pub struct TransactionRequest {
pub contract_address: Option<Vec<Bytes>>,
pub sender_address: Option<Vec<Bytes>>,
pub r#type: Option<Vec<String>>,
pub first_nonce: Option<u64>,
pub last_nonce: Option<u64>,
pub events: bool,
}
}


impl TransactionRequest {
fn predicate(&self, p: &mut PredicateBuilder) {
p.col_in_list("contract_address", self.contract_address.clone());
p.col_in_list("sender_address", self.sender_address.clone());
p.col_in_list("type", self.r#type.clone());
p.col_gt_eq("nonce", self.first_nonce);
p.col_lt_eq("nonce", self.last_nonce);
}

fn relations(&self, scan: &mut ScanBuilder) {
if self.events {
scan.join(
"events",
vec!["block_number", "transaction_index"],
vec!["block_number", "transaction_index"]
);
}
}
}


request! {
pub struct StarknetQuery {
pub from_block: Option<BlockNumber>,
pub to_block: Option<BlockNumber>,
pub fields: FieldSelection,
pub include_all_blocks: bool,
pub transactions: Vec<TransactionRequest>,
pub events: Vec<EventRequest>,
}
}


impl StarknetQuery {
pub fn validate(&self) -> anyhow::Result<()> {
ensure_block_range!(self);
ensure_item_count!(self, transactions, events);
Ok(())
}

pub fn compile(&self) -> Plan {
compile_plan!(self, &TABLES,
[blocks: self.fields.block.project()],
[transactions: self.fields.transaction.project()],
[events: self.fields.event.project()],
transactions,
events,
)
}
}