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

First working implementation of Solana #3210

Closed
Closed
Show file tree
Hide file tree
Changes from 1 commit
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
29 changes: 29 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
members = [
"core",
"chain/ethereum",
"chain/near",
"chain/solana",
"graphql",
"mock",
"node",
Expand Down
25 changes: 25 additions & 0 deletions chain/solana/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
[package]
name = "graph-chain-solana"
version = "0.24.1"
edition = "2018"

[build-dependencies]
tonic-build = "0.5.1"

[dependencies]
base64 = "0.13"
graph = { path = "../../graph" }
prost = "0.8.0"
prost-types = "0.8.0"
serde = "1.0"
base58 = "0.2.0"

graph-runtime-wasm = { path = "../../runtime/wasm" }
graph-runtime-derive = { path = "../../runtime/derive" }

[dev-dependencies]
diesel = { version = "1.4.7", features = ["postgres", "serde_json", "numeric", "r2d2"] }
graph-core = { path = "../../core" }
graph-store-postgres = { path = "../../store/postgres" }
pretty_assertions = "0.7.2"
test-store = { path = "../../store/test-store" }
8 changes: 8 additions & 0 deletions chain/solana/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
fn main() {
println!("cargo:rerun-if-changed=proto");
tonic_build::configure()
.out_dir("src/protobuf")
.format(true)
.compile(&["proto/codec.proto"], &["proto"])
.expect("Failed to compile StreamingFast Solana proto(s)");
}
142 changes: 142 additions & 0 deletions chain/solana/proto/codec.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
syntax = "proto3";

package sf.solana.codec.v1;

option go_package = "github.com/streamingfast/sf-solana/pb/sf/solana/codec/v1;pbcodec";

import "google/protobuf/any.proto";

message Block {
bytes id = 1; // corresponds to the Slot id (or hash)
uint64 number = 2; // corresponds to the Slot number for this block
uint32 version = 3;
bytes previous_id = 4; // corresponds to the previous_blockhash, might skip some slots, so beware
uint64 previous_block = 5;
uint64 genesis_unix_timestamp = 6;
uint64 clock_unix_timestamp = 7;
uint64 root_num = 8;

bytes last_entry_hash = 9;

repeated Transaction transactions = 10;
uint32 transaction_count = 11;

bool has_split_account_changes = 12;
string account_changes_file_ref = 13;
}

message Batch {
repeated Transaction transactions = 1;
}

// Bundled in separate files, referenced by `account_changes_file_ref`
message AccountChangesBundle {
// Maps to the index of the `repeated` field for Block::transactions
repeated AccountChangesPerTrxIndex transactions = 1;
}

message AccountChangesPerTrxIndex {
bytes TrxId = 1;

// Maps to the index within the `repeated` field of the proto for
// Transaction::instructions
repeated AccountChangesPerInstruction instructions = 2;
}

message AccountChangesPerInstruction {
// Data to be put in Instruction::account_changes
repeated AccountChange changes = 1;
}

message Transaction {
// The transaction ID corresponds to the _first_
// signature. Additional signatures are in `additional_signatures`.
bytes id = 1;

// Index from within a single Slot, deterministically ordered to the
// best of our ability using the transaction ID as a sort key for
// the batch of transactions executed in parallel.
uint64 index = 2;

repeated bytes additional_signatures = 3;

MessageHeader header = 4;
// From the original Message object
repeated bytes account_keys = 5;
// From the original Message object
bytes recent_blockhash = 6;

// What follows Once executed these can be set:
repeated string log_messages = 7;
// Instructions, containing both top-level and nested transactions
repeated Instruction instructions = 8;

bool failed = 9;
TransactionError error = 10;
}

message MessageHeader {
uint32 num_required_signatures = 1;
uint32 num_readonly_signed_accounts = 2;
uint32 num_readonly_unsigned_accounts = 3;
}


/**
- instr1 (id=1, parent=0)
- instr2 (id=2, parent=0) (pubkey1 is writable)
- instr3 (id=3, parent=2) (pubkey1 is writable)
- instr4 (id=4, parent=3) (pubkey1 is writable)
- instr5 (id=5, parent=4) (pubkey1 is writable, mutates pubkey1)
collect delta of pubkey1
collect delta of pubkey1 ONLY IF CHANGED AGAIN, from last time we took a snapshot of it.
collect delta of pubkey1
- instr6 (id=6, parent=0)
*/

message Instruction {
bytes program_id = 3;
repeated bytes account_keys = 4;
bytes data = 5;

// What follows is execution trace data, could be empty for un-executed transactions.

uint32 ordinal = 6;
uint32 parent_ordinal = 7;
uint32 depth = 8;

repeated BalanceChange balance_changes = 9;
repeated AccountChange account_changes = 10;

bool failed = 15;
InstructionError error = 16;
}

message BalanceChange {
bytes pubkey = 1;
uint64 prev_lamports = 2;
uint64 new_lamports = 3;
}

message AccountChange {
bytes pubkey = 1;
bytes prev_data = 2;
bytes new_data = 3;
uint64 new_data_length = 4;
}

message TransactionError {
string error = 2;
}

message TransactionInstructionError {
string error = 2;
}

message InstructionError {
string error = 2;
}

message InstructionErrorCustom {
string error = 2;
}
42 changes: 42 additions & 0 deletions chain/solana/src/adapter.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
use crate::capabilities::NodeCapabilities;
use crate::{data_source::DataSource, Chain};
use graph::blockchain as bc;
use graph::prelude::*;

#[derive(Clone, Debug, Default)]
pub struct TriggerFilter {
pub(crate) block: SolanaBlockFilter,
}

impl bc::TriggerFilter<Chain> for TriggerFilter {
fn extend<'a>(&mut self, data_sources: impl Iterator<Item = &'a DataSource> + Clone) {
self.block
.extend(SolanaBlockFilter::from_data_sources(data_sources));
}

fn node_capabilities(&self) -> NodeCapabilities {
NodeCapabilities {}
}
}

#[derive(Clone, Debug, Default)]
pub(crate) struct SolanaBlockFilter {
pub trigger_every_block: bool,
}

impl SolanaBlockFilter {
pub fn from_data_sources<'a>(iter: impl IntoIterator<Item = &'a DataSource>) -> Self {
iter.into_iter()
.filter(|data_source| data_source.source.program_id.is_some())
.fold(Self::default(), |mut filter_opt, _data_source| {
filter_opt.extend(Self {
trigger_every_block: true,
});
filter_opt
})
}

pub fn extend(&mut self, other: SolanaBlockFilter) {
self.trigger_every_block = self.trigger_every_block || other.trigger_every_block;
}
}
37 changes: 37 additions & 0 deletions chain/solana/src/capabilities.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
use graph::{anyhow::Error, impl_slog_value};
use std::cmp::{Ordering, PartialOrd};
use std::fmt;
use std::str::FromStr;

use crate::data_source::DataSource;

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct NodeCapabilities {}

impl PartialOrd for NodeCapabilities {
fn partial_cmp(&self, _other: &Self) -> Option<Ordering> {
None
}
}

impl FromStr for NodeCapabilities {
type Err = Error;

fn from_str(_s: &str) -> Result<Self, Self::Err> {
Ok(NodeCapabilities {})
}
}

impl fmt::Display for NodeCapabilities {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("solana")
}
}

impl_slog_value!(NodeCapabilities, "{}");

impl graph::blockchain::NodeCapabilities<crate::Chain> for NodeCapabilities {
fn from_data_sources(_data_sources: &[DataSource]) -> Self {
NodeCapabilities {}
}
}
Loading