diff --git a/solana-explorer/.gitignore b/solana-explorer/.gitignore new file mode 100644 index 0000000..2d7bb16 --- /dev/null +++ b/solana-explorer/.gitignore @@ -0,0 +1,6 @@ +.vscode +.idea +.DS_Store +buf.gen.yaml +/target +*.spkg \ No newline at end of file diff --git a/solana-explorer/.gitpod.yml b/solana-explorer/.gitpod.yml new file mode 100644 index 0000000..000c433 --- /dev/null +++ b/solana-explorer/.gitpod.yml @@ -0,0 +1,10 @@ +image: ghcr.io/graphprotocol/substreams-gitpod:latest +tasks: + - command: | + # Authenticate with the substreams server + export SUBSTREAMS_API_TOKEN=$(curl https://auth.dfuse.io/v1/auth/issue -s --data-binary '{"api_key":"'$STREAMINGFAST_KEY'"}' | jq -r .token) +ports: + - port: 6060 + onOpen: ignore + - port: 1065 + onOpen: ignore diff --git a/solana-explorer/.rustfmt.toml b/solana-explorer/.rustfmt.toml new file mode 100644 index 0000000..866c756 --- /dev/null +++ b/solana-explorer/.rustfmt.toml @@ -0,0 +1 @@ +max_width = 120 \ No newline at end of file diff --git a/solana-explorer/Cargo.lock b/solana-explorer/Cargo.lock new file mode 100644 index 0000000..ec394de --- /dev/null +++ b/solana-explorer/Cargo.lock @@ -0,0 +1,652 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + +[[package]] +name = "anyhow" +version = "1.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bigdecimal" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6773ddc0eafc0e509fb60e48dff7f450f8e674a0686ae8605e8d9901bd5eefa" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" + +[[package]] +name = "bs58" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" + +[[package]] +name = "bytes" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3e13f66a2f95e32a39eaa81f6b95d42878ca0e1db0c7543723dfe12557e860" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "fastrand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "hashbrown" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hex-literal" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0" + +[[package]] +name = "home" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "indexmap" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" + +[[package]] +name = "linux-raw-sys" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f" + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "memchr" +version = "2.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" + +[[package]] +name = "multimap" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" + +[[package]] +name = "num-bigint" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "pad" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2ad9b889f1b12e0b9ee24db044b5129150d5eada288edc800f789928dc8c0e3" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "percent-encoding" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" + +[[package]] +name = "petgraph" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" +dependencies = [ + "fixedbitset", + "indexmap", +] + +[[package]] +name = "prettyplease" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" +dependencies = [ + "proc-macro2", + "syn 1.0.109", +] + +[[package]] +name = "proc-macro2" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "prost" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-build" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "119533552c9a7ffacc21e099c24a0ac8bb19c2a2a3f363de84cd9b844feab270" +dependencies = [ + "bytes", + "heck", + "itertools", + "lazy_static", + "log", + "multimap", + "petgraph", + "prettyplease", + "prost", + "prost-types", + "regex", + "syn 1.0.109", + "tempfile", + "which", +] + +[[package]] +name = "prost-derive" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "prost-types" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213622a1460818959ac1181aaeb2dc9c7f63df720db7d788b3e24eacd1983e13" +dependencies = [ + "prost", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "regex" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + +[[package]] +name = "rustix" +version = "0.38.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3" +dependencies = [ + "bitflags 2.4.1", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "serde" +version = "1.0.190" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91d3c334ca1ee894a2c6f6ad698fe8c435b76d504b13d436f0685d648d6d96f7" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.190" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67c5609f394e5c2bd7fc51efda478004ea80ef42fee983d5c67a65e34f32c0e3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + +[[package]] +name = "serde_qs" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0431a35568651e363364210c91983c1da5eb29404d9f0928b67d4ebcfa7d330c" +dependencies = [ + "percent-encoding", + "serde", + "thiserror", +] + +[[package]] +name = "substreams" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af972e374502cdfc9998132f5343848d1c58f27a295dc061a89804371f408a46" +dependencies = [ + "anyhow", + "bigdecimal", + "hex", + "hex-literal", + "num-bigint", + "num-traits", + "pad", + "prost", + "prost-build", + "prost-types", + "substreams-macro", + "thiserror", +] + +[[package]] +name = "substreams-macro" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6521ccd011a4c3f52cd3c31fc7400733e4feba2094e0e0e6354adca25b2b3f37" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "thiserror", +] + +[[package]] +name = "substreams-solana" +version = "0.10.2" +source = "git+https://github.com/streamingfast/substreams-solana#c00176f6c3b45ddb17153d980762caa693c8cf18" +dependencies = [ + "anyhow", + "substreams", + "substreams-solana-core", + "substreams-solana-macro", +] + +[[package]] +name = "substreams-solana-core" +version = "0.10.2" +source = "git+https://github.com/streamingfast/substreams-solana#c00176f6c3b45ddb17153d980762caa693c8cf18" +dependencies = [ + "bs58", + "prost", + "prost-build", + "prost-types", +] + +[[package]] +name = "substreams-solana-explorer" +version = "0.1.0" +dependencies = [ + "anyhow", + "bs58", + "getrandom", + "hex-literal", + "num-bigint", + "prost", + "serde", + "serde_qs", + "substreams", + "substreams-solana", +] + +[[package]] +name = "substreams-solana-macro" +version = "0.10.2" +source = "git+https://github.com/streamingfast/substreams-solana#c00176f6c3b45ddb17153d980762caa693c8cf18" +dependencies = [ + "bs58", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tempfile" +version = "3.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" +dependencies = [ + "cfg-if", + "fastrand", + "redox_syscall", + "rustix", + "windows-sys", +] + +[[package]] +name = "thiserror" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-width" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" diff --git a/solana-explorer/Cargo.toml b/solana-explorer/Cargo.toml new file mode 100644 index 0000000..93a13d6 --- /dev/null +++ b/solana-explorer/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "substreams-solana-explorer" +version = "0.1.0" +description = "Substreams showcasing the building blocks of Solana" +edition = "2021" +repository = "https://github.com/streamingfast/substreams-explorers" +license = "Apache 2.0" + +[lib] +name = "substreams" +crate-type = ["cdylib"] + +[dependencies] +bs58 = "0.4" +hex-literal = "0.3" +num-bigint = "0.4" +prost = "0.11" +# Use latest from https://crates.io/crates/substreams +substreams = "0.5" +# Use latest from https://crates.io/crates/substreams-solana +substreams-solana = { git = "https://github.com/streamingfast/substreams-solana" } +serde_qs = "0.12.0" +serde = { version = "1.0", features = ["derive"] } +anyhow = "1.0" + +[target.wasm32-unknown-unknown.dependencies] +getrandom = { version = "0.2", features = ["custom"] } + +[profile.release] +lto = true +opt-level = 's' +strip = "debuginfo" diff --git a/solana-explorer/Makefile b/solana-explorer/Makefile new file mode 100644 index 0000000..36bca83 --- /dev/null +++ b/solana-explorer/Makefile @@ -0,0 +1,11 @@ +.PHONY: build +build: + cargo build --target wasm32-unknown-unknown --release + +.PHONY: protogen +protogen: + substreams protogen ./substreams.yaml --exclude-paths="sf/substreams,google" + +.PHONY: pack +pack: build + substreams pack substreams.yaml diff --git a/solana-explorer/README.md b/solana-explorer/README.md new file mode 100644 index 0000000..1a52945 --- /dev/null +++ b/solana-explorer/README.md @@ -0,0 +1,170 @@ +# Solana Explorer + +The Solana Explorer consists of several Substreams modules showcasing the most basic operations that you can perform with Substreams on the Solana blockchain. + +## Before You Begin + +Make sure you have the [Substreams CLI installed](https://substreams.streamingfast.io/getting-started/installing-the-cli), and you know the [basic structure of a Substreams module](https://substreams.streamingfast.io/getting-started/quickstart). You must also provide an [authentication token](https://substreams.streamingfast.io/reference-and-specs/authentication). + +## Modules + +## Running the Substreams + +First, generate the Protobuf code, which are the outputs of the Substreams: + +``` +> make protogen +``` + +Then, build the Rust code using the `cargo` command-line tool: + +``` +> make build +``` + +### Running the "map_block_meta" Module + +In the following command, you retrieve the metadata of the block with slot number `153000000`. You specify the starting block by using the `--start-block` parameter. + +```bash +> substreams gui -e mainnet.sol.streamingfast.io:443 ./solana-explorer-v0.1.0.spkg map_block_meta --start-block 153000000 --stop-block +1 +Connected (trace ID 0c93ceb65b98b138f0b8caf8a0e81c77) +Progress messages received: 0 (0/sec) +Backprocessing history up to requested target block 153000000: +(hit 'm' to switch mode) + +----------- BLOCK #153,000,000 (ENZNjBKCxXQqgFxX63T6kn7DJwc7fQiwy3W3vyehtEGA) --------------- +{ + "@module": "map_block_meta", + "@block": 153000000, + "@type": "sol.block_meta.v1.BlockMeta", + "@data": { + "slot": "153000000", + "hash": "ENZNjBKCxXQqgFxX63T6kn7DJwc7fQiwy3W3vyehtEGA", + "parentHash": "7Eric2Heq94zoz5zBf5xg3K7opnWDaRVoS6DVa4Xxtcn" + } +} + +all done +``` + +### Running the "map_filter_instructions" Module + +To run this module, you must provide a program id value in the parameters in your substreams.yaml manifest. + +This example will use the default `Stake11111111111111111111111111111111111111` program. + +```yaml +params: + map_filter_instructions: "program_id=Stake11111111111111111111111111111111111111" +``` + +```bash +> substreams run -e mainnet.sol.streamingfast.io:443 ./solana-explorer-v0.1.0.spkg map_filter_instructions -s 153000000 -t +50 +----------- BLOCK #153,000,000 (ENZNjBKCxXQqgFxX63T6kn7DJwc7fQiwy3W3vyehtEGA) --------------- +----------- BLOCK #153,000,001 (8q2n7y3ozKWUWrAGVbNc3wrkxdmT6iSdgf8CHgqrvSv1) --------------- +----------- BLOCK #153,000,002 (AfE4vBBsvcCXzdexP4sX9byHYrdZsUpd2GTTTTvkShxu) --------------- +----------- BLOCK #153,000,003 (H5RZGAShGm7sMW6NvaPY3TsX36WEvugZ64Y1gSBRPyLV) --------------- +----------- BLOCK #153,000,004 (Egf4PFv5636rycdntsBfi26Bou2Mt3Z5UAgH4hBbkZat) --------------- +----------- BLOCK #153,000,005 (DmkkhPG2RDWkJnLbSiG1XTUotJVpLbjqBeRa9FoQB3Tg) --------------- +----------- BLOCK #153,000,006 (Dy9YQQrTed69j7fsy7z3F3sa1x34T4CGmCVQVFoWobRE) --------------- +----------- BLOCK #153,000,007 (3bHscyCgsvzLo6u4CpvCzJe7ELkuf9k8MSwHyLUtif9L) --------------- +----------- BLOCK #153,000,008 (CkDjN7c4hjYqtuYXH9Vw8MTmk29XjgMnbEtAzrjbyjnU) --------------- +----------- BLOCK #153,000,009 (8SVnGrwbwpAWCPdRXKgyNCvJRedEqmYnLazB3mB7Rehg) --------------- +----------- BLOCK #153,000,010 (BTVDWyLK26P2CBjGjCvsHwNqaUcn15xUauwCJmkCSAx1) --------------- +----------- BLOCK #153,000,011 (DVzw63xEAHmWTdo9iA9ca7yTiaondmGGvr4VczQnFhbn) --------------- +----------- BLOCK #153,000,012 (EtMvzAbrkdWpawfP7ozcL86yocFNYxvWvtS4f8pMrajD) --------------- +{ + "@module": "map_filter_instructions", + "@block": 153000012, + "@type": "sol.programs.v1.Instructions", + "@data": { + "instructions": [ + { + "programId": "Stake11111111111111111111111111111111111111", + "accounts": [ + "4nicrkdB15JqjMViy8guLFi8x1RLqTQud37XGX5LZVkN", + "SysvarRent111111111111111111111111111111111" + ], + "data": "1111jgvBfvfPuc2GLifVk9vJpXFTL5urtkjvyJHP6p7TqNR9G47jkYe3RGab9rya96yeGycaY8SVbcpaBkRLZonTJL7y4GyDWwyEmYmvNz74HWew5cPsky18ppTT1WyqmjxvmznzUWXfRogakvUscqJ8C54tP", + "slotNumber": "153000012", + "blockHash": "EtMvzAbrkdWpawfP7ozcL86yocFNYxvWvtS4f8pMrajD" + }, + { + "programId": "Stake11111111111111111111111111111111111111", + "accounts": [ + "4nicrkdB15JqjMViy8guLFi8x1RLqTQud37XGX5LZVkN", + "6F5xdRXh2W3B2vhte12VG79JVUkUSLYrHydGX1SAadfZ", + "SysvarC1ock11111111111111111111111111111111", + "SysvarStakeHistory1111111111111111111111111", + "StakeConfig11111111111111111111111111111111", + "GJYanGsBPyRUgAYkXBTyBYdZiH5wppXoJys9HaJwitzk" + ], + "data": "3xyZh", + "slotNumber": "153000012", + "blockHash": "EtMvzAbrkdWpawfP7ozcL86yocFNYxvWvtS4f8pMrajD" + } + ] + } +} + +----------- BLOCK #153,000,013 (7NVSAZZefTrNkK7JSg227yoponB6Tig27PXnEm7kQFJf) --------------- +----------- BLOCK #153,000,014 (3nfE81F85ggdWxjRZUENBPhvXStAJsVxnwrQ99VcTMME) --------------- +----------- BLOCK #153,000,015 (4N3sqbbJEZobfu1pL6rZEZf6Kpx2WYB8fHm1hbqASa6S) --------------- +----------- BLOCK #153,000,016 (812uX2UUSvvep5APemSmTDk4bDnMkZnJtMBSa6enBmFN) --------------- +----------- BLOCK #153,000,017 (CXsKxq7LmJVW6P3YjBVbrfgDiyMyzYDX5jNhgdsryMfv) --------------- +----------- BLOCK #153,000,018 (FnVqabMm8VEKCr9pchMFxipxSssNeioxx7bCaqyGbzgX) --------------- +----------- BLOCK #153,000,019 (J49iZE979hGtK4hnxUigpxQiNsU3oNq9UMMJqknGLJVT) --------------- +----------- BLOCK #153,000,020 (GJ1BNqsBtyxucvqkipkZDaHW2KGdsU3sR41ebmCxth24) --------------- +----------- BLOCK #153,000,021 (Bxc99wYm1heyzfY1ViXNnJFmf81BFHzLKrwizW5TPemn) --------------- +----------- BLOCK #153,000,022 (2iLweM1VHWnkmXpF7G2fHr52zGuwsEjFXd8ZtpwwUcDw) --------------- +----------- BLOCK #153,000,023 (6JpfNdC2qTErHpXd8e74E5aAkm11USA2rJJbCvQdtHyg) --------------- +----------- BLOCK #153,000,024 (AjN8rk6c8ya5TNYRBUWKUgEYEJceqtJsPMMDdweg4MPR) --------------- +----------- BLOCK #153,000,025 (F7dvT2mwGusrLmRwdJrGZ7cAXsxq43kHsrKpzeseywwg) --------------- +----------- BLOCK #153,000,026 (aGdXha9hhhaETuNywV2XY39Y6B719NBZ6xbUzAu3wah) --------------- +----------- BLOCK #153,000,027 (GfoPvdzekjLV1QHvvHzyVG7xbjajDKA4Ev7gXum2Ry1S) --------------- +----------- BLOCK #153,000,028 (5xj9iYo6nuAiXvPFDUieUKBcRLbg9rz5qiBQg2NYjyBv) --------------- +{ + "@module": "map_filter_instructions", + "@block": 153000028, + "@type": "sol.programs.v1.Instructions", + "@data": { + "instructions": [ + { + "programId": "Stake11111111111111111111111111111111111111", + "accounts": [ + "EQFsbzpgBufUVPV65tt3awmnv1E8anaWfNSBCfnf4bUh", + "SysvarC1ock11111111111111111111111111111111", + "4sUsH6ZzqWU2g1xzM8udFErB4qN3GSL1QbNjiSHc3QxN" + ], + "data": "8QwQj", + "slotNumber": "153000028", + "blockHash": "5xj9iYo6nuAiXvPFDUieUKBcRLbg9rz5qiBQg2NYjyBv" + } + ] + } +} + +----------- BLOCK #153,000,029 (3LBYvzhWfdtcAwuCvoBzTCkUbpVbckyBFAcJezdScGhP) --------------- +----------- BLOCK #153,000,030 (B97KXhFadGBEkMjZ6FTyK6dP6Lyk79p2CqgQBYmjhSdf) --------------- +----------- BLOCK #153,000,031 (C2SgWr1LvVrG3N37DtvN3rd5mQisswU87PfSD6pyLdae) --------------- +----------- BLOCK #153,000,032 (4buy43g7PDLmR196MtRDDid1ZfWbqxJbTi2RWt7gvjqn) --------------- +----------- BLOCK #153,000,033 (C7RAFX27t2cpPyVWXbCACccQAjyHxoyyP2GbKmy7to3y) --------------- +----------- BLOCK #153,000,034 (CyigpnTa5q9j6vLMFpBCNyEUjViojVQcwicb89DAntq6) --------------- +----------- BLOCK #153,000,035 (8npojbiPbBFau8GuXtbYnn6JfBa2tkzfmv6uKEwAKhJ) --------------- +----------- BLOCK #153,000,036 (AAhLqu8Z8REBTMGh5FcMuWyWANBiVpf65XP6PWXG11rx) --------------- +----------- BLOCK #153,000,037 (8AYAF1uiVtnC94c99wmzZP7gRAs7oMFcvE99dtXaNYFL) --------------- +----------- BLOCK #153,000,038 (3aopsHdWuQLT4X11x4bo1e6Vcyyou9HB8wVV7hbMphvi) --------------- +----------- BLOCK #153,000,039 (8HpRgRVePiSpTUqRJBsnvSF3XMFQCyfy2STrTCqTCt2J) --------------- +----------- BLOCK #153,000,040 (AhfUVwbX1SinS8hXzfgSM1ESkrU9CV6aMvTQgch9nZhY) --------------- +----------- BLOCK #153,000,041 (A6JVr9HVkqQL1mvqGLzDuKvbsf9PFQffvS4PnaDNa44F) --------------- +----------- BLOCK #153,000,042 (FMqcoisPGNatsBt3eWmiWJuX1cLGAu3qLAy9696RNp4s) --------------- +----------- BLOCK #153,000,043 (47ARP75kLw3m6s3yWcUWmjsGB4avyNmspgFq6UkxYQde) --------------- +----------- BLOCK #153,000,044 (DzDjDvU1vXCHBeoYwEPZKy3VGByVAM6DkQEKZop3Z8Wn) --------------- +----------- BLOCK #153,000,045 (CrgFgZFxVCSqXUfysNe7GXQ71oTK8eGUVaM9FvsPG81C) --------------- +----------- BLOCK #153,000,046 (4bNCMpe2E3W1zMxHCNmKYooGe2ptTo1EMe92qRKQYMP5) --------------- +----------- BLOCK #153,000,047 (6MqMSHpKjwavQp4FRs5wAGEbKqkp8D82EH8KFkF2YXyH) --------------- +----------- BLOCK #153,000,048 (2E8ncPZMAqa5RKPvEUAMt6abLNcDZM7J6nawyaiSboGD) --------------- +----------- BLOCK #153,000,049 (GyG9Rw4Mo8sYb9WLzz8oqHgV3k4sYa3UWeveGG2uLGWX) --------------- +all done +``` \ No newline at end of file diff --git a/solana-explorer/proto/block_meta.proto b/solana-explorer/proto/block_meta.proto new file mode 100644 index 0000000..8e4a7ce --- /dev/null +++ b/solana-explorer/proto/block_meta.proto @@ -0,0 +1,9 @@ +syntax = "proto3"; + +package sol.block_meta.v1; + +message BlockMeta { + uint64 slot = 1; + string hash = 2; + string parent_hash = 3; +} \ No newline at end of file diff --git a/solana-explorer/proto/program_instructions.proto b/solana-explorer/proto/program_instructions.proto new file mode 100644 index 0000000..6141c2b --- /dev/null +++ b/solana-explorer/proto/program_instructions.proto @@ -0,0 +1,16 @@ +syntax = "proto3"; + +package sol.programs.v1; + +message Instructions { + repeated Instruction instructions = 1; +} + +message Instruction { + string program_id = 1; + repeated string accounts = 2; + string data = 3; + + uint64 slot_number = 4; + string block_hash = 5; +} diff --git a/solana-explorer/rust-toolchain.toml b/solana-explorer/rust-toolchain.toml new file mode 100644 index 0000000..e892501 --- /dev/null +++ b/solana-explorer/rust-toolchain.toml @@ -0,0 +1,4 @@ +[toolchain] +channel = "1.69" +components = [ "rustfmt" ] +targets = [ "wasm32-unknown-unknown" ] \ No newline at end of file diff --git a/solana-explorer/src/lib.rs b/solana-explorer/src/lib.rs new file mode 100644 index 0000000..76a8f1c --- /dev/null +++ b/solana-explorer/src/lib.rs @@ -0,0 +1,4 @@ +mod pb; +mod map_block_full; +mod map_block_meta; +mod map_filter_instructions; diff --git a/solana-explorer/src/map_block_full.rs b/solana-explorer/src/map_block_full.rs new file mode 100644 index 0000000..25c5c05 --- /dev/null +++ b/solana-explorer/src/map_block_full.rs @@ -0,0 +1,6 @@ +use substreams_solana::pb::sf::solana::r#type::v1::Block; + +#[substreams::handlers::map] +fn map_block_full(blk: Block) -> Result { + Ok(blk) +} \ No newline at end of file diff --git a/solana-explorer/src/map_block_meta.rs b/solana-explorer/src/map_block_meta.rs new file mode 100644 index 0000000..53ab91a --- /dev/null +++ b/solana-explorer/src/map_block_meta.rs @@ -0,0 +1,11 @@ +use substreams_solana::pb::sf::solana::r#type::v1::Block; +use crate::pb::sol::block_meta::v1::BlockMeta; + +#[substreams::handlers::map] +fn map_block_meta(blk: Block) -> Result { + Ok(BlockMeta { + slot: blk.slot, + hash: blk.blockhash, + parent_hash: blk.previous_blockhash, + }) +} \ No newline at end of file diff --git a/solana-explorer/src/map_filter_instructions.rs b/solana-explorer/src/map_filter_instructions.rs new file mode 100644 index 0000000..69e86c8 --- /dev/null +++ b/solana-explorer/src/map_filter_instructions.rs @@ -0,0 +1,69 @@ +use anyhow::anyhow; +use serde::Deserialize; +use substreams_solana::pb::sf::solana::r#type::v1::{Block, CompiledInstruction}; +use crate::pb::sol::programs::v1::{Instruction, Instructions}; + +#[derive(Deserialize, Debug)] +struct TransactionFilterParams { + program_id: Option, +} + + +#[substreams::handlers::map] +fn map_filter_instructions(params: String, blk: Block) -> Result> { + let filters = parse_filters_from_params(params)?; + + let mut instructions : Vec = Vec::new(); + + blk.transactions.iter().for_each(|tx| { + let msg = tx.transaction.clone().unwrap().message.unwrap(); + tx.transaction.clone().unwrap(). + let acct_keys = msg.account_keys.as_slice(); + let insts : Vec = msg.instructions.iter() + .filter(|inst| apply_filter(inst, &filters, acct_keys.to_vec())) + .map(|inst| { + Instruction { + slot_number: blk.slot, + block_hash: blk.blockhash.clone(), + program_id: bs58::encode(acct_keys[inst.program_id_index as usize].to_vec()).into_string(), + accounts: inst.accounts.iter().map(|acct| bs58::encode(acct_keys[*acct as usize].to_vec()).into_string()).collect(), + data: bs58::encode(inst.data.clone()).into_string(), + } + }).collect(); + instructions.extend(insts); + }); + + Ok(Instructions { instructions }) +} + +fn parse_filters_from_params(params: String) -> Result> { + let parsed_result = serde_qs::from_str(¶ms); + if parsed_result.is_err() { + return Err(Vec::from([anyhow!("Unexpected error while parsing parameters")])); + } + + let filters = parsed_result.unwrap(); + //todo: verify_filters(&filters)?; + + Ok(filters) +} + +fn apply_filter(instruction: &CompiledInstruction, filters: &TransactionFilterParams, account_keys: Vec>) -> bool { + if filters.program_id.is_none() { + return true; + } + let program_id_filter = filters.program_id.clone().unwrap(); + + let program_account_key = account_keys.get(instruction.program_id_index as usize); + if program_account_key.is_none() { + return false; + } + let program_account_key_val = bs58::encode(program_account_key.unwrap()).into_string(); + + //check if account key value is equal to the program id + if program_account_key_val != program_id_filter { + return false; + } + + true +} \ No newline at end of file diff --git a/solana-explorer/src/pb/mod.rs b/solana-explorer/src/pb/mod.rs new file mode 100644 index 0000000..aec8beb --- /dev/null +++ b/solana-explorer/src/pb/mod.rs @@ -0,0 +1,28 @@ +// @generated +pub mod sf { + pub mod solana { + pub mod r#type { + // @@protoc_insertion_point(attribute:sf.solana.type.v1) + pub mod v1 { + include!("sf.solana.type.v1.rs"); + // @@protoc_insertion_point(sf.solana.type.v1) + } + } + } +} +pub mod sol { + pub mod block_meta { + // @@protoc_insertion_point(attribute:sol.block_meta.v1) + pub mod v1 { + include!("sol.block_meta.v1.rs"); + // @@protoc_insertion_point(sol.block_meta.v1) + } + } + pub mod programs { + // @@protoc_insertion_point(attribute:sol.programs.v1) + pub mod v1 { + include!("sol.programs.v1.rs"); + // @@protoc_insertion_point(sol.programs.v1) + } + } +} diff --git a/solana-explorer/src/pb/sf.solana.type.v1.rs b/solana-explorer/src/pb/sf.solana.type.v1.rs new file mode 100644 index 0000000..3f078a0 --- /dev/null +++ b/solana-explorer/src/pb/sf.solana.type.v1.rs @@ -0,0 +1,256 @@ +// @generated +/// This Block is backwards compatible with solana.storage.ConfirmedBlock.ConfirmedBlock from +/// the Solana Labs repositories. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Block { + #[prost(string, tag="1")] + pub previous_blockhash: ::prost::alloc::string::String, + #[prost(string, tag="2")] + pub blockhash: ::prost::alloc::string::String, + #[prost(uint64, tag="3")] + pub parent_slot: u64, + #[prost(message, repeated, tag="4")] + pub transactions: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag="5")] + pub rewards: ::prost::alloc::vec::Vec, + #[prost(message, optional, tag="6")] + pub block_time: ::core::option::Option, + #[prost(message, optional, tag="7")] + pub block_height: ::core::option::Option, + /// StreamingFast additions + #[prost(uint64, tag="20")] + pub slot: u64, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ConfirmedTransaction { + #[prost(message, optional, tag="1")] + pub transaction: ::core::option::Option, + #[prost(message, optional, tag="2")] + pub meta: ::core::option::Option, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Transaction { + #[prost(bytes="vec", repeated, tag="1")] + pub signatures: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec>, + #[prost(message, optional, tag="2")] + pub message: ::core::option::Option, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Message { + #[prost(message, optional, tag="1")] + pub header: ::core::option::Option, + #[prost(bytes="vec", repeated, tag="2")] + pub account_keys: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec>, + #[prost(bytes="vec", tag="3")] + pub recent_blockhash: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag="4")] + pub instructions: ::prost::alloc::vec::Vec, + #[prost(bool, tag="5")] + pub versioned: bool, + #[prost(message, repeated, tag="6")] + pub address_table_lookups: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MessageHeader { + #[prost(uint32, tag="1")] + pub num_required_signatures: u32, + #[prost(uint32, tag="2")] + pub num_readonly_signed_accounts: u32, + #[prost(uint32, tag="3")] + pub num_readonly_unsigned_accounts: u32, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MessageAddressTableLookup { + #[prost(bytes="vec", tag="1")] + pub account_key: ::prost::alloc::vec::Vec, + #[prost(bytes="vec", tag="2")] + pub writable_indexes: ::prost::alloc::vec::Vec, + #[prost(bytes="vec", tag="3")] + pub readonly_indexes: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct TransactionStatusMeta { + #[prost(message, optional, tag="1")] + pub err: ::core::option::Option, + #[prost(uint64, tag="2")] + pub fee: u64, + #[prost(uint64, repeated, tag="3")] + pub pre_balances: ::prost::alloc::vec::Vec, + #[prost(uint64, repeated, tag="4")] + pub post_balances: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag="5")] + pub inner_instructions: ::prost::alloc::vec::Vec, + #[prost(bool, tag="10")] + pub inner_instructions_none: bool, + #[prost(string, repeated, tag="6")] + pub log_messages: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, + #[prost(bool, tag="11")] + pub log_messages_none: bool, + #[prost(message, repeated, tag="7")] + pub pre_token_balances: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag="8")] + pub post_token_balances: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag="9")] + pub rewards: ::prost::alloc::vec::Vec, + #[prost(bytes="vec", repeated, tag="12")] + pub loaded_writable_addresses: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec>, + #[prost(bytes="vec", repeated, tag="13")] + pub loaded_readonly_addresses: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec>, + #[prost(message, optional, tag="14")] + pub return_data: ::core::option::Option, + #[prost(bool, tag="15")] + pub return_data_none: bool, + /// Sum of compute units consumed by all instructions. + /// Available since Solana v1.10.35 / v1.11.6. + /// Set to `None` for txs executed on earlier versions. + #[prost(uint64, optional, tag="16")] + pub compute_units_consumed: ::core::option::Option, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct TransactionError { + #[prost(bytes="vec", tag="1")] + pub err: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct InnerInstructions { + #[prost(uint32, tag="1")] + pub index: u32, + #[prost(message, repeated, tag="2")] + pub instructions: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct InnerInstruction { + #[prost(uint32, tag="1")] + pub program_id_index: u32, + #[prost(bytes="vec", tag="2")] + pub accounts: ::prost::alloc::vec::Vec, + #[prost(bytes="vec", tag="3")] + pub data: ::prost::alloc::vec::Vec, + /// Invocation stack height of an inner instruction. + /// Available since Solana v1.14.6 + /// Set to `None` for txs executed on earlier versions. + #[prost(uint32, optional, tag="4")] + pub stack_height: ::core::option::Option, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CompiledInstruction { + #[prost(uint32, tag="1")] + pub program_id_index: u32, + #[prost(bytes="vec", tag="2")] + pub accounts: ::prost::alloc::vec::Vec, + #[prost(bytes="vec", tag="3")] + pub data: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct TokenBalance { + #[prost(uint32, tag="1")] + pub account_index: u32, + #[prost(string, tag="2")] + pub mint: ::prost::alloc::string::String, + #[prost(message, optional, tag="3")] + pub ui_token_amount: ::core::option::Option, + #[prost(string, tag="4")] + pub owner: ::prost::alloc::string::String, + #[prost(string, tag="5")] + pub program_id: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct UiTokenAmount { + #[prost(double, tag="1")] + pub ui_amount: f64, + #[prost(uint32, tag="2")] + pub decimals: u32, + #[prost(string, tag="3")] + pub amount: ::prost::alloc::string::String, + #[prost(string, tag="4")] + pub ui_amount_string: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ReturnData { + #[prost(bytes="vec", tag="1")] + pub program_id: ::prost::alloc::vec::Vec, + #[prost(bytes="vec", tag="2")] + pub data: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Reward { + #[prost(string, tag="1")] + pub pubkey: ::prost::alloc::string::String, + #[prost(int64, tag="2")] + pub lamports: i64, + #[prost(uint64, tag="3")] + pub post_balance: u64, + #[prost(enumeration="RewardType", tag="4")] + pub reward_type: i32, + #[prost(string, tag="5")] + pub commission: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Rewards { + #[prost(message, repeated, tag="1")] + pub rewards: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct UnixTimestamp { + #[prost(int64, tag="1")] + pub timestamp: i64, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BlockHeight { + #[prost(uint64, tag="1")] + pub block_height: u64, +} +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum RewardType { + Unspecified = 0, + Fee = 1, + Rent = 2, + Staking = 3, + Voting = 4, +} +impl RewardType { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + RewardType::Unspecified => "Unspecified", + RewardType::Fee => "Fee", + RewardType::Rent => "Rent", + RewardType::Staking => "Staking", + RewardType::Voting => "Voting", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "Unspecified" => Some(Self::Unspecified), + "Fee" => Some(Self::Fee), + "Rent" => Some(Self::Rent), + "Staking" => Some(Self::Staking), + "Voting" => Some(Self::Voting), + _ => None, + } + } +} +// @@protoc_insertion_point(module) diff --git a/solana-explorer/src/pb/sol.block_meta.v1.rs b/solana-explorer/src/pb/sol.block_meta.v1.rs new file mode 100644 index 0000000..acc0112 --- /dev/null +++ b/solana-explorer/src/pb/sol.block_meta.v1.rs @@ -0,0 +1,12 @@ +// @generated +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BlockMeta { + #[prost(uint64, tag="1")] + pub slot: u64, + #[prost(string, tag="2")] + pub hash: ::prost::alloc::string::String, + #[prost(string, tag="3")] + pub parent_hash: ::prost::alloc::string::String, +} +// @@protoc_insertion_point(module) diff --git a/solana-explorer/src/pb/sol.programs.v1.rs b/solana-explorer/src/pb/sol.programs.v1.rs new file mode 100644 index 0000000..8e8784f --- /dev/null +++ b/solana-explorer/src/pb/sol.programs.v1.rs @@ -0,0 +1,22 @@ +// @generated +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Instructions { + #[prost(message, repeated, tag="1")] + pub instructions: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Instruction { + #[prost(string, tag="1")] + pub program_id: ::prost::alloc::string::String, + #[prost(string, repeated, tag="2")] + pub accounts: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, + #[prost(string, tag="3")] + pub data: ::prost::alloc::string::String, + #[prost(uint64, tag="4")] + pub slot_number: u64, + #[prost(string, tag="5")] + pub block_hash: ::prost::alloc::string::String, +} +// @@protoc_insertion_point(module) diff --git a/solana-explorer/substreams.yaml b/solana-explorer/substreams.yaml new file mode 100644 index 0000000..60b21d0 --- /dev/null +++ b/solana-explorer/substreams.yaml @@ -0,0 +1,45 @@ +specVersion: v0.1.0 +package: + name: "solana_explorer" + version: v0.1.0 + +imports: + solana: https://github.com/streamingfast/firehose-solana/releases/download/v0.1.1/solana-v0.1.1.spkg + +protobuf: + files: + - block_meta.proto + - program_instructions.proto + importPaths: + - ./proto + +binaries: + default: + type: wasm/rust-v1 + file: ./target/wasm32-unknown-unknown/release/substreams.wasm + +modules: + - name: map_block_meta + kind: map + inputs: + - source: sf.solana.type.v1.Block + output: + type: proto:sol.block_meta.v1.BlockMeta + + - name: map_block_full + kind: map + inputs: + - source: sf.solana.type.v1.Block + output: + type: proto:sf.solana.type.v1.Block + + - name: map_filter_instructions + kind: map + inputs: + - params: string + - source: sf.solana.type.v1.Block + output: + type: proto:sol.programs.v1.Instructions + +params: + map_filter_instructions: "program_id=Stake11111111111111111111111111111111111111"