├── common ├── trie-geyser │ ├── src │ │ ├── lib.rs │ │ ├── snapshots │ │ │ └── witnessed_trie_geyser__api__slot_data_serialisation.snap │ │ └── api.rs │ └── Cargo.toml ├── wasm │ ├── src │ │ ├── lib.rs │ │ ├── snapshots │ │ │ └── wasm__proto__consensus_state.snap │ │ ├── proto.rs │ │ └── consensus_state.rs │ └── Cargo.toml ├── proto-utils │ ├── src │ │ ├── snapshots │ │ │ └── proto_utils__tests__message.snap │ │ └── tests.rs │ └── Cargo.toml ├── cf-guest │ ├── build.rs │ ├── src │ │ ├── snapshots │ │ │ ├── cf_guest__proto__consensus_state.snap │ │ │ ├── cf_guest__proto__header.snap │ │ │ ├── cf_guest__proto__client_message.snap │ │ │ ├── cf_guest__proto__signature.snap │ │ │ ├── cf_guest__proto__client_state.snap │ │ │ └── cf_guest__proto__misbehaviour.snap │ │ ├── lib.rs │ │ ├── misbehaviour.rs │ │ ├── proto.rs │ │ └── consensus.rs │ ├── Cargo.toml │ └── proto │ │ └── guest.proto ├── cf-solana │ ├── build.rs │ ├── src │ │ ├── snapshots │ │ │ ├── cf_solana__proto__consensus_state.snap │ │ │ ├── cf_solana__proto__client_state.snap │ │ │ ├── cf_solana__proto__header.snap │ │ │ └── cf_solana__proto__client_message.snap │ │ ├── lib.rs │ │ ├── blake3.rs │ │ ├── misbehaviour.rs │ │ ├── proto.rs │ │ ├── client.rs │ │ ├── types.rs │ │ ├── consensus.rs │ │ └── message.rs │ ├── proto │ │ └── solana.proto │ └── Cargo.toml ├── stdx │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── README.md ├── lib │ ├── src │ │ ├── lib.rs │ │ ├── test_utils.rs │ │ └── par.rs │ └── Cargo.toml ├── memory │ └── Cargo.toml ├── sealable-trie │ ├── src │ │ ├── lib.rs │ │ ├── trie │ │ │ └── seal.rs │ │ └── nodes │ │ │ └── stress_tests.rs │ └── Cargo.toml ├── guestchain │ ├── src │ │ ├── snapshots │ │ │ ├── guestchain__proto__consensus_state.snap │ │ │ ├── guestchain__block__block-block.snap │ │ │ ├── guestchain__block__block-header.snap │ │ │ ├── guestchain__block__genesis-header.snap │ │ │ └── guestchain__block__genesis-block.snap │ │ ├── lib.rs │ │ ├── proto.rs │ │ ├── ibc_state.rs │ │ ├── common.rs │ │ └── height.rs │ └── Cargo.toml └── trie-ids │ ├── src │ ├── lib.rs │ └── path.rs │ └── Cargo.toml ├── solana ├── solana-ibc │ ├── programs │ │ └── solana-ibc │ │ │ ├── Xargo.toml │ │ │ ├── src │ │ │ ├── no-mocks.rs │ │ │ ├── snapshots │ │ │ │ ├── solana_ibc__events__snapshot_tests__borsh_ibc_event.snap │ │ │ │ ├── solana_ibc__events__snapshot_tests__borsh_block_finalised.snap │ │ │ │ ├── solana_ibc__events__snapshot_tests__borsh_block_signed.snap │ │ │ │ ├── solana_ibc__events__snapshot_tests__borsh_initialised.snap │ │ │ │ ├── solana_ibc__events__snapshot_tests__borsh_new_block.snap │ │ │ │ └── solana_ibc__events__snapshot_tests__borsh_new_block_with_epoch.snap │ │ │ ├── storage │ │ │ │ └── map.rs │ │ │ ├── allocator.rs │ │ │ └── mocks.rs │ │ │ └── Cargo.toml │ ├── keypair.json │ ├── token_mint_keypair.json │ ├── migrations │ │ └── deploy.ts │ └── tests │ │ ├── constants.ts │ │ ├── schema.ts │ │ └── utils.ts ├── trie-geyser-plugin │ ├── .rustfmt.toml │ ├── config.json │ ├── src │ │ ├── lib.rs │ │ ├── utils.rs │ │ └── config.rs │ └── README.md ├── restaking │ ├── programs │ │ └── restaking │ │ │ ├── Xargo.toml │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ ├── constants.rs │ │ │ └── validation.rs │ ├── restaking-flow.png │ ├── tests │ │ └── constants.ts │ ├── migrations │ │ └── deploy.ts │ └── querying.md ├── write-account │ ├── src │ │ └── lib.rs │ └── Cargo.toml ├── witnessed-trie │ ├── src │ │ ├── lib.rs │ │ ├── utils.rs │ │ └── contract.rs │ ├── Cargo.toml │ └── wip.rs ├── signature-verifier │ ├── src │ │ ├── lib.rs │ │ ├── snapshots │ │ │ ├── sigverify__ed25519_program__test__single_signature__new_instruction_snapshot.snap │ │ │ ├── sigverify__ed25519_program__test__two_signatures_prefix_message__new_instruction_snapshot.snap │ │ │ ├── sigverify__ed25519_program__test__two_signatures_same_message__new_instruction_snapshot.snap │ │ │ └── sigverify__ed25519_program__test__two_signatures__new_instruction_snapshot.snap │ │ └── ed25519.rs │ └── Cargo.toml ├── allocator │ ├── Cargo.toml │ └── src │ │ └── ptr.rs ├── trie │ ├── Cargo.toml │ └── src │ │ ├── data_ref.rs │ │ └── header.rs └── witnessed-trie-cli │ └── Cargo.toml ├── .prettierignore ├── validator ├── src │ └── main.rs ├── example.config.toml ├── Cargo.toml └── README.md ├── .mocharc.cjs ├── .gitignore ├── docker ├── build_docker.sh └── Dockerfile ├── tsconfig.json ├── deny.toml ├── solana-test.sh ├── .rustfmt.toml ├── Anchor.toml ├── README.md ├── package.json └── LICENSE /common/trie-geyser/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod api; 2 | -------------------------------------------------------------------------------- /solana/solana-ibc/programs/solana-ibc/Xargo.toml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /solana/trie-geyser-plugin/.rustfmt.toml: -------------------------------------------------------------------------------- 1 | ../../.rustfmt.toml -------------------------------------------------------------------------------- /common/wasm/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate alloc; 2 | 3 | pub mod consensus_state; 4 | pub mod proto; 5 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | 2 | .anchor 3 | .DS_Store 4 | target 5 | node_modules 6 | dist 7 | build 8 | test-ledger 9 | -------------------------------------------------------------------------------- /solana/restaking/programs/restaking/Xargo.toml: -------------------------------------------------------------------------------- 1 | [target.bpfel-unknown-unknown.dependencies.std] 2 | features = [] 3 | -------------------------------------------------------------------------------- /validator/src/main.rs: -------------------------------------------------------------------------------- 1 | mod command; 2 | mod stake; 3 | mod utils; 4 | mod validator; 5 | 6 | fn main() { command::process_command(); } 7 | -------------------------------------------------------------------------------- /solana/restaking/restaking-flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ComposableFi/emulated-light-client/HEAD/solana/restaking/restaking-flow.png -------------------------------------------------------------------------------- /solana/write-account/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "library")] 2 | pub mod instruction; 3 | #[cfg(not(feature = "library"))] 4 | mod program; 5 | -------------------------------------------------------------------------------- /.mocharc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extension: ['js', 'jsx', 'ts', 'tsx'], 3 | spec: ['solana/restaking/tests/**.{js,ts,jsx,tsx}'], 4 | loader: 'ts-node/esm' 5 | }; 6 | -------------------------------------------------------------------------------- /common/proto-utils/src/snapshots/proto_utils__tests__message.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: common/proto-utils/src/tests.rs 3 | expression: any.value 4 | --- 5 | [ 6 | 8, 7 | 42, 8 | ] 9 | -------------------------------------------------------------------------------- /solana/witnessed-trie/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate alloc; 2 | 3 | #[cfg(feature = "contract")] 4 | mod accounts; 5 | pub mod api; 6 | #[cfg(feature = "contract")] 7 | mod contract; 8 | mod utils; 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.rs.bk 2 | .DS_Store 3 | .anchor 4 | /dist/ 5 | Cargo.lock 6 | local-ibc 7 | node_modules 8 | package-lock.json 9 | target 10 | test-ledger 11 | *.so 12 | .idea 13 | .vscode 14 | -------------------------------------------------------------------------------- /common/cf-guest/build.rs: -------------------------------------------------------------------------------- 1 | fn main() -> std::io::Result<()> { 2 | prost_build::Config::new() 3 | .enable_type_names() 4 | .include_file("messages.rs") 5 | .compile_protos(&["proto/guest.proto"], &["proto/"]) 6 | } 7 | -------------------------------------------------------------------------------- /common/cf-solana/build.rs: -------------------------------------------------------------------------------- 1 | fn main() -> std::io::Result<()> { 2 | prost_build::Config::new() 3 | .enable_type_names() 4 | .include_file("messages.rs") 5 | .compile_protos(&["proto/solana.proto"], &["proto/"]) 6 | } 7 | -------------------------------------------------------------------------------- /common/stdx/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "stdx" 3 | version = "0.0.0" 4 | edition = "2021" 5 | 6 | # [dependencies] 7 | # The crate should have no dependencies. The idea behind it is to include code 8 | # which depends on the standard library only. 9 | -------------------------------------------------------------------------------- /solana/solana-ibc/keypair.json: -------------------------------------------------------------------------------- 1 | [48,123,8,80,248,0,217,142,124,193,95,24,168,139,214,136,147,210,168,135,26,36,162,89,150,185,99,191,247,135,78,111,12,8,4,81,129,165,153,230,192,225,51,119,216,14,69,225,73,7,204,144,39,213,91,255,136,38,95,131,197,4,101,186] -------------------------------------------------------------------------------- /solana/trie-geyser-plugin/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "libpath": "target/release/libwitnessed_trie_geyser_plugin.so", 3 | "trie_program": "8Czzh5DFpFAN69Qow3gvpqS4APJyTFpqZR7cJhwphqPE", 4 | "root_account": "4r4XhdAitwVUXmurwF6ywkVjUYnUqxe23NjzBo6MdNsj", 5 | "bind_address": "127.0.0.1:42069" 6 | } 7 | -------------------------------------------------------------------------------- /solana/signature-verifier/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate alloc; 2 | 3 | mod api; 4 | pub mod ed25519; 5 | pub mod ed25519_program; 6 | #[cfg(not(feature = "library"))] 7 | mod program; 8 | mod verifier; 9 | 10 | pub use api::{SignatureHash, SignaturesAccount}; 11 | pub use verifier::Verifier; 12 | -------------------------------------------------------------------------------- /common/README.md: -------------------------------------------------------------------------------- 1 | Common crates which have no code which is specific to any blockchain. 2 | All code here should be no_std-compatible (though crates can have 3 | `std` optional features). 4 | 5 | The creates implement the generic algorithms and features and are 6 | basis for blockchain-specific contracts. 7 | -------------------------------------------------------------------------------- /docker/build_docker.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | 4 | image="composable/emulated-light-client" 5 | tag="$(git describe --tags --exact-match HEAD 2>/dev/null || git rev-parse --short HEAD)" 6 | 7 | docker build \ 8 | -f ./docker/Dockerfile \ 9 | -t "${image}:${tag}" . 10 | -------------------------------------------------------------------------------- /common/lib/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::unit_arg, clippy::comparison_chain)] 2 | #![no_std] 3 | extern crate alloc; 4 | #[cfg(any(feature = "test_utils", test))] 5 | extern crate std; 6 | 7 | pub mod hash; 8 | pub mod par; 9 | #[cfg(any(feature = "test_utils", test))] 10 | pub mod test_utils; 11 | pub mod u3; 12 | -------------------------------------------------------------------------------- /solana/solana-ibc/token_mint_keypair.json: -------------------------------------------------------------------------------- 1 | [48, 216, 27, 94, 233, 149, 157, 236, 99, 190, 237, 125, 8, 150, 152, 115, 15, 170, 227, 13, 86, 156, 70, 233, 92, 251, 207, 55, 234, 14, 75, 188, 30, 91, 225, 94, 216, 244, 42, 119, 215, 119, 245, 206, 31, 130, 188, 131, 22, 6, 190, 115, 159, 80, 190, 119, 188, 6, 59, 217, 2, 69, 10, 44] -------------------------------------------------------------------------------- /solana/allocator/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "solana-allocator" 3 | authors = ["Michal Nazarewicz "] 4 | edition = "2021" 5 | version.workspace = true 6 | 7 | [target.'cfg(target_os = "solana")'.dependencies] 8 | bytemuck.workspace = true 9 | solana-program.workspace = true 10 | 11 | [dev-dependencies] 12 | bytemuck.workspace = true 13 | -------------------------------------------------------------------------------- /common/memory/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "memory" 3 | authors = ["Michal Nazarewicz "] 4 | version = "0.0.0" 5 | edition = "2021" 6 | 7 | [dependencies] 8 | derive_more.workspace = true 9 | stdx = { workspace = true, optional = true } 10 | 11 | [dev-dependencies] 12 | stdx.workspace = true 13 | 14 | [features] 15 | test_utils = ["stdx"] 16 | -------------------------------------------------------------------------------- /solana/restaking/tests/constants.ts: -------------------------------------------------------------------------------- 1 | export const restakingProgramId = "8n3FHwYxFgQCQc2FNFkwDUf9mcqupxXcCvgfHbApMLv3"; 2 | export const guestChainProgramId = 3 | "2HLLVco5HvwWriNbUhmVwA2pCetRkpgrqwnjcsZdyTKT"; 4 | export const initialMintAmount = 100000000; 5 | export const depositAmount = 4000; 6 | export const boundingPeriod = 5; // seconds 7 | export const testSeed = "abcdefg2"; 8 | -------------------------------------------------------------------------------- /common/sealable-trie/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | extern crate alloc; 3 | #[cfg(test)] 4 | extern crate std; 5 | 6 | pub mod bits; 7 | pub mod nodes; 8 | pub mod proof; 9 | pub mod trie; 10 | 11 | pub use trie::{Error, Trie}; 12 | 13 | pub trait Allocator: memory::Allocator {} 14 | 15 | impl> Allocator for A {} 16 | -------------------------------------------------------------------------------- /solana/write-account/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "solana-write-account" 3 | authors = ["Michal Nazarewicz "] 4 | edition = "2021" 5 | version.workspace = true 6 | 7 | [lib] 8 | name = "write" 9 | crate-type = ["cdylib", "lib"] 10 | 11 | [features] 12 | library = [] 13 | 14 | [dependencies] 15 | solana-program.workspace = true 16 | 17 | stdx.workspace = true 18 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@tsconfig/recommended/tsconfig.json", 3 | "ts-node": { 4 | "compilerOptions": { 5 | "esModuleInterop": true, 6 | "module": "commonjs" 7 | } 8 | }, 9 | "compilerOptions": { 10 | "declaration": true, 11 | "moduleResolution": "node", 12 | "module": "es2015" 13 | }, 14 | "resolveJsonModule": true, 15 | "esModuleInterop": true, 16 | "include": ["/**/*.ts"], 17 | "exclude": ["node_modules"] 18 | } 19 | -------------------------------------------------------------------------------- /validator/example.config.toml: -------------------------------------------------------------------------------- 1 | rpc_url = "http://127.0.0.1:8899" 2 | ws_url = "ws://127.0.0.1:8900" 3 | program_id = "2HLLVco5HvwWriNbUhmVwA2pCetRkpgrqwnjcsZdyTKT" 4 | genesis_hash = "AXO4arKprlSJUQssh8aJxLIWFX5sObiG2Nd2817cfvY=" 5 | keypair = [48,123,8,80,248,0,217,142,124,193,95,24,168,139,214,136,147,210,168,135,26,36,162,89,150,185,99,191,247,135,78,111,12,8,4,81,129,165,153,230,192,225,51,119,216,14,69,225,73,7,204,144,39,213,91,255,136,38,95,131,197,4,101,186] 6 | log_level = "INFO" 7 | -------------------------------------------------------------------------------- /solana/restaking/migrations/deploy.ts: -------------------------------------------------------------------------------- 1 | // Migrations are an early feature. Currently, they're nothing more than this 2 | // single deploy script that's invoked from the CLI, injecting a provider 3 | // configured from the workspace's Anchor.toml. 4 | 5 | const anchor = require("@coral-xyz/anchor"); 6 | 7 | module.exports = async function (provider) { 8 | // Configure client to use the provider. 9 | anchor.setProvider(provider); 10 | 11 | // Add your deploy script here. 12 | }; 13 | -------------------------------------------------------------------------------- /solana/solana-ibc/migrations/deploy.ts: -------------------------------------------------------------------------------- 1 | // Migrations are an early feature. Currently, they're nothing more than this 2 | // single deploy script that's invoked from the CLI, injecting a provider 3 | // configured from the workspace's Anchor.toml. 4 | 5 | const anchor = require("@coral-xyz/anchor"); 6 | 7 | module.exports = async function (provider) { 8 | // Configure client to use the provider. 9 | anchor.setProvider(provider); 10 | 11 | // Add your deploy script here. 12 | }; 13 | -------------------------------------------------------------------------------- /deny.toml: -------------------------------------------------------------------------------- 1 | [sources] 2 | unknown-registry = "deny" 3 | unknown-git = "deny" 4 | allow-registry = ["https://github.com/rust-lang/crates.io-index"] 5 | allow-git = [] 6 | 7 | [bans] 8 | # solana-program is weird and has bunch of duplicate dependencies. 9 | # For now allow duplicates. TODO(mina86): Figure out if there’s 10 | # something better we can do. 11 | multiple-versions = "allow" 12 | skip = [ 13 | # derive_more still uses old syn 14 | { name = "syn", version = "1.0.*" }, 15 | ] 16 | -------------------------------------------------------------------------------- /solana-test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -eux 3 | solana config set --url http://127.0.0.1:8899 4 | cd solana/write-account 5 | cargo build-sbf 6 | cd ../.. 7 | cd solana/signature-verifier 8 | cargo build-sbf 9 | cd ../.. 10 | solana program deploy target/deploy/write.so 11 | solana program deploy target/deploy/sigverify.so 12 | cargo test --lib -- --nocapture --include-ignored ::anchor 13 | find solana/restaking/tests/ -name '*.ts' \ 14 | -exec yarn run ts-mocha -p ./tsconfig.json -t 1000000 {} + 15 | -------------------------------------------------------------------------------- /solana/solana-ibc/programs/solana-ibc/src/no-mocks.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_variables)] 2 | 3 | use anchor_lang::prelude::*; 4 | 5 | use crate::{ibc, MockDeliver}; 6 | 7 | pub(crate) fn mock_deliver<'a, 'info>( 8 | ctx: Context<'a, 'a, 'a, 'info, MockDeliver<'info>>, 9 | port_id: ibc::PortId, 10 | commitment_prefix: ibc::CommitmentPrefix, 11 | client_id: ibc::ClientId, 12 | counterparty_client_id: ibc::ClientId, 13 | ) -> Result<()> { 14 | panic!("This instruction is only available in mocks build") 15 | } 16 | -------------------------------------------------------------------------------- /solana/trie/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "solana-trie" 3 | authors = ["Michal Nazarewicz "] 4 | edition = "2021" 5 | version.workspace = true 6 | 7 | [dependencies] 8 | bytemuck = { workspace = true, features = ["min_const_generics", "must_cast"] } 9 | solana-program.workspace = true 10 | 11 | lib = { workspace = true, features = ["solana-program"] } 12 | memory.workspace = true 13 | sealable-trie.workspace = true 14 | stdx.workspace = true 15 | 16 | [dev-dependencies] 17 | pretty_assertions.workspace = true 18 | -------------------------------------------------------------------------------- /solana/trie-geyser-plugin/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate alloc; 2 | extern crate core; 3 | 4 | use solana_geyser_plugin_interface::geyser_plugin_interface::GeyserPlugin; 5 | 6 | mod config; 7 | mod plugin; 8 | mod rpc; 9 | mod types; 10 | mod utils; 11 | mod worker; 12 | 13 | #[no_mangle] 14 | #[allow(improper_ctypes_definitions)] 15 | /// # Safety 16 | /// This function returns the Plugin pointer as trait GeyserPlugin. 17 | pub unsafe extern "C" fn _create_plugin() -> *mut dyn GeyserPlugin { 18 | Box::into_raw(Box::::default()) 19 | } 20 | -------------------------------------------------------------------------------- /docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rust:1.71.0-bookworm AS build 2 | 3 | WORKDIR /build 4 | 5 | COPY . . 6 | 7 | RUN apt-get update -y \ 8 | && apt-get install -y protobuf-compiler libprotobuf-dev 9 | 10 | RUN cargo fetch --locked 11 | RUN cargo build --release --bin validator 12 | 13 | FROM debian:bookworm 14 | 15 | RUN apt-get update -y \ 16 | && apt-get install -y catatonit openssl ca-certificates 17 | 18 | COPY --from=build /build/target/release/validator /usr/local/bin 19 | 20 | ENTRYPOINT ["/usr/bin/catatonit", "--"] 21 | CMD ["validator"] 22 | -------------------------------------------------------------------------------- /common/proto-utils/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "proto-utils" 3 | authors = ["Michal Nazarewicz "] 4 | version = "0.0.0" 5 | edition = "2021" 6 | 7 | [dependencies] 8 | const_format.workspace = true 9 | derive_more.workspace = true 10 | ibc-core-client-context = { workspace = true, optional = true } 11 | ibc-proto.workspace = true 12 | prost.workspace = true 13 | 14 | [dev-dependencies] 15 | insta.workspace = true 16 | prost = { workspace = true, features = ["prost-derive"] } 17 | 18 | [features] 19 | ibc = ["dep:ibc-core-client-context"] 20 | -------------------------------------------------------------------------------- /solana/solana-ibc/tests/constants.ts: -------------------------------------------------------------------------------- 1 | import { PublicKey, Keypair } from "@solana/web3.js"; 2 | import bs58 from "bs58"; 3 | 4 | export const solanaIbcProgramId = new PublicKey( 5 | "FeFjYj2YuMsk87Cp48ubzQPtW4MWDaKJrCs1TcdgosZJ" 6 | ); 7 | 8 | export const depositorPrivate = 9 | "472ZS33Lftn7wdM31QauCkmpgFKFvgBRg6Z6NGtA6JgeRi1NfeZFRNvNi3b3sh5jvrQWrgiTimr8giVs9oq4UM5g"; // Signer 10 | 11 | export const rpcUrl = "https://api.devnet.solana.com"; 12 | 13 | export const depositor = Keypair.fromSecretKey( 14 | new Uint8Array(bs58.decode(depositorPrivate)) 15 | ); 16 | -------------------------------------------------------------------------------- /common/wasm/src/snapshots/wasm__proto__consensus_state.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: common/wasm/src/proto.rs 3 | expression: any.value 4 | --- 5 | [ 6 | 10, 7 | 32, 8 | 0, 9 | 0, 10 | 0, 11 | 42, 12 | 0, 13 | 0, 14 | 0, 15 | 42, 16 | 0, 17 | 0, 18 | 0, 19 | 42, 20 | 0, 21 | 0, 22 | 0, 23 | 42, 24 | 0, 25 | 0, 26 | 0, 27 | 42, 28 | 0, 29 | 0, 30 | 0, 31 | 42, 32 | 0, 33 | 0, 34 | 0, 35 | 42, 36 | 0, 37 | 0, 38 | 0, 39 | 42, 40 | 16, 41 | 1, 42 | ] 43 | -------------------------------------------------------------------------------- /.rustfmt.toml: -------------------------------------------------------------------------------- 1 | binop_separator = "Back" 2 | blank_lines_lower_bound = 0 3 | blank_lines_upper_bound = 3 4 | color = "Auto" 5 | condense_wildcard_suffixes = true 6 | fn_single_line = true 7 | format_macro_matchers = true 8 | format_strings = true 9 | group_imports = "StdExternalCrate" 10 | imports_granularity = "Module" 11 | max_width = 80 12 | newline_style = "Unix" 13 | normalize_doc_attributes = true 14 | overflow_delimited_expr = true 15 | reorder_imports = true 16 | reorder_modules = true 17 | use_field_init_shorthand = true 18 | use_small_heuristics = "Max" 19 | use_try_shorthand = true 20 | -------------------------------------------------------------------------------- /common/cf-guest/src/snapshots/cf_guest__proto__consensus_state.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: common/cf-guest/src/proto.rs 3 | expression: any.value 4 | --- 5 | [ 6 | 10, 7 | 32, 8 | 0, 9 | 0, 10 | 0, 11 | 42, 12 | 0, 13 | 0, 14 | 0, 15 | 42, 16 | 0, 17 | 0, 18 | 0, 19 | 42, 20 | 0, 21 | 0, 22 | 0, 23 | 42, 24 | 0, 25 | 0, 26 | 0, 27 | 42, 28 | 0, 29 | 0, 30 | 0, 31 | 42, 32 | 0, 33 | 0, 34 | 0, 35 | 42, 36 | 0, 37 | 0, 38 | 0, 39 | 42, 40 | 16, 41 | 1, 42 | ] 43 | -------------------------------------------------------------------------------- /common/cf-solana/src/snapshots/cf_solana__proto__consensus_state.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: common/cf-solana/src/proto.rs 3 | expression: any.value 4 | --- 5 | [ 6 | 10, 7 | 32, 8 | 0, 9 | 0, 10 | 0, 11 | 42, 12 | 0, 13 | 0, 14 | 0, 15 | 42, 16 | 0, 17 | 0, 18 | 0, 19 | 42, 20 | 0, 21 | 0, 22 | 0, 23 | 42, 24 | 0, 25 | 0, 26 | 0, 27 | 42, 28 | 0, 29 | 0, 30 | 0, 31 | 42, 32 | 0, 33 | 0, 34 | 0, 35 | 42, 36 | 0, 37 | 0, 38 | 0, 39 | 42, 40 | 16, 41 | 1, 42 | ] 43 | -------------------------------------------------------------------------------- /common/guestchain/src/snapshots/guestchain__proto__consensus_state.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: common/cf-guest/src/proto.rs 3 | expression: any.value 4 | --- 5 | [ 6 | 10, 7 | 32, 8 | 0, 9 | 0, 10 | 0, 11 | 42, 12 | 0, 13 | 0, 14 | 0, 15 | 42, 16 | 0, 17 | 0, 18 | 0, 19 | 42, 20 | 0, 21 | 0, 22 | 0, 23 | 42, 24 | 0, 25 | 0, 26 | 0, 27 | 42, 28 | 0, 29 | 0, 30 | 0, 31 | 42, 32 | 0, 33 | 0, 34 | 0, 35 | 42, 36 | 0, 37 | 0, 38 | 0, 39 | 42, 40 | 16, 41 | 1, 42 | ] 43 | -------------------------------------------------------------------------------- /solana/solana-ibc/programs/solana-ibc/src/snapshots/solana_ibc__events__snapshot_tests__borsh_ibc_event.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: solana/solana-ibc/programs/solana-ibc/src/events.rs 3 | expression: serialised 4 | --- 5 | [ 6 | 0, 7 | 20, 8 | 4, 9 | 0, 10 | 0, 11 | 0, 12 | 107, 13 | 105, 14 | 110, 15 | 100, 16 | 1, 17 | 0, 18 | 0, 19 | 0, 20 | 3, 21 | 0, 22 | 0, 23 | 0, 24 | 107, 25 | 101, 26 | 121, 27 | 5, 28 | 0, 29 | 0, 30 | 0, 31 | 118, 32 | 97, 33 | 108, 34 | 117, 35 | 101, 36 | ] 37 | -------------------------------------------------------------------------------- /common/trie-geyser/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "witnessed-trie-geyser" 3 | authors = ["Michal Nazarewicz "] 4 | version = "0.0.0" 5 | edition = "2021" 6 | 7 | [dependencies] 8 | serde = { workspace = true, features = ["rc", "std"] } 9 | serde_json.workspace = true 10 | jsonrpc-core-client.workspace = true 11 | jsonrpc-core.workspace = true 12 | jsonrpc-derive.workspace = true 13 | 14 | cf-solana = { workspace = true, features = ["serde"] } 15 | 16 | [dev-dependencies] 17 | insta = { workspace = true, features = ["json"] } 18 | 19 | lib = { workspace = true, features = ["test_utils"] } 20 | -------------------------------------------------------------------------------- /solana/witnessed-trie-cli/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "solana-witnessed-trie-cli" 3 | authors = ["Michal Nazarewicz "] 4 | edition = "2021" 5 | version.workspace = true 6 | 7 | [dependencies] 8 | arrayvec.workspace = true 9 | base64.workspace = true 10 | bytemuck.workspace = true 11 | derive_more.workspace = true 12 | chrono.workspace = true 13 | hex.workspace = true 14 | solana-cli-config.workspace = true 15 | solana-client.workspace = true 16 | solana-sdk.workspace = true 17 | solana-transaction-status.workspace = true 18 | 19 | lib.workspace = true 20 | solana-witnessed-trie.workspace = true 21 | -------------------------------------------------------------------------------- /common/trie-ids/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod ids; 2 | mod path; 3 | pub mod path_info; 4 | mod trie_key; 5 | 6 | mod ibc { 7 | pub(crate) use ibc_core_channel_types::error::ChannelError; 8 | pub(crate) use ibc_core_client_types::Height; 9 | pub(crate) use ibc_core_connection_types::error::ConnectionError; 10 | pub(crate) use ibc_core_host_types::identifiers::{ 11 | ChannelId, ClientId, ConnectionId, PortId, Sequence, 12 | }; 13 | pub(crate) use ibc_core_host_types::path; 14 | } 15 | 16 | pub use ids::{ChannelIdx, ClientIdx, ConnectionIdx, PortChannelPK, PortKey}; 17 | pub use path::SequencePath; 18 | pub use path_info::PathInfo; 19 | pub use trie_key::{Tag, TrieKey}; 20 | -------------------------------------------------------------------------------- /common/trie-ids/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "trie-ids" 3 | authors = ["Michal Nazarewicz "] 4 | version = "0.0.0" 5 | edition = "2021" 6 | 7 | [dependencies] 8 | ascii.workspace = true 9 | base64.workspace = true 10 | borsh = { workspace = true, optional = true } 11 | ibc-core-channel-types.workspace = true 12 | ibc-core-client-types.workspace = true 13 | ibc-core-connection-types.workspace = true 14 | ibc-core-host-types.workspace = true 15 | bytemuck.workspace = true 16 | derive_more.workspace = true 17 | strum.workspace = true 18 | 19 | [dev-dependencies] 20 | hex-literal.workspace = true 21 | lib = { workspace = true, features = ["test_utils"] } 22 | rand.workspace = true 23 | -------------------------------------------------------------------------------- /common/guestchain/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::unit_arg, clippy::comparison_chain)] 2 | #![no_std] 3 | extern crate alloc; 4 | #[cfg(any(feature = "std", test))] 5 | extern crate std; 6 | 7 | pub mod block; 8 | mod candidates; 9 | mod common; 10 | pub mod config; 11 | pub mod epoch; 12 | pub mod height; 13 | pub mod manager; 14 | pub mod validators; 15 | 16 | pub use block::{Block, BlockHeader}; 17 | pub use candidates::{Candidate, Candidates}; 18 | pub use config::Config; 19 | pub use epoch::Epoch; 20 | pub use height::{BlockDelta, BlockHeight, HostDelta, HostHeight}; 21 | pub use manager::ChainManager; 22 | pub use validators::{ 23 | BadFormat, PubKey, Signature, Signer, Validator, Verifier, 24 | }; 25 | -------------------------------------------------------------------------------- /solana/solana-ibc/programs/solana-ibc/src/snapshots/solana_ibc__events__snapshot_tests__borsh_block_finalised.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: solana/solana-ibc/programs/solana-ibc/src/events.rs 3 | expression: serialised 4 | --- 5 | [ 6 | 4, 7 | 0, 8 | 0, 9 | 0, 10 | 42, 11 | 0, 12 | 0, 13 | 0, 14 | 42, 15 | 0, 16 | 0, 17 | 0, 18 | 42, 19 | 0, 20 | 0, 21 | 0, 22 | 42, 23 | 0, 24 | 0, 25 | 0, 26 | 42, 27 | 0, 28 | 0, 29 | 0, 30 | 42, 31 | 0, 32 | 0, 33 | 0, 34 | 42, 35 | 0, 36 | 0, 37 | 0, 38 | 42, 39 | 164, 40 | 1, 41 | 0, 42 | 0, 43 | 0, 44 | 0, 45 | 0, 46 | 0, 47 | ] 48 | -------------------------------------------------------------------------------- /common/cf-solana/src/snapshots/cf_solana__proto__client_state.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: common/cf-solana/src/proto.rs 3 | expression: any.value 4 | --- 5 | [ 6 | 8, 7 | 8, 8 | 18, 9 | 32, 10 | 42, 11 | 42, 12 | 42, 13 | 42, 14 | 42, 15 | 42, 16 | 42, 17 | 42, 18 | 42, 19 | 42, 20 | 42, 21 | 42, 22 | 42, 23 | 42, 24 | 42, 25 | 42, 26 | 42, 27 | 42, 28 | 42, 29 | 42, 30 | 42, 31 | 42, 32 | 42, 33 | 42, 34 | 42, 35 | 42, 36 | 42, 37 | 42, 38 | 42, 39 | 42, 40 | 42, 41 | 42, 42 | 24, 43 | 128, 44 | 128, 45 | 136, 46 | 186, 47 | 144, 48 | 173, 49 | 205, 50 | 4, 51 | ] 52 | -------------------------------------------------------------------------------- /common/sealable-trie/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "sealable-trie" 3 | authors = ["Michal Nazarewicz "] 4 | version = "0.0.0" 5 | edition = "2021" 6 | 7 | [dependencies] 8 | ascii.workspace = true 9 | base64.workspace = true 10 | borsh = { workspace = true, optional = true } 11 | bytemuck.workspace = true 12 | derive_more.workspace = true 13 | sha2.workspace = true 14 | strum.workspace = true 15 | 16 | lib.workspace = true 17 | memory.workspace = true 18 | stdx.workspace = true 19 | 20 | [dev-dependencies] 21 | hex-literal.workspace = true 22 | pretty_assertions.workspace = true 23 | rand.workspace = true 24 | 25 | lib = { workspace = true, features = ["test_utils"] } 26 | memory = { workspace = true, features = ["test_utils"] } 27 | -------------------------------------------------------------------------------- /common/wasm/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wasm" 3 | authors = ["Michal Nazarewicz "] 4 | version = "0.0.0" 5 | edition = "2021" 6 | 7 | [dependencies] 8 | const_format.workspace = true 9 | derive_more.workspace = true 10 | ibc-primitives.workspace = true 11 | ibc-core-commitment-types.workspace = true 12 | ibc-core-client-context.workspace = true 13 | ibc-proto.workspace = true 14 | prost = { workspace = true, features = ["prost-derive"] } 15 | 16 | lib = { workspace = true, features = ["borsh"] } 17 | proto-utils = { workspace = true, features = ["ibc"] } 18 | 19 | [dev-dependencies] 20 | insta.workspace = true 21 | rand.workspace = true 22 | 23 | lib = { workspace = true, features = ["test_utils"] } 24 | 25 | [features] 26 | std = [] 27 | -------------------------------------------------------------------------------- /common/lib/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lib" 3 | authors = ["Michal Nazarewicz "] 4 | version = "0.0.0" 5 | edition = "2021" 6 | 7 | [dependencies] 8 | base64.workspace = true 9 | borsh = { workspace = true, optional = true } 10 | bs58 = { workspace = true, optional = true } 11 | bytemuck = { workspace = true, features = ["derive"] } 12 | derive_more.workspace = true 13 | rayon = { workspace = true, optional = true } 14 | serde = { workspace = true, optional = true } 15 | sha2.workspace = true 16 | solana-program = { workspace = true, optional = true } 17 | 18 | stdx.workspace = true 19 | 20 | [dev-dependencies] 21 | rand.workspace = true 22 | serde.workspace = true 23 | serde_json.workspace = true 24 | 25 | [features] 26 | test_utils = [] 27 | -------------------------------------------------------------------------------- /common/cf-solana/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::unit_arg, clippy::comparison_chain)] 2 | #![no_std] 3 | extern crate alloc; 4 | #[cfg(any(feature = "std", test))] 5 | extern crate std; 6 | 7 | mod blake3; 8 | mod client; 9 | mod consensus; 10 | mod header; 11 | mod message; 12 | mod misbehaviour; 13 | pub mod proof; 14 | pub mod proto; 15 | #[cfg(feature = "serde")] 16 | mod serde_impl; 17 | pub mod types; 18 | 19 | pub use client::impls::{CommonContext, Neighbourhood}; 20 | pub use client::ClientState; 21 | pub use consensus::ConsensusState; 22 | pub use header::Header; 23 | pub use message::ClientMessage; 24 | pub use misbehaviour::Misbehaviour; 25 | pub use proof::IbcProof; 26 | 27 | /// Client type of the Solana blockchain’s light client. 28 | pub const CLIENT_TYPE: &str = "cf-solana"; 29 | -------------------------------------------------------------------------------- /solana/restaking/programs/restaking/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "restaking" 3 | description = "Created with Anchor" 4 | edition = "2021" 5 | version.workspace = true 6 | 7 | [lib] 8 | crate-type = ["cdylib", "lib"] 9 | name = "restaking" 10 | 11 | [features] 12 | # added so that we can compile this along with `solana-ibc` with mocks features. Currently unused. 13 | mocks = [] 14 | no-entrypoint = [] 15 | no-idl = [] 16 | no-log-ix-name = [] 17 | cpi = ["no-entrypoint"] 18 | witness = ["solana-ibc/witness"] 19 | default = [] 20 | 21 | [dependencies] 22 | anchor-lang = { workspace = true, features = ["init-if-needed"] } 23 | anchor-spl = { workspace = true, features = ["metadata"] } 24 | solana-ibc = { workspace = true, features = ["cpi"] } 25 | solana-program.workspace = true 26 | 27 | [dev-dependencies] 28 | home = "=0.5.5" 29 | -------------------------------------------------------------------------------- /common/cf-guest/src/snapshots/cf_guest__proto__header.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: common/cf-guest/src/proto.rs 3 | expression: any.value 4 | --- 5 | [ 6 | 10, 7 | 32, 8 | 0, 9 | 0, 10 | 0, 11 | 0, 12 | 0, 13 | 0, 14 | 0, 15 | 0, 16 | 0, 17 | 0, 18 | 0, 19 | 0, 20 | 0, 21 | 0, 22 | 0, 23 | 0, 24 | 0, 25 | 0, 26 | 0, 27 | 0, 28 | 0, 29 | 0, 30 | 0, 31 | 0, 32 | 0, 33 | 0, 34 | 0, 35 | 0, 36 | 0, 37 | 0, 38 | 0, 39 | 0, 40 | 18, 41 | 10, 42 | 1, 43 | 1, 44 | 1, 45 | 1, 46 | 1, 47 | 1, 48 | 1, 49 | 1, 50 | 1, 51 | 1, 52 | 26, 53 | 10, 54 | 2, 55 | 2, 56 | 2, 57 | 2, 58 | 2, 59 | 2, 60 | 2, 61 | 2, 62 | 2, 63 | 2, 64 | ] 65 | -------------------------------------------------------------------------------- /solana/signature-verifier/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "solana-signature-verifier" 3 | authors = ["Michal Nazarewicz "] 4 | edition = "2021" 5 | version.workspace = true 6 | 7 | [lib] 8 | name = "sigverify" 9 | crate-type = ["cdylib", "lib"] 10 | 11 | [features] 12 | default = ["borsh", "guest"] 13 | guest = ["guestchain"] 14 | library = [] 15 | 16 | [dependencies] 17 | base64.workspace = true 18 | borsh = { workspace = true, optional = true } 19 | bytemuck = { workspace = true, features = ["must_cast"] } 20 | derive_more.workspace = true 21 | solana-program.workspace = true 22 | 23 | guestchain = { workspace = true, optional = true } 24 | lib = { workspace = true, features = ["bs58"] } 25 | stdx.workspace = true 26 | 27 | [dev-dependencies] 28 | ed25519-dalek.workspace = true 29 | insta.workspace = true 30 | solana-sdk.workspace = true 31 | -------------------------------------------------------------------------------- /common/cf-guest/src/snapshots/cf_guest__proto__client_message.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: common/cf-guest/src/proto.rs 3 | expression: any.value 4 | --- 5 | [ 6 | 10, 7 | 58, 8 | 10, 9 | 32, 10 | 0, 11 | 0, 12 | 0, 13 | 0, 14 | 0, 15 | 0, 16 | 0, 17 | 0, 18 | 0, 19 | 0, 20 | 0, 21 | 0, 22 | 0, 23 | 0, 24 | 0, 25 | 0, 26 | 0, 27 | 0, 28 | 0, 29 | 0, 30 | 0, 31 | 0, 32 | 0, 33 | 0, 34 | 0, 35 | 0, 36 | 0, 37 | 0, 38 | 0, 39 | 0, 40 | 0, 41 | 0, 42 | 18, 43 | 10, 44 | 1, 45 | 1, 46 | 1, 47 | 1, 48 | 1, 49 | 1, 50 | 1, 51 | 1, 52 | 1, 53 | 1, 54 | 26, 55 | 10, 56 | 2, 57 | 2, 58 | 2, 59 | 2, 60 | 2, 61 | 2, 62 | 2, 63 | 2, 64 | 2, 65 | 2, 66 | ] 67 | -------------------------------------------------------------------------------- /solana/restaking/programs/restaking/src/constants.rs: -------------------------------------------------------------------------------- 1 | pub const STAKING_PARAMS_SEED: &[u8] = b"staking_params"; 2 | pub const VAULT_PARAMS_SEED: &[u8] = b"vault_params"; 3 | pub const VAULT_SEED: &[u8] = b"vault"; 4 | pub const TEST_SEED: &[u8] = b"abcdefg2"; 5 | pub const ESCROW_RECEIPT_SEED: &[u8] = b"escrow_receipt"; 6 | pub const REWARDS_SEED: &[u8] = b"rewards"; 7 | 8 | pub const TOKEN_NAME: &str = "Composable Restaking Position"; 9 | pub const TOKEN_SYMBOL: &str = "CRP"; 10 | pub const TOKEN_URI: &str = 11 | "https://arweave.net/QbxPlvN1nHFG0AVXfGNdlXUk-LEkrQxFffI3fOUDciA"; 12 | 13 | /// Period of time funds are held until they can be withdrawn. 14 | /// 15 | /// Currently set to seven days. However, when code is compiled with `mocks` 16 | /// feature enabled it’s set to one second for testing. 17 | pub const UNBONDING_PERIOD_IN_SEC: u64 = 18 | if cfg!(feature = "mocks") { 1 } else { 7 * 24 * 60 * 60 }; 19 | -------------------------------------------------------------------------------- /common/cf-guest/src/snapshots/cf_guest__proto__signature.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: common/cf-guest/src/proto.rs 3 | expression: any.value 4 | --- 5 | [ 6 | 8, 7 | 1, 8 | 18, 9 | 64, 10 | 0, 11 | 0, 12 | 0, 13 | 0, 14 | 0, 15 | 0, 16 | 0, 17 | 0, 18 | 0, 19 | 0, 20 | 0, 21 | 0, 22 | 0, 23 | 0, 24 | 0, 25 | 0, 26 | 0, 27 | 0, 28 | 0, 29 | 0, 30 | 0, 31 | 0, 32 | 0, 33 | 0, 34 | 0, 35 | 0, 36 | 0, 37 | 0, 38 | 0, 39 | 0, 40 | 0, 41 | 0, 42 | 0, 43 | 0, 44 | 0, 45 | 0, 46 | 0, 47 | 0, 48 | 0, 49 | 0, 50 | 0, 51 | 0, 52 | 0, 53 | 0, 54 | 0, 55 | 0, 56 | 0, 57 | 0, 58 | 0, 59 | 0, 60 | 0, 61 | 0, 62 | 0, 63 | 0, 64 | 0, 65 | 0, 66 | 0, 67 | 0, 68 | 0, 69 | 0, 70 | 0, 71 | 0, 72 | 0, 73 | 0, 74 | ] 75 | -------------------------------------------------------------------------------- /common/proto-utils/src/tests.rs: -------------------------------------------------------------------------------- 1 | pub mod pb { 2 | pub mod foo { 3 | #[derive(Clone, PartialEq, prost::Message)] 4 | pub struct Message { 5 | #[prost(uint64, tag = "1")] 6 | pub value: u64, 7 | } 8 | 9 | impl prost::Name for Message { 10 | const NAME: &'static str = "Message"; 11 | const PACKAGE: &'static str = "foo"; 12 | 13 | fn full_name() -> ::alloc::string::String { "foo.Message".into() } 14 | 15 | fn type_url() -> ::alloc::string::String { "/foo.Message".into() } 16 | } 17 | } 18 | } 19 | 20 | crate::define_message! { 21 | pub use pb::foo::Message; 22 | test_message Self { value: 42 }; 23 | } 24 | 25 | #[test] 26 | fn test_macro() { 27 | // Check that test_foo test has been defined. 28 | #[allow(dead_code)] 29 | if false { 30 | test_message(); 31 | } 32 | let msg: Message = Message::test(); 33 | assert_eq!(42, msg.value); 34 | } 35 | -------------------------------------------------------------------------------- /solana/trie-geyser-plugin/src/utils.rs: -------------------------------------------------------------------------------- 1 | use solana_geyser_plugin_interface::geyser_plugin_interface::GeyserPluginError; 2 | 3 | 4 | /// Convenience helper which constructs a `GeyserPluginError::Custom` error. 5 | pub fn custom_err(err: T) -> GeyserPluginError 6 | where 7 | T: Into>, 8 | { 9 | GeyserPluginError::Custom(err.into()) 10 | } 11 | 12 | 13 | /// Displays data buffer. 14 | /// 15 | /// Displays the first 64 bytes of the slice in hex followed by its length. 16 | /// Truncated data is indicated with an ellipsis. 17 | pub struct DataDisplay<'a>(pub &'a [u8]); 18 | 19 | impl<'a> core::fmt::Display for DataDisplay<'a> { 20 | fn fmt(&self, fmtr: &mut core::fmt::Formatter) -> core::fmt::Result { 21 | let (data, suff) = if self.0.len() <= 64 { 22 | (self.0, "") 23 | } else { 24 | (&self.0[..64], "…") 25 | }; 26 | write!(fmtr, "0x{}{suff} ({} bytes)", hex::display(&data), self.0.len()) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /common/trie-geyser/src/snapshots/witnessed_trie_geyser__api__slot_data_serialisation.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: common/trie-geyser/src/api.rs 3 | expression: data 4 | --- 5 | { 6 | "delta_hash_proof": { 7 | "parent_blockhash": "AAAAZQAAAGUAAABlAAAAZQAAAGUAAABlAAAAZQAAAGU=", 8 | "accounts_delta_hash": "AAAAZgAAAGYAAABmAAAAZgAAAGYAAABmAAAAZgAAAGY=", 9 | "num_sigs": 103, 10 | "blockhash": "AAAAaAAAAGgAAABoAAAAaAAAAGgAAABoAAAAaAAAAGg=" 11 | }, 12 | "witness_proof": { 13 | "account_hash_data": { 14 | "lamports": 42, 15 | "owner": "1113diW7qC4UejYmrNwaGTZbE5bsokUdUaunfztqD2", 16 | "data": "Zm9v", 17 | "key": "1116GS1EfP7xJU6Yhkt9Xv8BTACkcVxFxApaLznfR3" 18 | }, 19 | "proof": "ARIAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAwAAAAMAAAADAAAAAwAAAAMAAAADAAAAAwAAAAM" 20 | }, 21 | "root_account": { 22 | "lamports": 42, 23 | "owner": "1113Gen6tYXzqXgPfZv3gKu6WGy4oJUpSnEWNcugZMs", 24 | "data": "dHJpZQ==", 25 | "key": "1113KHVc1Nj4KBQwSRHzFbMf6W3fg7EJ5FpRAHuaPZt" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Anchor.toml: -------------------------------------------------------------------------------- 1 | [features] 2 | seeds = false 3 | skip-lint = false 4 | 5 | [programs.devnet] 6 | restaking = "8n3FHwYxFgQCQc2FNFkwDUf9mcqupxXcCvgfHbApMLv3" 7 | solana_ibc = "2HLLVco5HvwWriNbUhmVwA2pCetRkpgrqwnjcsZdyTKT" 8 | 9 | [programs.localnet] 10 | restaking = "8n3FHwYxFgQCQc2FNFkwDUf9mcqupxXcCvgfHbApMLv3" 11 | solana_ibc = "2HLLVco5HvwWriNbUhmVwA2pCetRkpgrqwnjcsZdyTKT" 12 | 13 | [registry] 14 | url = "https://api.apr.dev" 15 | 16 | [provider] 17 | cluster = "localnet" 18 | wallet = "~/.config/solana/id.json" 19 | 20 | [workspace] 21 | members = [ 22 | "solana/restaking/programs/restaking", 23 | "solana/solana-ibc/programs/solana-ibc" 24 | ] 25 | 26 | [scripts] 27 | test = "./solana-test.sh" 28 | 29 | [test] 30 | startup_wait = 20000 31 | shutdown_wait = 2000 32 | upgradeable = true 33 | 34 | [test.validator] 35 | bind_address = "0.0.0.0" 36 | url = "https://api.devnet.solana.com" 37 | ledger = ".anchor/test-ledger" 38 | rpc_port = 8899 39 | 40 | [[test.validator.clone]] 41 | address = "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s" 42 | -------------------------------------------------------------------------------- /common/trie-ids/src/path.rs: -------------------------------------------------------------------------------- 1 | use super::ibc; 2 | 3 | /// A path for next send, receive and ack sequence paths. 4 | /// 5 | /// This is a generalisation of ibc’s `SeqSendPath`, `SeqRecvPath` and 6 | /// `SeqAckPath` which all hold the same elements (port and channel ids) and 7 | /// only differ in type. 8 | pub struct SequencePath<'a> { 9 | pub port_id: &'a ibc::PortId, 10 | pub channel_id: &'a ibc::ChannelId, 11 | } 12 | 13 | impl<'a> From<&'a ibc::path::SeqSendPath> for SequencePath<'a> { 14 | fn from(path: &'a ibc::path::SeqSendPath) -> Self { 15 | Self { port_id: &path.0, channel_id: &path.1 } 16 | } 17 | } 18 | 19 | impl<'a> From<&'a ibc::path::SeqRecvPath> for SequencePath<'a> { 20 | fn from(path: &'a ibc::path::SeqRecvPath) -> Self { 21 | Self { port_id: &path.0, channel_id: &path.1 } 22 | } 23 | } 24 | 25 | impl<'a> From<&'a ibc::path::SeqAckPath> for SequencePath<'a> { 26 | fn from(path: &'a ibc::path::SeqAckPath) -> Self { 27 | Self { port_id: &path.0, channel_id: &path.1 } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /common/guestchain/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "guestchain" 3 | authors = ["Michal Nazarewicz "] 4 | version = "0.0.0" 5 | edition = "2021" 6 | 7 | [dependencies] 8 | borsh.workspace = true 9 | bytemuck = { workspace = true, features = ["must_cast"] } 10 | derive_more.workspace = true 11 | ibc-core-client-context.workspace = true 12 | ibc-core-commitment-types.workspace = true 13 | ibc-core-host.workspace = true 14 | ibc-primitives.workspace = true 15 | ibc-proto.workspace = true 16 | prost = { workspace = true, features = ["prost-derive"] } 17 | strum.workspace = true 18 | 19 | lib = { workspace = true, features = ["borsh"] } 20 | proto-utils = { workspace = true, features = ["ibc"] } 21 | sealable-trie = { workspace = true, features = ["borsh"] } 22 | stdx.workspace = true 23 | trie-ids.workspace = true 24 | 25 | [dev-dependencies] 26 | insta.workspace = true 27 | rand.workspace = true 28 | 29 | lib = { workspace = true, features = ["test_utils"] } 30 | memory = { workspace = true, features = ["test_utils"] } 31 | 32 | [features] 33 | std = [] 34 | test_utils = [] 35 | -------------------------------------------------------------------------------- /validator/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "validator" 3 | version = "0.0.7" 4 | authors.workspace = true 5 | edition.workspace = true 6 | rust-version.workspace = true 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [dependencies] 11 | anchor-client.workspace = true 12 | anchor-lang.workspace = true 13 | anchor-spl.workspace = true 14 | bs58.workspace = true 15 | base64.workspace = true 16 | borsh.workspace = true 17 | clap.workspace = true 18 | derive_more.workspace = true 19 | dialoguer.workspace = true 20 | directories.workspace = true 21 | env_logger.workspace = true 22 | log.workspace = true 23 | reqwest = { workspace = true, features = ["blocking", "json"] } 24 | serde.workspace = true 25 | serde_json.workspace = true 26 | serde_bytes.workspace = true 27 | toml.workspace = true 28 | 29 | guestchain.workspace = true 30 | lib.workspace = true 31 | restaking.workspace = true 32 | solana-signature-verifier = { workspace = true, features = ["library"] } 33 | solana-ibc.workspace = true 34 | solana-trie.workspace = true 35 | 36 | [features] 37 | witness = ["solana-ibc/witness"] 38 | -------------------------------------------------------------------------------- /common/guestchain/src/proto.rs: -------------------------------------------------------------------------------- 1 | pub use proto_utils::{Any, AnyConvert, BadMessage, DecodeError}; 2 | 3 | mod pb { 4 | include!(concat!(env!("OUT_DIR"), "/messages.rs")); 5 | } 6 | 7 | impl_proto!(ClientState; test_client_state Self { 8 | genesis_hash: lib::hash::CryptoHash::test(24).to_vec(), 9 | latest_height: 8, 10 | epoch_commitment: lib::hash::CryptoHash::test(11).to_vec(), 11 | is_frozen: false, 12 | trusting_period_ns: 30 * 24 * 3600 * 1_000_000_000, 13 | }); 14 | 15 | impl_proto!(ConsensusState; test_consensus_state { 16 | let block_hash = lib::hash::CryptoHash::test(42).to_vec(); 17 | Self { block_hash, timestamp_ns: 1 } 18 | }); 19 | 20 | impl_proto!(Header; test_header { 21 | // TODO(mina86): Construct a proper signed header. 22 | Self { 23 | genesis_hash: alloc::vec![0; 32], 24 | block_header: alloc::vec![1; 10], 25 | epoch: alloc::vec![2; 10], 26 | signatures: alloc::vec![], 27 | } 28 | }); 29 | 30 | impl_proto!(Signature; test_signature Self { 31 | index: 1, 32 | signature: alloc::vec![0; 64], 33 | }); 34 | 35 | impl_proto!(Misbehaviour; test_misbehaviour Self { 36 | header1: Some(Header::test()), 37 | header2: Some(Header::test()), 38 | }); 39 | -------------------------------------------------------------------------------- /common/cf-guest/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cf-guest" 3 | authors = ["Michal Nazarewicz "] 4 | version = "0.0.0" 5 | edition = "2021" 6 | 7 | [dependencies] 8 | borsh.workspace = true 9 | bytemuck = { workspace = true, features = ["must_cast"] } 10 | derive_more.workspace = true 11 | ibc-core-client-context.workspace = true 12 | ibc-core-commitment-types.workspace = true 13 | ibc-core-host.workspace = true 14 | ibc-primitives.workspace = true 15 | ibc-client-tendermint-types.workspace = true 16 | ibc-proto.workspace = true 17 | prost = { workspace = true, features = ["prost-derive"] } 18 | 19 | guestchain.workspace = true 20 | lib = { workspace = true, features = ["borsh"] } 21 | proto-utils = { workspace = true, features = ["ibc"] } 22 | sealable-trie = { workspace = true, features = ["borsh"] } 23 | stdx.workspace = true 24 | trie-ids.workspace = true 25 | 26 | [build-dependencies] 27 | prost-build.workspace = true 28 | 29 | [dev-dependencies] 30 | insta.workspace = true 31 | rand.workspace = true 32 | 33 | guestchain = { workspace = true, features = ["test_utils"] } 34 | lib = { workspace = true, features = ["test_utils"] } 35 | memory = { workspace = true, features = ["test_utils"] } 36 | 37 | [features] 38 | std = [] 39 | -------------------------------------------------------------------------------- /common/wasm/src/proto.rs: -------------------------------------------------------------------------------- 1 | pub use proto_utils::{Any, AnyConvert, BadMessage, DecodeError}; 2 | 3 | /// The consensus state in wasm. 4 | #[derive(Clone, PartialEq, Eq, prost::Message)] 5 | pub struct ConsensusState { 6 | /// protobuf encoded data of consensus state 7 | #[prost(bytes = "vec", tag = "1")] 8 | pub data: alloc::vec::Vec, 9 | /// Timestamp in nanoseconds. 10 | #[prost(uint64, tag = "2")] 11 | pub timestamp_ns: u64, 12 | } 13 | 14 | impl prost::Name for ConsensusState { 15 | const PACKAGE: &'static str = "ibc.lightclients.wasm.v1"; 16 | const NAME: &'static str = "ConsensusState"; 17 | 18 | fn full_name() -> alloc::string::String { 19 | const_format::concatcp!( 20 | ConsensusState::PACKAGE, 21 | ".", 22 | ConsensusState::NAME 23 | ) 24 | .into() 25 | } 26 | fn type_url() -> alloc::string::String { 27 | const_format::concatcp!( 28 | "/", 29 | ConsensusState::PACKAGE, 30 | ".", 31 | ConsensusState::NAME 32 | ) 33 | .into() 34 | } 35 | } 36 | 37 | proto_utils::define_message! { 38 | ConsensusState; test_consensus_state { 39 | let data = lib::hash::CryptoHash::test(42).to_vec(); 40 | Self { data, timestamp_ns: 1 } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /solana/witnessed-trie/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "solana-witnessed-trie" 3 | authors = ["Michal Nazarewicz "] 4 | edition = "2021" 5 | version.workspace = true 6 | 7 | [lib] 8 | name = "wittrie" 9 | crate-type = ["cdylib", "lib"] 10 | 11 | [dependencies] 12 | arrayvec.workspace = true 13 | bytemuck = { workspace = true, features = ["min_const_generics"] } 14 | derive_more.workspace = true 15 | hex = { workspace = true, optional = true } 16 | solana-program = { workspace = true, optional = true } 17 | solana-program-2 = { workspace = true, optional = true } 18 | strum = { features = ["derive"], workspace = true } 19 | 20 | cf-solana = { workspace = true, optional = true } 21 | lib.workspace = true 22 | memory = { workspace = true, optional = true } 23 | sealable-trie = { workspace = true, optional = true } 24 | solana-trie.workspace = true 25 | stdx.workspace = true 26 | 27 | [dev-dependencies] 28 | blake3.workspace = true 29 | hex-literal.workspace = true 30 | 31 | [features] 32 | default = ["contract"] 33 | api = [ 34 | "cf-solana", 35 | "cf-solana/solana-program", 36 | "solana-program", 37 | ] 38 | api2 = [ 39 | "cf-solana", 40 | "cf-solana/solana-program-2", 41 | "solana-program-2" 42 | ] 43 | contract = [ 44 | "api", 45 | "hex", 46 | "memory", 47 | "sealable-trie", 48 | ] 49 | -------------------------------------------------------------------------------- /common/lib/src/test_utils.rs: -------------------------------------------------------------------------------- 1 | /// Reads `STRESS_TEST_ITERATIONS` environment variable to determine how many 2 | /// iterations stress tests should run. 3 | /// 4 | /// The variable is used by tests which generate random data to verify 5 | /// invariants. By default they run hundred thousand iterations. The 6 | /// aforementioned environment variable allows that number to be changed 7 | /// (including to zero which effectively disables such tests). 8 | /// 9 | /// Heavier tests can use `divisor` argument greater than one to return the 10 | /// value reduced by given factor. Using `divisor` is better than dividing the 11 | /// result because if requested number of tests is non-zero, this function will 12 | /// always return at least one. 13 | /// 14 | /// When running under Miri, the returned value is clamped to be at most five. 15 | /// The idea being to avoid stress tests, which run for good several second when 16 | /// run normally, taking minutes or hours when run through Miri. 17 | pub fn get_iteration_count(divisor: usize) -> usize { 18 | use core::str::FromStr; 19 | let n = std::env::var_os("STRESS_TEST_ITERATIONS") 20 | .map(|val| usize::from_str(val.to_str().unwrap()).unwrap()) 21 | .unwrap_or(100_000); 22 | let n = match n { 23 | 0 => 0, 24 | n => 1.max(n / divisor), 25 | }; 26 | if cfg!(miri) { 27 | n.min(5) 28 | } else { 29 | n 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /common/cf-guest/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::unit_arg, clippy::comparison_chain)] 2 | #![no_std] 3 | extern crate alloc; 4 | #[cfg(any(feature = "std", test))] 5 | extern crate std; 6 | 7 | mod client; 8 | mod consensus; 9 | mod header; 10 | mod message; 11 | mod misbehaviour; 12 | pub mod proof; 13 | pub mod proto; 14 | 15 | pub use client::impls::{CommonContext, Neighbourhood}; 16 | pub use client::ClientState; 17 | pub use consensus::ConsensusState; 18 | pub use header::Header; 19 | pub use message::ClientMessage; 20 | pub use misbehaviour::Misbehaviour; 21 | pub use proof::IbcProof; 22 | 23 | /// Client type of the guest blockchain’s light client. 24 | pub const CLIENT_TYPE: &str = "cf-guest"; 25 | 26 | pub use crate::proto::{BadMessage, DecodeError}; 27 | 28 | /// Returns digest of the value with client id mixed in. 29 | /// 30 | /// We don’t store full client id in the trie key for paths which include 31 | /// client id. To avoid accepting malicious proofs, we must include it in 32 | /// some other way. We do this by mixing in the client id into the hash of 33 | /// the value stored at the path. 34 | /// 35 | /// Specifically, this calculates `digest(client_id || b'0' || serialised)`. 36 | #[inline] 37 | pub fn digest_with_client_id( 38 | client_id: &ibc_core_host::types::identifiers::ClientId, 39 | value: &[u8], 40 | ) -> lib::hash::CryptoHash { 41 | lib::hash::CryptoHash::digestv(&[client_id.as_bytes(), b"\0", value]) 42 | } 43 | -------------------------------------------------------------------------------- /solana/witnessed-trie/src/utils.rs: -------------------------------------------------------------------------------- 1 | /// Returns the first `N` elements from the `data` slice or error if the slice 2 | /// is too short. Updates the slice past the returned elements. 3 | pub(crate) fn take<'a, const N: usize>( 4 | data: &mut &'a [u8], 5 | ) -> Result<&'a [u8; N], DataTooShort> { 6 | if let Some((head, tail)) = stdx::split_at::(data) { 7 | *data = tail; 8 | Ok(head) 9 | } else { 10 | Err(DataTooShort { expected: N, left: data.len() }) 11 | } 12 | } 13 | 14 | /// Returns the first `n` elements from the `data` slice or error if the slice 15 | /// is too short. Updates the slice past the returned elements. 16 | // TODO(mina86): Use [T]::split_at_checked once that stabilises. 17 | pub(crate) fn take_slice<'a>( 18 | n: usize, 19 | data: &mut &'a [u8], 20 | ) -> Result<&'a [u8], DataTooShort> { 21 | if data.len() >= n { 22 | let (head, tail) = data.split_at(n); 23 | *data = tail; 24 | Ok(head) 25 | } else { 26 | Err(DataTooShort { expected: n, left: data.len() }) 27 | } 28 | } 29 | 30 | /// Error trying to read bytes from instruction data. 31 | #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, derive_more::Display)] 32 | #[display( 33 | fmt = "not enough data; expected {} more bytes but only {} left", 34 | expected, 35 | left 36 | )] 37 | pub(crate) struct DataTooShort { 38 | pub expected: usize, 39 | pub left: usize, 40 | } 41 | -------------------------------------------------------------------------------- /solana/solana-ibc/tests/schema.ts: -------------------------------------------------------------------------------- 1 | import { BorshSchema, Unit } from "borsher"; 2 | 3 | const tracePathSchema = BorshSchema.Vec( 4 | BorshSchema.Struct({ 5 | port_id: BorshSchema.String, 6 | channel_id: BorshSchema.String, 7 | }) 8 | ); 9 | 10 | const packetDataSchema = BorshSchema.Struct({ 11 | token: BorshSchema.Struct({ 12 | denom: BorshSchema.Struct({ 13 | trace_path: tracePathSchema, 14 | base_denom: BorshSchema.String, 15 | }), 16 | amount: BorshSchema.Array(BorshSchema.u8, 32), 17 | }), 18 | sender: BorshSchema.String, 19 | receiver: BorshSchema.String, 20 | memo: BorshSchema.String, 21 | }); 22 | 23 | const timeoutHeightSchema = BorshSchema.Enum({ 24 | Never: BorshSchema.Unit, 25 | At: BorshSchema.Struct({ 26 | revision_number: BorshSchema.u64, 27 | revision_height: BorshSchema.u64, 28 | }), 29 | }); 30 | const timeoutTimestampSchema = BorshSchema.Struct({ 31 | time: BorshSchema.u64, 32 | }); 33 | 34 | export const msgTransferSchema = BorshSchema.Struct({ 35 | port_id_on_a: BorshSchema.String, 36 | chan_id_on_a: BorshSchema.String, 37 | packet_data: packetDataSchema, 38 | timeout_height_on_b: timeoutHeightSchema, 39 | timeout_timestamp_on_b: timeoutTimestampSchema, 40 | }); 41 | 42 | export const instructionSchema = BorshSchema.Struct({ 43 | discriminator: BorshSchema.Array(BorshSchema.u8, 8), 44 | hashed_base_denom: BorshSchema.Array(BorshSchema.u8, 32), 45 | msg: msgTransferSchema, 46 | }); 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Emulated Light Client 2 | 3 | This is our attempt to build a bridge between Solana and Cosmos using IBC 4 | 5 | ## Instructions to test solana program 6 | 7 | 1. Run anchor test with `mocks` feature. Since we cannot pass features to anchor test command, we need to build it. 8 | ``` 9 | anchor build -- --features mocks 10 | ``` 11 | 12 | 2. Now while running the tests, we need to provide a flag to skip build since they are already set. Not providing the flag to skip build would make the program to be built again but without any features ( which we dont want for testing ). 13 | ``` 14 | anchor test --skip-build 15 | ``` 16 | 17 | ### Note: 18 | - If you want to deploy the program with `mocks` feature, you need to build the program with the mocks feature and then deploy. 19 | ``` 20 | anchor build -- --features mocks 21 | anchor deploy 22 | ``` 23 | - If you want to retain the local state once the tests are run, you would have to run a local validator. A local validator should run in the background and while running the test `skip-local-validator` flag has to be passed so that the program doesnt spin up its only validator. 24 | Below is the command to run local validator ( run it in a seperate terminal). 25 | ``` 26 | solana-test-validator -r 27 | ``` 28 | And pass the flag to skip local validator while running the tests. 29 | ``` 30 | anchor test --skip-local-validator --skip-build 31 | ``` 32 | The `skip-build` has to be passed if you are running tests with `mocks` feature. So remember to build it with the command above before you run the tests. 33 | -------------------------------------------------------------------------------- /validator/README.md: -------------------------------------------------------------------------------- 1 | # Guest Chain Validator 2 | 3 | ## Setup 4 | 5 | 1. Install the validator CLI using the below command (From `validator-impl` branch until its merged) 6 | ``` 7 | cargo install --git https://github.com/composableFi/emulated-light-client#validator-impl 8 | ``` 9 | 2. Check if the validator CLI is installed using the below command. The current version would print indicating successful installation. 10 | ``` 11 | validator --version 12 | > 0.0.1 13 | ``` 14 | 3. Set up the rpc url with validator keypair using the command below. The validator keypair can be any solana keypair which has enough SOL to pay for transaction fees. 15 | ``` 16 | validator init --rpc-url --ws-url --program-id --genesis-hash --keypair-path 17 | ``` 18 | **Note:** The key utilised here does not need to be the same as your mainnet validator key; it can be any Solana mainnet account holding SOL for covering gas fees. After completing all the steps outlined in this guide, please provide us with the address associated with this key. 19 | 20 | 4. Once the config file is set, run the validator. 21 | ``` 22 | validator run 23 | ``` 24 | **Note:** You can even pass any of the arguments which would override the default config set in the previous step. These arguments are 25 | optional and have higher preference than the default config file. Any of the arguments can be passed and it's unnecessary to pass 26 | all of them. 27 | ``` 28 | validator run --rpc-url --ws-url --program-id --genesis-hash --keypair-path 29 | ``` 30 | 31 | -------------------------------------------------------------------------------- /common/cf-guest/src/snapshots/cf_guest__proto__client_state.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: common/cf-guest/src/proto.rs 3 | expression: any.value 4 | --- 5 | [ 6 | 10, 7 | 32, 8 | 0, 9 | 0, 10 | 0, 11 | 24, 12 | 0, 13 | 0, 14 | 0, 15 | 24, 16 | 0, 17 | 0, 18 | 0, 19 | 24, 20 | 0, 21 | 0, 22 | 0, 23 | 24, 24 | 0, 25 | 0, 26 | 0, 27 | 24, 28 | 0, 29 | 0, 30 | 0, 31 | 24, 32 | 0, 33 | 0, 34 | 0, 35 | 24, 36 | 0, 37 | 0, 38 | 0, 39 | 24, 40 | 16, 41 | 8, 42 | 24, 43 | 128, 44 | 128, 45 | 136, 46 | 186, 47 | 144, 48 | 173, 49 | 205, 50 | 4, 51 | 34, 52 | 32, 53 | 0, 54 | 0, 55 | 0, 56 | 11, 57 | 0, 58 | 0, 59 | 0, 60 | 11, 61 | 0, 62 | 0, 63 | 0, 64 | 11, 65 | 0, 66 | 0, 67 | 0, 68 | 11, 69 | 0, 70 | 0, 71 | 0, 72 | 11, 73 | 0, 74 | 0, 75 | 0, 76 | 11, 77 | 0, 78 | 0, 79 | 0, 80 | 11, 81 | 0, 82 | 0, 83 | 0, 84 | 11, 85 | 50, 86 | 32, 87 | 0, 88 | 0, 89 | 0, 90 | 12, 91 | 0, 92 | 0, 93 | 0, 94 | 12, 95 | 0, 96 | 0, 97 | 0, 98 | 12, 99 | 0, 100 | 0, 101 | 0, 102 | 12, 103 | 0, 104 | 0, 105 | 0, 106 | 12, 107 | 0, 108 | 0, 109 | 0, 110 | 12, 111 | 0, 112 | 0, 113 | 0, 114 | 12, 115 | 0, 116 | 0, 117 | 0, 118 | 12, 119 | ] 120 | -------------------------------------------------------------------------------- /common/cf-solana/src/blake3.rs: -------------------------------------------------------------------------------- 1 | pub use ::blake3::Hasher; 2 | use lib::hash::CryptoHash; 3 | 4 | const CONSIDER_SOL: bool = 5 | !cfg!(feature = "no-blake3-syscall") && cfg!(target_os = "solana-program"); 6 | const HAS_SOL: bool = 7 | cfg!(feature = "solana-program") || cfg!(feature = "solana-program-2"); 8 | const USE_SOL: bool = CONSIDER_SOL && HAS_SOL; 9 | 10 | /// Calculates Blake3 hash of given byte slice. 11 | /// 12 | /// When `solana-program` or `solana-program-2` feature is enabled and 13 | /// building a solana program, this is using Solana’s `sol_blake3` syscall. 14 | /// Otherwise, the calculation is done by `blake3` crate. 15 | pub fn hash(bytes: &[u8]) -> CryptoHash { 16 | if USE_SOL { 17 | hashv(&[bytes]) 18 | } else { 19 | CryptoHash(::blake3::hash(bytes).into()) 20 | } 21 | } 22 | 23 | /// Calculates Blake3 hash of concatenation of given byte slices. 24 | /// 25 | /// When `solana` or `solana2` feature is enabled and building a Solana 26 | /// program, this is using Solana’s `sol_blake3` syscall. Otherwise, the 27 | /// calculation is done by `blake3` crate. 28 | #[allow(unreachable_code)] 29 | pub fn hashv(slices: &[&[u8]]) -> CryptoHash { 30 | if USE_SOL { 31 | #[cfg(feature = "solana-program-2")] 32 | return CryptoHash(solana_program_2::blake3::hashv(slices).0); 33 | #[cfg(feature = "solana-program")] 34 | return CryptoHash(solana_program::blake3::hashv(slices).0); 35 | } 36 | 37 | let mut hasher = Hasher::default(); 38 | for bytes in slices { 39 | hasher.update(bytes); 40 | } 41 | CryptoHash(hasher.finalize().into()) 42 | } 43 | -------------------------------------------------------------------------------- /common/cf-guest/src/snapshots/cf_guest__proto__misbehaviour.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: common/cf-guest/src/proto.rs 3 | expression: any.value 4 | --- 5 | [ 6 | 10, 7 | 58, 8 | 10, 9 | 32, 10 | 0, 11 | 0, 12 | 0, 13 | 0, 14 | 0, 15 | 0, 16 | 0, 17 | 0, 18 | 0, 19 | 0, 20 | 0, 21 | 0, 22 | 0, 23 | 0, 24 | 0, 25 | 0, 26 | 0, 27 | 0, 28 | 0, 29 | 0, 30 | 0, 31 | 0, 32 | 0, 33 | 0, 34 | 0, 35 | 0, 36 | 0, 37 | 0, 38 | 0, 39 | 0, 40 | 0, 41 | 0, 42 | 18, 43 | 10, 44 | 1, 45 | 1, 46 | 1, 47 | 1, 48 | 1, 49 | 1, 50 | 1, 51 | 1, 52 | 1, 53 | 1, 54 | 26, 55 | 10, 56 | 2, 57 | 2, 58 | 2, 59 | 2, 60 | 2, 61 | 2, 62 | 2, 63 | 2, 64 | 2, 65 | 2, 66 | 18, 67 | 58, 68 | 10, 69 | 32, 70 | 0, 71 | 0, 72 | 0, 73 | 0, 74 | 0, 75 | 0, 76 | 0, 77 | 0, 78 | 0, 79 | 0, 80 | 0, 81 | 0, 82 | 0, 83 | 0, 84 | 0, 85 | 0, 86 | 0, 87 | 0, 88 | 0, 89 | 0, 90 | 0, 91 | 0, 92 | 0, 93 | 0, 94 | 0, 95 | 0, 96 | 0, 97 | 0, 98 | 0, 99 | 0, 100 | 0, 101 | 0, 102 | 18, 103 | 10, 104 | 1, 105 | 1, 106 | 1, 107 | 1, 108 | 1, 109 | 1, 110 | 1, 111 | 1, 112 | 1, 113 | 1, 114 | 26, 115 | 10, 116 | 2, 117 | 2, 118 | 2, 119 | 2, 120 | 2, 121 | 2, 122 | 2, 123 | 2, 124 | 2, 125 | 2, 126 | ] 127 | -------------------------------------------------------------------------------- /common/guestchain/src/snapshots/guestchain__block__block-block.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: common/blockchain/src/block.rs 3 | expression: check(&block) 4 | --- 5 | [ 6 | 0, 7 | 126, 8 | 90, 9 | 201, 10 | 10, 11 | 178, 12 | 207, 13 | 85, 14 | 189, 15 | 80, 16 | 13, 17 | 163, 18 | 112, 19 | 235, 20 | 105, 21 | 78, 22 | 143, 23 | 188, 24 | 233, 25 | 155, 26 | 153, 27 | 248, 28 | 202, 29 | 172, 30 | 56, 31 | 15, 32 | 114, 33 | 95, 34 | 101, 35 | 124, 36 | 198, 37 | 197, 38 | 239, 39 | 1, 40 | 0, 41 | 0, 42 | 0, 43 | 0, 44 | 0, 45 | 0, 46 | 0, 47 | 50, 48 | 0, 49 | 0, 50 | 0, 51 | 0, 52 | 0, 53 | 0, 54 | 0, 55 | 50, 56 | 0, 57 | 0, 58 | 0, 59 | 0, 60 | 0, 61 | 0, 62 | 0, 63 | 0, 64 | 0, 65 | 0, 66 | 99, 67 | 0, 68 | 0, 69 | 0, 70 | 99, 71 | 0, 72 | 0, 73 | 0, 74 | 99, 75 | 0, 76 | 0, 77 | 0, 78 | 99, 79 | 0, 80 | 0, 81 | 0, 82 | 99, 83 | 0, 84 | 0, 85 | 0, 86 | 99, 87 | 0, 88 | 0, 89 | 0, 90 | 99, 91 | 0, 92 | 0, 93 | 0, 94 | 99, 95 | 126, 96 | 90, 97 | 201, 98 | 10, 99 | 178, 100 | 207, 101 | 85, 102 | 189, 103 | 80, 104 | 13, 105 | 163, 106 | 112, 107 | 235, 108 | 105, 109 | 78, 110 | 143, 111 | 188, 112 | 233, 113 | 155, 114 | 153, 115 | 248, 116 | 202, 117 | 172, 118 | 56, 119 | 15, 120 | 114, 121 | 95, 122 | 101, 123 | 124, 124 | 198, 125 | 197, 126 | 239, 127 | 0, 128 | ] 129 | -------------------------------------------------------------------------------- /common/guestchain/src/snapshots/guestchain__block__block-header.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: common/blockchain/src/block.rs 3 | expression: check(&block.header) 4 | --- 5 | [ 6 | 0, 7 | 126, 8 | 90, 9 | 201, 10 | 10, 11 | 178, 12 | 207, 13 | 85, 14 | 189, 15 | 80, 16 | 13, 17 | 163, 18 | 112, 19 | 235, 20 | 105, 21 | 78, 22 | 143, 23 | 188, 24 | 233, 25 | 155, 26 | 153, 27 | 248, 28 | 202, 29 | 172, 30 | 56, 31 | 15, 32 | 114, 33 | 95, 34 | 101, 35 | 124, 36 | 198, 37 | 197, 38 | 239, 39 | 1, 40 | 0, 41 | 0, 42 | 0, 43 | 0, 44 | 0, 45 | 0, 46 | 0, 47 | 50, 48 | 0, 49 | 0, 50 | 0, 51 | 0, 52 | 0, 53 | 0, 54 | 0, 55 | 50, 56 | 0, 57 | 0, 58 | 0, 59 | 0, 60 | 0, 61 | 0, 62 | 0, 63 | 0, 64 | 0, 65 | 0, 66 | 99, 67 | 0, 68 | 0, 69 | 0, 70 | 99, 71 | 0, 72 | 0, 73 | 0, 74 | 99, 75 | 0, 76 | 0, 77 | 0, 78 | 99, 79 | 0, 80 | 0, 81 | 0, 82 | 99, 83 | 0, 84 | 0, 85 | 0, 86 | 99, 87 | 0, 88 | 0, 89 | 0, 90 | 99, 91 | 0, 92 | 0, 93 | 0, 94 | 99, 95 | 126, 96 | 90, 97 | 201, 98 | 10, 99 | 178, 100 | 207, 101 | 85, 102 | 189, 103 | 80, 104 | 13, 105 | 163, 106 | 112, 107 | 235, 108 | 105, 109 | 78, 110 | 143, 111 | 188, 112 | 233, 113 | 155, 114 | 153, 115 | 248, 116 | 202, 117 | 172, 118 | 56, 119 | 15, 120 | 114, 121 | 95, 122 | 101, 123 | 124, 124 | 198, 125 | 197, 126 | 239, 127 | 0, 128 | ] 129 | -------------------------------------------------------------------------------- /common/cf-solana/proto/solana.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package lightclients.solana.v1; 4 | 5 | // The consensus state of the Solana blockchain. 6 | message ConsensusState { 7 | // 32-byte root of the Merkle trie. 8 | bytes trie_root = 1; 9 | // Timestamp in seconds. Never zero. 10 | uint64 timestamp_sec = 2; 11 | 12 | // NEXT ID: 3 13 | } 14 | 15 | // The client state of the light client for the guest blockchain. 16 | message ClientState { 17 | // Latest rooted slot. 18 | uint64 latest_slot = 1; 19 | 20 | // Address of the witness account which holds trie commitment root. 21 | bytes witness_account = 2; 22 | 23 | // Duration of the period since the last timestamp during which the 24 | // submitted headers are valid for upgrade. 25 | uint64 trusting_period_ns = 3; 26 | 27 | // Whether client is frozen. 28 | bool is_frozen = 4; 29 | 30 | // NEXT ID: 5 31 | } 32 | 33 | message ClientMessage { 34 | oneof message { 35 | Header header = 1; 36 | Misbehaviour misbehaviour = 2; 37 | } 38 | 39 | // NEXT ID: 3 40 | } 41 | 42 | message Header { 43 | // Slot number. 44 | uint64 slot = 1; 45 | 46 | // 32-byte bank hash. 47 | bytes bank_hash = 2; 48 | 49 | // Accounts delta hsah proof. This is serialised DeltaHashProof struct. 50 | bytes delta_hash_proof = 3; 51 | 52 | // Hash data of the witness account. This is AccountHashData struct. 53 | bytes account_hash_data = 4; 54 | 55 | // Merkle proof of the witness account. This is serialised MerkleProof 56 | // struct. 57 | bytes account_merkle_proof = 5; 58 | 59 | // NEXT ID: 6 60 | } 61 | 62 | message Misbehaviour { 63 | // First header. 64 | Header header1 = 1; 65 | 66 | // Second header. 67 | // 68 | // Note that any field missing in `header2` will be copied from 69 | // `header1`. This allows identical values to be deduplicated. 70 | Header header2 = 2; 71 | 72 | // NEXT ID: 3 73 | } 74 | -------------------------------------------------------------------------------- /solana/signature-verifier/src/snapshots/sigverify__ed25519_program__test__single_signature__new_instruction_snapshot.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: solana/signature-verifier/src/ed25519_program.rs 3 | expression: data.as_slice() 4 | --- 5 | [ 6 | 1, 7 | 0, 8 | 23, 9 | 0, 10 | 255, 11 | 255, 12 | 87, 13 | 0, 14 | 255, 15 | 255, 16 | 16, 17 | 0, 18 | 7, 19 | 0, 20 | 255, 21 | 255, 22 | 109, 23 | 101, 24 | 115, 25 | 115, 26 | 97, 27 | 103, 28 | 101, 29 | 223, 30 | 236, 31 | 81, 32 | 97, 33 | 178, 34 | 101, 35 | 43, 36 | 11, 37 | 86, 38 | 133, 39 | 68, 40 | 49, 41 | 8, 42 | 69, 43 | 30, 44 | 93, 45 | 177, 46 | 43, 47 | 93, 48 | 145, 49 | 253, 50 | 208, 51 | 52, 52 | 161, 53 | 177, 54 | 117, 55 | 161, 56 | 67, 57 | 24, 58 | 139, 59 | 249, 60 | 253, 61 | 156, 62 | 131, 63 | 182, 64 | 122, 65 | 246, 66 | 36, 67 | 24, 68 | 64, 69 | 106, 70 | 235, 71 | 202, 72 | 49, 73 | 204, 74 | 47, 75 | 41, 76 | 15, 77 | 237, 78 | 153, 79 | 62, 80 | 236, 81 | 1, 82 | 214, 83 | 12, 84 | 146, 85 | 251, 86 | 18, 87 | 5, 88 | 221, 89 | 202, 90 | 213, 91 | 35, 92 | 15, 93 | 18, 94 | 10, 95 | 242, 96 | 85, 97 | 239, 98 | 109, 99 | 138, 100 | 32, 101 | 37, 102 | 117, 103 | 17, 104 | 6, 105 | 184, 106 | 125, 107 | 216, 108 | 16, 109 | 222, 110 | 201, 111 | 241, 112 | 41, 113 | 225, 114 | 95, 115 | 171, 116 | 115, 117 | 85, 118 | 114, 119 | 249, 120 | 152, 121 | 205, 122 | 71, 123 | 25, 124 | 89, 125 | ] 126 | -------------------------------------------------------------------------------- /common/guestchain/src/ibc_state.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::unit_arg, clippy::comparison_chain)] 2 | #![no_std] 3 | extern crate alloc; 4 | #[cfg(any(feature = "std", test))] 5 | extern crate std; 6 | 7 | use alloc::string::ToString; 8 | 9 | use ibc_proto::google::protobuf::Any; 10 | 11 | mod client; 12 | mod client_impls; 13 | mod consensus; 14 | mod header; 15 | mod misbehaviour; 16 | pub mod proof; 17 | pub mod proto; 18 | 19 | pub use client::ClientState; 20 | pub use client_impls::CommonContext; 21 | pub use consensus::ConsensusState; 22 | pub use header::Header; 23 | pub use misbehaviour::Misbehaviour; 24 | pub use proof::IbcProof; 25 | 26 | /// Client type of the guest blockchain’s light client. 27 | pub const CLIENT_TYPE: &str = "cf-guest"; 28 | 29 | pub use crate::proto::{BadMessage, DecodeError}; 30 | 31 | impl From for ibc_core_client_context::types::error::ClientError { 32 | fn from(err: DecodeError) -> Self { 33 | Self::ClientSpecific { description: err.to_string() } 34 | } 35 | } 36 | 37 | impl From for ibc_core_client_context::types::error::ClientError { 38 | fn from(_: BadMessage) -> Self { 39 | Self::ClientSpecific { description: "BadMessage".to_string() } 40 | } 41 | } 42 | 43 | /// Returns digest of the value with client id mixed in. 44 | /// 45 | /// We don’t store full client id in the trie key for paths which include 46 | /// client id. To avoid accepting malicious proofs, we must include it in 47 | /// some other way. We do this by mixing in the client id into the hash of 48 | /// the value stored at the path. 49 | /// 50 | /// Specifically, this calculates `digest(client_id || b'0' || serialised)`. 51 | #[inline] 52 | pub fn digest_with_client_id( 53 | client_id: &ibc_core_host::types::identifiers::ClientId, 54 | value: &[u8], 55 | ) -> lib::hash::CryptoHash { 56 | lib::hash::CryptoHash::digestv(&[client_id.as_bytes(), b"\0", value]) 57 | } 58 | -------------------------------------------------------------------------------- /common/cf-guest/src/misbehaviour.rs: -------------------------------------------------------------------------------- 1 | use guestchain::PubKey; 2 | 3 | use crate::{proto, Header}; 4 | 5 | #[derive(Clone, Debug, PartialEq, Eq)] 6 | pub struct Misbehaviour { 7 | pub header1: Header, 8 | pub header2: Header, 9 | } 10 | 11 | impl From> for proto::Misbehaviour { 12 | fn from(msg: Misbehaviour) -> Self { Self::from(&msg) } 13 | } 14 | 15 | impl From<&Misbehaviour> for proto::Misbehaviour { 16 | fn from(msg: &Misbehaviour) -> Self { 17 | let header1 = proto::Header::from(&msg.header1); 18 | let mut header2 = proto::Header::from(&msg.header2); 19 | if header1.genesis_hash == header2.genesis_hash { 20 | header2.genesis_hash.clear(); 21 | } 22 | if header1.epoch == header2.epoch { 23 | header2.epoch.clear() 24 | } 25 | 26 | Self { header1: Some(header1), header2: Some(header2) } 27 | } 28 | } 29 | 30 | impl TryFrom for Misbehaviour { 31 | type Error = proto::BadMessage; 32 | fn try_from(msg: proto::Misbehaviour) -> Result { 33 | Self::try_from(&msg) 34 | } 35 | } 36 | 37 | impl TryFrom<&proto::Misbehaviour> for Misbehaviour { 38 | type Error = proto::BadMessage; 39 | fn try_from(msg: &proto::Misbehaviour) -> Result { 40 | let header1 = 41 | msg.header1.as_ref().ok_or(proto::BadMessage)?.try_into()?; 42 | let header2 = Header::try_from_proto_inherit( 43 | msg.header2.as_ref().ok_or(proto::BadMessage)?, 44 | &header1, 45 | )?; 46 | 47 | Ok(Self { header1, header2 }) 48 | } 49 | } 50 | 51 | proto_utils::define_wrapper! { 52 | proto: proto::Misbehaviour, 53 | wrapper: Misbehaviour where 54 | PK: guestchain::PubKey = guestchain::validators::MockPubKey, 55 | } 56 | -------------------------------------------------------------------------------- /common/cf-solana/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cf-solana" 3 | authors = ["Michal Nazarewicz "] 4 | version = "0.0.0" 5 | edition = "2021" 6 | 7 | [dependencies] 8 | arrayvec.workspace = true 9 | blake3.workspace = true 10 | bs58.workspace = true 11 | base64.workspace = true 12 | bytemuck.workspace = true 13 | derive_more.workspace = true 14 | ibc-client-tendermint-types.workspace = true 15 | ibc-core-client-context.workspace = true 16 | ibc-core-commitment-types.workspace = true 17 | ibc-core-host.workspace = true 18 | ibc-primitives.workspace = true 19 | ibc-proto.workspace = true 20 | prost = { workspace = true, features = ["prost-derive"] } 21 | serde = { workspace = true, optional = true } 22 | solana-program = { workspace = true, optional = true } 23 | 24 | cf-guest.workspace = true 25 | lib = { workspace = true, features = ["bs58"] } 26 | proto-utils = { workspace = true, features = ["ibc"] } 27 | stdx.workspace = true 28 | trie-ids.workspace = true 29 | 30 | solana-program-2 = { package = "solana-program", git = "https://github.com/ComposableFi/mantis-solana.git", branch = "mantis/dev", optional = true } 31 | 32 | [build-dependencies] 33 | prost-build.workspace = true 34 | 35 | [dev-dependencies] 36 | insta.workspace = true 37 | rand.workspace = true 38 | rand_chacha.workspace = true 39 | 40 | solana-accounts-db2 = { package = "solana-accounts-db", git = "https://github.com/ComposableFi/mantis-solana.git", branch = "mantis/dev" } 41 | solana-program-2 = { package = "solana-program", git = "https://github.com/ComposableFi/mantis-solana.git", branch = "mantis/dev" } 42 | 43 | lib = { workspace = true, features = ["test_utils"] } 44 | 45 | [features] 46 | no-blake3-syscall = [] 47 | rayon = ["lib/rayon"] 48 | serde = [ 49 | "dep:serde", 50 | "lib/serde", 51 | ] 52 | solana-program = [ 53 | "dep:solana-program", 54 | "lib/solana-program", 55 | ] 56 | solana-program-2 = [ 57 | "dep:solana-program-2", 58 | ] 59 | -------------------------------------------------------------------------------- /solana/allocator/src/ptr.rs: -------------------------------------------------------------------------------- 1 | //! Helper functions for pointer arithmetic. 2 | 3 | /// Creates a new pointer with the given address. 4 | // TODO(mina86): Use ptr.with_addr once strict_provenance stabilises. 5 | pub(super) fn with_addr(ptr: *mut u8, addr: usize) -> *mut u8 { 6 | ptr.wrapping_add(addr.wrapping_sub(ptr as usize)) 7 | } 8 | 9 | /// Aligns pointer to given alignment which must be a power of two. 10 | /// 11 | /// If `align` isn’t a power of two, result is unspecified. 12 | pub(super) fn align(ptr: *mut u8, align: usize) -> *mut u8 { 13 | let mask = align - 1; 14 | debug_assert!(align != 0 && align & mask == 0); 15 | // TODO(mina86): Use ptr.map_addr once strict_provenance stabilises. 16 | with_addr(ptr, ptr.wrapping_add(mask) as usize & !mask) 17 | } 18 | 19 | /// Returns end address of given object. 20 | pub(super) fn end_addr_of_val(obj: &T) -> usize { 21 | (obj as *const T).wrapping_add(1) as usize 22 | } 23 | 24 | /// Returns a range of pointers of given size. 25 | pub(super) fn range(start: *mut u8, size: usize) -> core::ops::Range<*mut u8> { 26 | start..start.wrapping_add(size) 27 | } 28 | 29 | 30 | /// Copies `size` bytes from `src` to `dst`. 31 | /// 32 | /// # Safety 33 | /// 34 | /// Caller must guarantees all of the conditions required by 35 | /// [`core::ptr::copy_nonoverlapping`]. 36 | pub(super) unsafe fn memcpy(dst: *mut u8, src: *const u8, size: usize) { 37 | if cfg!(debug_assertions) { 38 | assert_no_overlap(dst, size, src, size); 39 | } 40 | // SAFETY: Caller guarantees all necessary conditions. 41 | unsafe { core::ptr::copy_nonoverlapping(src, dst, size) } 42 | } 43 | 44 | #[track_caller] 45 | pub(super) fn assert_no_overlap( 46 | a: *const u8, 47 | a_size: usize, 48 | b: *const u8, 49 | b_size: usize, 50 | ) { 51 | let a = range(a as *mut u8, a_size); 52 | let b = range(b as *mut u8, b_size); 53 | assert!( 54 | !a.contains(&b.start) && !a.contains(&b.end), 55 | "{a:?} and {b:?} overlap", 56 | ) 57 | } 58 | -------------------------------------------------------------------------------- /solana/solana-ibc/programs/solana-ibc/src/snapshots/solana_ibc__events__snapshot_tests__borsh_block_signed.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: solana/solana-ibc/programs/solana-ibc/src/events.rs 3 | expression: serialised 4 | --- 5 | [ 6 | 3, 7 | 0, 8 | 0, 9 | 0, 10 | 42, 11 | 0, 12 | 0, 13 | 0, 14 | 42, 15 | 0, 16 | 0, 17 | 0, 18 | 42, 19 | 0, 20 | 0, 21 | 0, 22 | 42, 23 | 0, 24 | 0, 25 | 0, 26 | 42, 27 | 0, 28 | 0, 29 | 0, 30 | 42, 31 | 0, 32 | 0, 33 | 0, 34 | 42, 35 | 0, 36 | 0, 37 | 0, 38 | 42, 39 | 164, 40 | 1, 41 | 0, 42 | 0, 43 | 0, 44 | 0, 45 | 0, 46 | 0, 47 | 0, 48 | 0, 49 | 0, 50 | 24, 51 | 0, 52 | 0, 53 | 0, 54 | 24, 55 | 0, 56 | 0, 57 | 0, 58 | 24, 59 | 0, 60 | 0, 61 | 0, 62 | 24, 63 | 0, 64 | 0, 65 | 0, 66 | 24, 67 | 0, 68 | 0, 69 | 0, 70 | 24, 71 | 0, 72 | 0, 73 | 0, 74 | 24, 75 | 0, 76 | 0, 77 | 0, 78 | 24, 79 | 69, 80 | 69, 81 | 69, 82 | 69, 83 | 69, 84 | 69, 85 | 69, 86 | 69, 87 | 69, 88 | 69, 89 | 69, 90 | 69, 91 | 69, 92 | 69, 93 | 69, 94 | 69, 95 | 69, 96 | 69, 97 | 69, 98 | 69, 99 | 69, 100 | 69, 101 | 69, 102 | 69, 103 | 69, 104 | 69, 105 | 69, 106 | 69, 107 | 69, 108 | 69, 109 | 69, 110 | 69, 111 | 69, 112 | 69, 113 | 69, 114 | 69, 115 | 69, 116 | 69, 117 | 69, 118 | 69, 119 | 69, 120 | 69, 121 | 69, 122 | 69, 123 | 69, 124 | 69, 125 | 69, 126 | 69, 127 | 69, 128 | 69, 129 | 69, 130 | 69, 131 | 69, 132 | 69, 133 | 69, 134 | 69, 135 | 69, 136 | 69, 137 | 69, 138 | 69, 139 | 69, 140 | 69, 141 | 69, 142 | 69, 143 | ] 144 | -------------------------------------------------------------------------------- /solana/restaking/querying.md: -------------------------------------------------------------------------------- 1 | # Querying the Smart contract on Client side 2 | 3 | Here are the steps required to query the smart contract in the 4 | frontend 5 | 6 | 1. Set up the program. You would need the `IDL` and the program ID. 7 | Program ID can be found in the `Anchor.toml` and should be 8 | a `PublicKey`. The IDL can be found by running `anchor build` in 9 | the current contract. It would be present in 10 | `target/types/restaking.ts`. 11 | 12 | ```ts 13 | import * as anchor from "@coral-xyz/anchor"; 14 | import IDL from 'restaking.ts'; 15 | 16 | // Example 17 | const restakingProgramId = 18 | new PublicKey("8n3FHwYxFgQCQc2FNFkwDUf9mcqupxXcCvgfHbApMLv3") 19 | const provider = new anchor.AnchorProvider(connection, window?.solana, { 20 | preflightCommitment: 'processed' 21 | }); 22 | const program = new Program(IDL, restakingProgramId, provider); 23 | ``` 24 | 25 | 2. Once the program is set, get the account from the seeds and pass it 26 | to the RPC. Refer how to get the accounts in `tests/helpers.ts`. 27 | 28 | ```ts 29 | // Example 30 | let stakeParameters = 31 | await program.account.stake.fetch(stakingParamsPDA) 32 | ``` 33 | 34 | ## Account Structure 35 | 36 | We have 2 storage accounts 37 | 1. **StakingParams**: `StakingParams` contains the paramters required 38 | for staking. They are as follows. 39 | - Whitelisted Tokens: The tokens which can be staked. 40 | - Guest chain Program Id: If `None` or `null`, it means that the guest 41 | chain is not initialized yet. 42 | - rewards token mint: The token mint which would be used to distribute 43 | the rewards 44 | - staking cap: The maximum amount of staking allowed. 45 | - total deposited amount: The TVL in the contract. 46 | 47 | 2. **Vault**: `Vault` contains the details of the stake. They are as 48 | follows 49 | - stake mint: The token mint of the staked tokens 50 | - stake amount: Amount of tokens which were staked 51 | - service: The validator to which the stake was delegated to. 52 | - last_received_rewards_height: The last epoch height at which rewards 53 | were claimed. 54 | -------------------------------------------------------------------------------- /common/cf-solana/src/misbehaviour.rs: -------------------------------------------------------------------------------- 1 | use crate::{proto, Header}; 2 | 3 | #[derive(Clone, Debug, PartialEq, Eq)] 4 | pub struct Misbehaviour { 5 | pub header1: Header, 6 | pub header2: Header, 7 | } 8 | 9 | impl From for proto::Misbehaviour { 10 | fn from(msg: Misbehaviour) -> Self { 11 | let header1 = proto::Header::from(msg.header1); 12 | let header2 = proto::Header::from(msg.header2); 13 | Self::new(header1, header2) 14 | } 15 | } 16 | 17 | impl From<&Misbehaviour> for proto::Misbehaviour { 18 | fn from(msg: &Misbehaviour) -> Self { 19 | let header1 = proto::Header::from(&msg.header1); 20 | let header2 = proto::Header::from(&msg.header2); 21 | Self::new(header1, header2) 22 | } 23 | } 24 | 25 | impl TryFrom for Misbehaviour { 26 | type Error = proto::BadMessage; 27 | fn try_from(msg: proto::Misbehaviour) -> Result { 28 | let header1 = msg.header1.ok_or(proto::BadMessage)?; 29 | let mut header2 = msg.header2.ok_or(proto::BadMessage)?; 30 | let account_hash_data = core::mem::take(&mut header2.account_hash_data); 31 | 32 | let header2 = Header::try_from_proto( 33 | &header2, 34 | Some(account_hash_data), 35 | Some(&header1), 36 | )?; 37 | let header1 = Header::try_from(header1)?; 38 | Ok(Self { header1, header2 }) 39 | } 40 | } 41 | 42 | impl TryFrom<&proto::Misbehaviour> for Misbehaviour { 43 | type Error = proto::BadMessage; 44 | fn try_from(msg: &proto::Misbehaviour) -> Result { 45 | let header1 = msg.header1.as_ref().ok_or(proto::BadMessage)?; 46 | let header2 = msg.header2.as_ref().ok_or(proto::BadMessage)?; 47 | let header2 = Header::try_from_proto(header2, None, Some(header1))?; 48 | let header1 = Header::try_from(header1)?; 49 | Ok(Self { header1, header2 }) 50 | } 51 | } 52 | 53 | proto_utils::define_wrapper! { 54 | proto: proto::Misbehaviour, 55 | wrapper: Misbehaviour, 56 | } 57 | -------------------------------------------------------------------------------- /common/wasm/src/consensus_state.rs: -------------------------------------------------------------------------------- 1 | use ibc_primitives::proto::Any; 2 | use ibc_proto::Protobuf; 3 | 4 | use crate::proto; 5 | 6 | #[derive(Clone, Debug, PartialEq, Eq)] 7 | pub struct ConsensusState { 8 | pub data: Vec, 9 | pub timestamp_ns: u64, 10 | } 11 | 12 | impl ConsensusState { 13 | pub fn new(data: Vec, timestamp_ns: u64) -> Self { 14 | Self { data, timestamp_ns } 15 | } 16 | } 17 | 18 | impl ibc_core_client_context::consensus_state::ConsensusState 19 | for ConsensusState 20 | { 21 | fn root(&self) -> &ibc_core_commitment_types::commitment::CommitmentRoot { 22 | todo!() 23 | } 24 | 25 | fn timestamp(&self) -> ibc_primitives::Timestamp { 26 | ibc_primitives::Timestamp::from_nanoseconds(self.timestamp_ns).unwrap() 27 | } 28 | 29 | fn encode_vec(self) -> alloc::vec::Vec { 30 | >::encode_vec(self) 31 | } 32 | } 33 | 34 | impl Protobuf for ConsensusState {} 35 | 36 | impl From for proto::ConsensusState { 37 | fn from(state: ConsensusState) -> Self { 38 | Self { data: state.data, timestamp_ns: state.timestamp_ns } 39 | } 40 | } 41 | 42 | impl From<&ConsensusState> for proto::ConsensusState { 43 | fn from(state: &ConsensusState) -> Self { Self::from(state.clone()) } 44 | } 45 | 46 | impl TryFrom for ConsensusState { 47 | type Error = proto::BadMessage; 48 | fn try_from(msg: proto::ConsensusState) -> Result { 49 | Ok(ConsensusState { data: msg.data, timestamp_ns: msg.timestamp_ns }) 50 | } 51 | } 52 | 53 | impl TryFrom<&proto::ConsensusState> for ConsensusState { 54 | type Error = proto::BadMessage; 55 | fn try_from(msg: &proto::ConsensusState) -> Result { 56 | Ok(ConsensusState { 57 | data: as Clone>::clone(&msg.data), 58 | timestamp_ns: msg.timestamp_ns, 59 | }) 60 | } 61 | } 62 | 63 | proto_utils::define_wrapper! { 64 | proto: proto::ConsensusState, 65 | wrapper: ConsensusState, 66 | } 67 | -------------------------------------------------------------------------------- /solana/solana-ibc/programs/solana-ibc/src/storage/map.rs: -------------------------------------------------------------------------------- 1 | use core::fmt; 2 | 3 | use anchor_lang::prelude::borsh; 4 | use anchor_lang::prelude::borsh::maybestd::io; 5 | 6 | /// A mapping using an unsorted vector as backing storage. 7 | /// 8 | /// Lookup operations on the map take linear time but for small maps that might 9 | /// actually be faster than hash maps or B trees. 10 | #[derive(Clone, derive_more::Deref, derive_more::DerefMut)] 11 | pub struct Map(linear_map::LinearMap); 12 | 13 | impl Default for Map { 14 | fn default() -> Self { Self(Default::default()) } 15 | } 16 | 17 | impl fmt::Debug for Map { 18 | fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result { 19 | fmtr.debug_map().entries(&self.0).finish() 20 | } 21 | } 22 | 23 | impl From> for Map { 24 | fn from(entries: Vec<(K, V)>) -> Self { Self(entries.into()) } 25 | } 26 | 27 | impl From> for Vec<(K, V)> { 28 | fn from(map: Map) -> Self { Self::from(map.0) } 29 | } 30 | 31 | impl borsh::BorshSerialize for Map 32 | where 33 | K: borsh::BorshSerialize, 34 | V: borsh::BorshSerialize, 35 | { 36 | fn serialize(&self, wr: &mut W) -> io::Result<()> { 37 | // LinearMap doesn’t offer as_slice function so we need to encode it by 38 | // ourselves. 39 | u32::try_from(self.len()).unwrap().serialize(wr)?; 40 | for pair in self.iter() { 41 | pair.serialize(wr)?; 42 | } 43 | Ok(()) 44 | } 45 | } 46 | 47 | impl borsh::BorshDeserialize for Map 48 | where 49 | K: borsh::BorshDeserialize, 50 | V: borsh::BorshDeserialize, 51 | { 52 | /// Deserialises the map from a vector of `(K, V)` pairs. 53 | /// 54 | /// **Note**: No checking for duplicates is performed. Malicious value may 55 | /// lead to a map with duplicate keys. 56 | fn deserialize_reader(rd: &mut R) -> io::Result { 57 | Vec::<(K, V)>::deserialize_reader(rd).map(|vec| Self(vec.into())) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /solana/trie-geyser-plugin/src/config.rs: -------------------------------------------------------------------------------- 1 | use cf_solana::types::PubKey; 2 | use solana_geyser_plugin_interface::geyser_plugin_interface; 3 | use solana_sdk::pubkey::Pubkey; 4 | 5 | #[derive(Debug, Clone, serde::Deserialize)] 6 | #[serde(deny_unknown_fields)] 7 | struct FileConfig { 8 | #[serde(rename = "libpath")] 9 | _libpath: String, 10 | trie_program: PubKey, 11 | root_account: PubKey, 12 | bind_address: std::net::SocketAddr, 13 | } 14 | 15 | #[derive(Debug, Clone)] 16 | pub struct Config { 17 | pub root_account: Pubkey, 18 | pub witness_account: Pubkey, 19 | pub bind_address: std::net::SocketAddr, 20 | } 21 | 22 | #[derive(Debug, derive_more::From, derive_more::Display)] 23 | pub enum Error { 24 | IO(std::io::Error), 25 | Parse(serde_json::Error), 26 | #[display( 27 | fmt = "Unable to find witness account for trie {} owned by {}", 28 | root_account, 29 | trie_program 30 | )] 31 | UnableToFindWitnessAccount { 32 | trie_program: Pubkey, 33 | root_account: Pubkey, 34 | }, 35 | } 36 | 37 | impl Config { 38 | /// Loads configuration from a file. 39 | pub fn load(file: &std::path::Path) -> Result { 40 | let cfg: FileConfig = 41 | serde_json::from_reader(std::fs::File::open(file)?)?; 42 | let trie_program = Pubkey::from(cfg.trie_program); 43 | let root_account = Pubkey::from(cfg.root_account); 44 | let bind_address = cfg.bind_address; 45 | let (witness_account, _) = 46 | wittrie::api::find_witness_account(&trie_program, &root_account) 47 | .ok_or_else(|| Error::UnableToFindWitnessAccount { 48 | trie_program, 49 | root_account, 50 | })?; 51 | Ok(Self { root_account, witness_account, bind_address }) 52 | } 53 | } 54 | 55 | impl From for geyser_plugin_interface::GeyserPluginError { 56 | fn from(err: Error) -> Self { 57 | match err { 58 | Error::IO(err) => err.into(), 59 | err => Self::ConfigFileReadError { msg: err.to_string() }, 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /common/cf-guest/src/proto.rs: -------------------------------------------------------------------------------- 1 | pub use proto_utils::{Any, AnyConvert, BadMessage, DecodeError}; 2 | 3 | mod pb { 4 | include!(concat!(env!("OUT_DIR"), "/messages.rs")); 5 | } 6 | 7 | pub use pb::lightclients::guest::v1::client_message; 8 | 9 | macro_rules! define_proto { 10 | ($Msg:ident; $test:ident; $test_object:expr) => { 11 | proto_utils::define_message! { 12 | pub use pb::lightclients::guest::v1::$Msg as $Msg; 13 | $test $test_object; 14 | } 15 | }; 16 | } 17 | 18 | define_proto!(ClientState; test_client_state; Self { 19 | genesis_hash: lib::hash::CryptoHash::test(24).to_vec(), 20 | latest_height: 8, 21 | epoch_commitment: lib::hash::CryptoHash::test(11).to_vec(), 22 | prev_epoch_commitment: lib::hash::CryptoHash::test(12).to_vec(), 23 | is_frozen: false, 24 | trusting_period_ns: 30 * 24 * 3600 * 1_000_000_000, 25 | }); 26 | 27 | define_proto!(ConsensusState; test_consensus_state; { 28 | let block_hash = lib::hash::CryptoHash::test(42).to_vec(); 29 | Self { block_hash, timestamp_ns: 1 } 30 | }); 31 | 32 | define_proto!(ClientMessage; test_client_message; Header::test().into()); 33 | 34 | define_proto!(Header; test_header; { 35 | // TODO(mina86): Construct a proper signed header. 36 | Self { 37 | genesis_hash: alloc::vec![0; 32], 38 | block_header: alloc::vec![1; 10], 39 | epoch: alloc::vec![2; 10], 40 | signatures: alloc::vec![], 41 | } 42 | }); 43 | 44 | define_proto!(Signature; test_signature; Self { 45 | index: 1, 46 | signature: alloc::vec![0; 64], 47 | }); 48 | 49 | define_proto!(Misbehaviour; test_misbehaviour; Self { 50 | header1: Some(Header::test()), 51 | header2: Some(Header::test()), 52 | }); 53 | 54 | impl From
for ClientMessage { 55 | #[inline] 56 | fn from(msg: Header) -> Self { 57 | Self { message: Some(client_message::Message::Header(msg)) } 58 | } 59 | } 60 | 61 | impl From for ClientMessage { 62 | #[inline] 63 | fn from(msg: Misbehaviour) -> Self { 64 | Self { message: Some(client_message::Message::Misbehaviour(msg)) } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /common/guestchain/src/snapshots/guestchain__block__genesis-header.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: common/blockchain/src/block.rs 3 | expression: check(&genesis.header) 4 | --- 5 | [ 6 | 0, 7 | 0, 8 | 0, 9 | 0, 10 | 0, 11 | 0, 12 | 0, 13 | 0, 14 | 0, 15 | 0, 16 | 0, 17 | 0, 18 | 0, 19 | 0, 20 | 0, 21 | 0, 22 | 0, 23 | 0, 24 | 0, 25 | 0, 26 | 0, 27 | 0, 28 | 0, 29 | 0, 30 | 0, 31 | 0, 32 | 0, 33 | 0, 34 | 0, 35 | 0, 36 | 0, 37 | 0, 38 | 0, 39 | 0, 40 | 0, 41 | 0, 42 | 0, 43 | 0, 44 | 0, 45 | 0, 46 | 0, 47 | 42, 48 | 0, 49 | 0, 50 | 0, 51 | 0, 52 | 0, 53 | 0, 54 | 0, 55 | 24, 56 | 0, 57 | 0, 58 | 0, 59 | 0, 60 | 0, 61 | 0, 62 | 0, 63 | 0, 64 | 0, 65 | 0, 66 | 66, 67 | 0, 68 | 0, 69 | 0, 70 | 66, 71 | 0, 72 | 0, 73 | 0, 74 | 66, 75 | 0, 76 | 0, 77 | 0, 78 | 66, 79 | 0, 80 | 0, 81 | 0, 82 | 66, 83 | 0, 84 | 0, 85 | 0, 86 | 66, 87 | 0, 88 | 0, 89 | 0, 90 | 66, 91 | 0, 92 | 0, 93 | 0, 94 | 66, 95 | 0, 96 | 0, 97 | 0, 98 | 0, 99 | 0, 100 | 0, 101 | 0, 102 | 0, 103 | 0, 104 | 0, 105 | 0, 106 | 0, 107 | 0, 108 | 0, 109 | 0, 110 | 0, 111 | 0, 112 | 0, 113 | 0, 114 | 0, 115 | 0, 116 | 0, 117 | 0, 118 | 0, 119 | 0, 120 | 0, 121 | 0, 122 | 0, 123 | 0, 124 | 0, 125 | 0, 126 | 0, 127 | 1, 128 | 196, 129 | 47, 130 | 231, 131 | 100, 132 | 180, 133 | 107, 134 | 167, 135 | 158, 136 | 100, 137 | 227, 138 | 158, 139 | 6, 140 | 166, 141 | 177, 142 | 90, 143 | 160, 144 | 94, 145 | 56, 146 | 115, 147 | 222, 148 | 167, 149 | 197, 150 | 60, 151 | 16, 152 | 240, 153 | 81, 154 | 39, 155 | 213, 156 | 86, 157 | 193, 158 | 217, 159 | 50, 160 | ] 161 | -------------------------------------------------------------------------------- /solana/solana-ibc/programs/solana-ibc/src/snapshots/solana_ibc__events__snapshot_tests__borsh_initialised.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: solana/solana-ibc/programs/solana-ibc/src/events.rs 3 | expression: serialised 4 | --- 5 | [ 6 | 1, 7 | 0, 8 | 0, 9 | 0, 10 | 0, 11 | 0, 12 | 0, 13 | 0, 14 | 0, 15 | 0, 16 | 0, 17 | 0, 18 | 0, 19 | 0, 20 | 0, 21 | 0, 22 | 0, 23 | 0, 24 | 0, 25 | 0, 26 | 0, 27 | 0, 28 | 0, 29 | 0, 30 | 0, 31 | 0, 32 | 0, 33 | 0, 34 | 0, 35 | 0, 36 | 0, 37 | 0, 38 | 0, 39 | 0, 40 | 0, 41 | 0, 42 | 0, 43 | 0, 44 | 0, 45 | 0, 46 | 0, 47 | 0, 48 | 42, 49 | 0, 50 | 0, 51 | 0, 52 | 0, 53 | 0, 54 | 0, 55 | 0, 56 | 24, 57 | 0, 58 | 0, 59 | 0, 60 | 0, 61 | 0, 62 | 0, 63 | 0, 64 | 0, 65 | 0, 66 | 0, 67 | 66, 68 | 0, 69 | 0, 70 | 0, 71 | 66, 72 | 0, 73 | 0, 74 | 0, 75 | 66, 76 | 0, 77 | 0, 78 | 0, 79 | 66, 80 | 0, 81 | 0, 82 | 0, 83 | 66, 84 | 0, 85 | 0, 86 | 0, 87 | 66, 88 | 0, 89 | 0, 90 | 0, 91 | 66, 92 | 0, 93 | 0, 94 | 0, 95 | 66, 96 | 0, 97 | 0, 98 | 0, 99 | 0, 100 | 0, 101 | 0, 102 | 0, 103 | 0, 104 | 0, 105 | 0, 106 | 0, 107 | 0, 108 | 0, 109 | 0, 110 | 0, 111 | 0, 112 | 0, 113 | 0, 114 | 0, 115 | 0, 116 | 0, 117 | 0, 118 | 0, 119 | 0, 120 | 0, 121 | 0, 122 | 0, 123 | 0, 124 | 0, 125 | 0, 126 | 0, 127 | 0, 128 | 1, 129 | 219, 130 | 192, 131 | 172, 132 | 39, 133 | 119, 134 | 107, 135 | 149, 136 | 47, 137 | 168, 138 | 161, 139 | 165, 140 | 238, 141 | 123, 142 | 171, 143 | 147, 144 | 83, 145 | 100, 146 | 62, 147 | 216, 148 | 182, 149 | 211, 150 | 163, 151 | 202, 152 | 167, 153 | 194, 154 | 157, 155 | 67, 156 | 41, 157 | 2, 158 | 87, 159 | 139, 160 | 43, 161 | ] 162 | -------------------------------------------------------------------------------- /solana/solana-ibc/programs/solana-ibc/src/snapshots/solana_ibc__events__snapshot_tests__borsh_new_block.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: solana/solana-ibc/programs/solana-ibc/src/events.rs 3 | expression: serialised 4 | --- 5 | [ 6 | 2, 7 | 0, 8 | 0, 9 | 0, 10 | 0, 11 | 0, 12 | 0, 13 | 0, 14 | 0, 15 | 0, 16 | 0, 17 | 0, 18 | 0, 19 | 0, 20 | 0, 21 | 0, 22 | 0, 23 | 0, 24 | 0, 25 | 0, 26 | 0, 27 | 0, 28 | 0, 29 | 0, 30 | 0, 31 | 0, 32 | 0, 33 | 0, 34 | 0, 35 | 0, 36 | 0, 37 | 0, 38 | 0, 39 | 0, 40 | 0, 41 | 0, 42 | 0, 43 | 0, 44 | 0, 45 | 0, 46 | 0, 47 | 0, 48 | 42, 49 | 0, 50 | 0, 51 | 0, 52 | 0, 53 | 0, 54 | 0, 55 | 0, 56 | 24, 57 | 0, 58 | 0, 59 | 0, 60 | 0, 61 | 0, 62 | 0, 63 | 0, 64 | 0, 65 | 0, 66 | 0, 67 | 66, 68 | 0, 69 | 0, 70 | 0, 71 | 66, 72 | 0, 73 | 0, 74 | 0, 75 | 66, 76 | 0, 77 | 0, 78 | 0, 79 | 66, 80 | 0, 81 | 0, 82 | 0, 83 | 66, 84 | 0, 85 | 0, 86 | 0, 87 | 66, 88 | 0, 89 | 0, 90 | 0, 91 | 66, 92 | 0, 93 | 0, 94 | 0, 95 | 66, 96 | 0, 97 | 0, 98 | 0, 99 | 0, 100 | 0, 101 | 0, 102 | 0, 103 | 0, 104 | 0, 105 | 0, 106 | 0, 107 | 0, 108 | 0, 109 | 0, 110 | 0, 111 | 0, 112 | 0, 113 | 0, 114 | 0, 115 | 0, 116 | 0, 117 | 0, 118 | 0, 119 | 0, 120 | 0, 121 | 0, 122 | 0, 123 | 0, 124 | 0, 125 | 0, 126 | 0, 127 | 0, 128 | 1, 129 | 219, 130 | 192, 131 | 172, 132 | 39, 133 | 119, 134 | 107, 135 | 149, 136 | 47, 137 | 168, 138 | 161, 139 | 165, 140 | 238, 141 | 123, 142 | 171, 143 | 147, 144 | 83, 145 | 100, 146 | 62, 147 | 216, 148 | 182, 149 | 211, 150 | 163, 151 | 202, 152 | 167, 153 | 194, 154 | 157, 155 | 67, 156 | 41, 157 | 2, 158 | 87, 159 | 139, 160 | 43, 161 | 0, 162 | ] 163 | -------------------------------------------------------------------------------- /solana/solana-ibc/tests/utils.ts: -------------------------------------------------------------------------------- 1 | import * as anchor from "@coral-xyz/anchor"; 2 | import * as spl from "@solana/spl-token"; 3 | import { BorshSchema, borshSerialize, borshDeserialize, Unit } from "borsher"; 4 | import { hash } from "@coral-xyz/anchor/dist/cjs/utils/sha256"; 5 | import { 6 | ComputeBudgetInstruction, 7 | ComputeBudgetProgram, 8 | Connection, 9 | SystemProgram, 10 | Transaction, 11 | TransactionInstruction, 12 | sendAndConfirmTransaction, 13 | } from "@solana/web3.js"; 14 | import bs58 from "bs58"; 15 | import { solanaIbcProgramId } from "./constants"; 16 | 17 | export function getInt64Bytes(x: number) { 18 | let y = Math.floor(x / 2 ** 32); 19 | return [y, y << 8, y << 16, y << 24, x, x << 8, x << 16, x << 24].map( 20 | (z) => z >>> 24 21 | ); 22 | } 23 | 24 | export function hexToBytes(hex: string) { 25 | let bytes = []; 26 | for (let c = 0; c < hex.length; c += 2) 27 | bytes.push(parseInt(hex.substr(c, 2), 16)); 28 | return bytes; 29 | } 30 | 31 | export const getGuestChainAccounts = (hashedDenom: number[]) => { 32 | const [guestChainPDA, guestChainBump] = 33 | anchor.web3.PublicKey.findProgramAddressSync( 34 | [Buffer.from("chain")], 35 | solanaIbcProgramId 36 | ); 37 | 38 | const [triePDA, trieBump] = anchor.web3.PublicKey.findProgramAddressSync( 39 | [Buffer.from("trie")], 40 | solanaIbcProgramId 41 | ); 42 | 43 | const [mintAuthorityPDA, mintAuthorityBump] = 44 | anchor.web3.PublicKey.findProgramAddressSync( 45 | [Buffer.from("mint_escrow")], 46 | solanaIbcProgramId 47 | ); 48 | 49 | const [ibcStoragePDA, ibcStorageBump] = 50 | anchor.web3.PublicKey.findProgramAddressSync( 51 | [Buffer.from("private")], 52 | solanaIbcProgramId 53 | ); 54 | 55 | const [escrowAccountPDA, escrowAccountBump] = 56 | anchor.web3.PublicKey.findProgramAddressSync( 57 | [ 58 | Buffer.from("escrow"), 59 | Buffer.from(hashedDenom), 60 | ], 61 | solanaIbcProgramId 62 | ); 63 | 64 | const [feePDA, feeBump] = 65 | anchor.web3.PublicKey.findProgramAddressSync( 66 | [ 67 | Buffer.from("fee"), 68 | ], 69 | solanaIbcProgramId 70 | ); 71 | 72 | return { guestChainPDA, triePDA, ibcStoragePDA, mintAuthorityPDA, escrowAccountPDA, feePDA }; 73 | }; -------------------------------------------------------------------------------- /common/cf-solana/src/proto.rs: -------------------------------------------------------------------------------- 1 | pub use proto_utils::{Any, AnyConvert, BadMessage, DecodeError}; 2 | 3 | mod pb { 4 | include!(concat!(env!("OUT_DIR"), "/messages.rs")); 5 | } 6 | 7 | pub use pb::lightclients::solana::v1::client_message; 8 | 9 | macro_rules! define_proto { 10 | ($Msg:ident; $test:ident; $test_object:expr) => { 11 | proto_utils::define_message! { 12 | pub use pb::lightclients::solana::v1::$Msg as $Msg; 13 | $test $test_object; 14 | } 15 | }; 16 | } 17 | 18 | define_proto!(ClientState; test_client_state; Self { 19 | latest_slot: 8, 20 | witness_account: alloc::vec![42; 32], 21 | trusting_period_ns: 30 * 24 * 3600 * 1_000_000_000, 22 | is_frozen: false, 23 | }); 24 | 25 | define_proto!(ConsensusState; test_consensus_state; Self { 26 | trie_root: lib::hash::CryptoHash::test(42).to_vec(), 27 | timestamp_sec: 1, 28 | }); 29 | 30 | define_proto!(ClientMessage; test_client_message; Header::test().into()); 31 | 32 | define_proto!(Header; test_header; crate::Header::test(b"").into()); 33 | 34 | define_proto!(Misbehaviour; test_misbehaviour; Self { 35 | header1: Some(Header::test()), 36 | header2: Some(Header::test()), 37 | }); 38 | 39 | impl From
for ClientMessage { 40 | #[inline] 41 | fn from(msg: Header) -> Self { 42 | Self { message: Some(client_message::Message::Header(msg)) } 43 | } 44 | } 45 | 46 | impl From for ClientMessage { 47 | #[inline] 48 | fn from(msg: Misbehaviour) -> Self { 49 | Self { message: Some(client_message::Message::Misbehaviour(msg)) } 50 | } 51 | } 52 | 53 | impl Misbehaviour { 54 | pub(crate) fn new(header1: Header, mut header2: Header) -> Misbehaviour { 55 | macro_rules! dedup { 56 | ($hdr1:ident, $hdr2:ident, $field:ident) => { 57 | if $hdr1.bank_hash == $hdr2.bank_hash { 58 | $hdr2.bank_hash.clear(); 59 | } 60 | }; 61 | } 62 | 63 | dedup!(header1, header2, bank_hash); 64 | dedup!(header1, header2, delta_hash_proof); 65 | dedup!(header1, header2, account_hash_data); 66 | dedup!(header1, header2, account_merkle_proof); 67 | 68 | Misbehaviour { header1: Some(header1), header2: Some(header2) } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "solana-trie-example", 3 | "version": "0.0.1", 4 | "author": "Michał Nazarewicz ", 5 | "scripts": { 6 | "start": "ts-node solana/trie-example/client/main.ts", 7 | "start-with-test-validator": "start-server-and-test 'solana-test-validator --reset --quiet' http://localhost:8899/health start", 8 | "lint": "eslint --ext .ts solana/trie-example/* && prettier --check \"solana/trie-example/**/*.ts\"", 9 | "lint:fix": "eslint --ext .ts solana/trie-example/* --fix && prettier --write \"solana/trie-example/**/*.ts\"", 10 | "clean": "npm run clean:trie-example", 11 | "build:trie-example": "cargo build-sbf --manifest-path=solana/trie-example/Cargo.toml --sbf-out-dir=dist/trie-example", 12 | "deploy:trie-example": "solana program deploy dist/trie-example/trie.so", 13 | "clean:trie-example": "cargo clean --manifest-path=solana/trie-example/Cargo.toml && rm -rf ./dist", 14 | "test:trie-example": "cargo test-bpf --manifest-path=solana/trie-example/Cargo.toml", 15 | "pretty": "prettier --write 'solana/trie-example/client/*.ts'" 16 | }, 17 | "dependencies": { 18 | "@coral-xyz/anchor": "^0.27.0", 19 | "@metaplex-foundation/mpl-token-metadata": "^3.1.2", 20 | "@metaplex-foundation/umi": "^0.9.0", 21 | "@solana/spl-token": "^0.3.10", 22 | "@solana/web3.js": "^1.91.3", 23 | "borsher": "^3.5.0", 24 | "bs58": "^5.0.0", 25 | "mz": "^2.7.0", 26 | "tsconfig": "^7.0.0", 27 | "yaml": "^2.0.0" 28 | }, 29 | "devDependencies": { 30 | "@tsconfig/recommended": "^1.0.1", 31 | "@types/bn.js": "^5.1.0", 32 | "@types/chai": "^4.3.0", 33 | "@types/eslint": "^8.2.2", 34 | "@types/eslint-plugin-prettier": "^3.1.0", 35 | "@types/mocha": "^9.0.0", 36 | "@types/mz": "^2.7.2", 37 | "@types/prettier": "^2.1.5", 38 | "@types/yaml": "^1.9.7", 39 | "@typescript-eslint/eslint-plugin": "^4.6.0", 40 | "@typescript-eslint/parser": "^4.6.0", 41 | "chai": "^4.3.4", 42 | "eslint": "^7.12.1", 43 | "eslint-config-prettier": "^6.15.0", 44 | "eslint-plugin-prettier": "^4.0.0", 45 | "mocha": "^9.0.3", 46 | "prettier": "^2.1.2", 47 | "start-server-and-test": "^2.0", 48 | "ts-mocha": "^10.0.0", 49 | "ts-node": "^10.9.2", 50 | "typescript": "^4.0.5" 51 | }, 52 | "engines": { 53 | "node": ">=14.0.0" 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /solana/witnessed-trie/wip.rs: -------------------------------------------------------------------------------- 1 | const TRIE_SEED: &[u8] = b"trie"; 2 | 3 | /// Takes enough entries from the `accounts` to match number of `indices` and 4 | /// collects them into a mapping. 5 | /// 6 | /// Returns an error if `accounts` iterator has fewer entries than `indices` 7 | /// slice or if any of the accounts are not a valid trie data account 8 | /// corresponding to given `root` trie account. 9 | /// 10 | /// A trie data account is a PDA owned by `program_id` created with seeds 11 | /// `["trie", root.pubkey, index.to_le_bytes()]`. 12 | /// 13 | /// Duplicate accounts (i.e. duplicate index) are ignored. 14 | /// 15 | /// Trie data accounts are supplementary accounts where trie data spills over if 16 | /// the root account is too small. Those spill over accounts are necessary 17 | /// because Solana has a limit of 10 MiB for a single account. 18 | /// 19 | /// Note that the spill over trie accounts feature isn’t currently implemented. 20 | /// This function is in practice unused but is provided for future 21 | /// extensibility. 22 | pub(crate) fn get_trie_accounts<'a, 'b: 'a>( 23 | program_id: &Pubkey, 24 | root: &AccountInfo<'b>, 25 | accounts: &mut core::slice::Iter<'a, AccountInfo<'b>>, 26 | indices: &[[u8; 2]], 27 | ) -> Result>> { 28 | let accounts = next_account_infos(accounts, indices.len())?; 29 | indices 30 | .iter() 31 | .copied() 32 | .map(u16::from_le_bytes) 33 | .zip(accounts.iter()) 34 | .map(|(index, account)| { 35 | verify_trie_account(program_id, root, account, index)?; 36 | Ok((index, account)) 37 | }) 38 | .collect() 39 | } 40 | 41 | /// Verifies that the account is a trie PDA account with given index. 42 | /// 43 | /// Trie accounts store the trie nodes and 44 | fn verify_trie_account( 45 | program_id: &Pubkey, 46 | root: &AccountInfo, 47 | account: &AccountInfo, 48 | index: &u16, 49 | ) -> Result<()> { 50 | if account.owner != program_id { 51 | msg!("Invalid data account owner"); 52 | return Err(ProgramError::InvalidAccountOwner); 53 | } 54 | let seeds = [TRIE_SEED, root.pubkey.as_ref(), &index.to_le_bytes()]; 55 | let (pubkey, _) = Pubkey::find_program_address(&seeds, program_id); 56 | if account.pubkey != pubkey { 57 | msg!("Invalid data account address"); 58 | return Err(ProgramError::InvalidAccountData); 59 | } 60 | Ok(()) 61 | } 62 | -------------------------------------------------------------------------------- /solana/trie-geyser-plugin/README.md: -------------------------------------------------------------------------------- 1 | # Witnessed trie Solana geyser plugin 2 | 3 | The plugin runs as part of Solana client and observes changes to the trie 4 | witness account. When change happens, the plugin generates proofs for the trie 5 | root and captures the trie root account. This allows generating proofs for 6 | individual keys in the trie. 7 | 8 | ## Usage 9 | 10 | The plugin requires Solana client from `mantis/dev` branch in 11 | https://github.com/ComposableFi/mantis-solana/. First clone that repository and 12 | build the client: 13 | 14 | git clone -b mantis/dev https://github.com/ComposableFi/mantis-solana/ 15 | cd mantis-solana 16 | cargo build -rp solana-test-validator 17 | 18 | With that done, enter root of the `emulated-light-client` repository and build 19 | necessary binaries: 20 | 21 | cd path/to/emulated-light-client 22 | cargo build-sbf 23 | cargo build -r --manifest-path=solana/trie-geyser-plugin/Cargo.toml 24 | 25 | To start the Solana validator with the plugin enabled, use the 26 | `--geyser-plugin-config` flag to point at the `config.json` file. Note that 27 | when running on MacOS, path in `config.json` needs to be updated to point to 28 | a `.dylib` file. 29 | 30 | cd mantis-solana 31 | config=path/to/emulated-light-client/solana/trie-geyser-plugin/config.json 32 | # On MacOS execute: 33 | # sed -i s/\\.so/.dylib/ -- "${config:?}" 34 | ./target/release/solana-test-validator \ 35 | --geyser-plugin-config "${config:?}" 36 | 37 | In another terminal, deploy the witnessed-trie contract and test it with 38 | provided command line tool: 39 | 40 | cd path/to/emulated-light-client 41 | solana -u localhost program deploy ./target/deploy/wittrie.so 42 | ./target/release/solana-witnessed-trie-cli set foo bar 43 | 44 | You may need to adjust `trie_program` and `root_account` in `config.json` and 45 | restart the validator. 46 | 47 | The plugin provides an RPC server for getting the proofs and trie data. The 48 | simplest way to test this server is by using httpie utility, for example: 49 | 50 | http 127.0.0.1:42069 jsonrpc:='"2.0"' id=_ method=listSlots 51 | http 127.0.0.1:42069 jsonrpc:='"2.0"' id=_ method=getLatestSlotData 52 | http 127.0.0.1:42069 jsonrpc:='"2.0"' id=_ method=getSlotData params:='[66522]' 53 | 54 | ## Using the proof 55 | 56 | At the moment, the proof is only logged. Mechanism for getting the proof to be 57 | used by relayer is not yet implemented. 58 | -------------------------------------------------------------------------------- /solana/solana-ibc/programs/solana-ibc/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "solana-ibc" 3 | description = "Created with Anchor" 4 | edition = "2021" 5 | version.workspace = true 6 | 7 | [lib] 8 | crate-type = ["cdylib", "lib"] 9 | name = "solana_ibc" 10 | 11 | [features] 12 | default = ["custom-entrypoint", "custom-heap"] 13 | cpi = ["no-entrypoint"] 14 | custom-heap = ["solana-allocator"] 15 | custom-entrypoint = ["custom-heap"] 16 | mocks = ["ibc-testkit"] 17 | no-entrypoint = [] 18 | no-idl = [] 19 | no-log-ix-name = [] 20 | witness = [] 21 | 22 | [dependencies] 23 | anchor-lang.workspace = true 24 | anchor-spl = { workspace = true, features = ["metadata"] } 25 | base64.workspace = true 26 | bytemuck = { workspace = true, features = ["must_cast", "zeroable_atomics"] } 27 | derive_more.workspace = true 28 | hex-literal.workspace = true 29 | ibc-client-tendermint-types.workspace = true 30 | ibc-proto.workspace = true 31 | ibc-testkit = { workspace = true, optional = true } 32 | ibc.workspace = true 33 | linear-map.workspace = true 34 | primitive-types.workspace = true 35 | prost.workspace = true 36 | serde.workspace = true 37 | serde_json.workspace = true 38 | # We normally access solana_program via anchor_lang but to support 39 | # pubkey! macro we need to have solana_program as direct dependency. 40 | # TODO(mina86): Remove this once we upgrade Anchor to version with its 41 | # own pubkey! macro. 42 | solana-program.workspace = true 43 | spl-associated-token-account.workspace = true 44 | spl-token.workspace = true 45 | strum.workspace = true 46 | tendermint-light-client-verifier.workspace = true 47 | tendermint.workspace = true 48 | uint.workspace = true 49 | 50 | guestchain.workspace = true 51 | cf-guest.workspace = true 52 | cf-solana = { workspace = true, features = ["solana-program", "no-blake3-syscall"] } 53 | lib = { workspace = true, features = ["solana-program"] } 54 | memory.workspace = true 55 | solana-allocator = { workspace = true, optional = true } 56 | solana-signature-verifier = { workspace = true, features = ["guest", "library"] } 57 | solana-trie.workspace = true 58 | stdx.workspace = true 59 | trie-ids = { workspace = true, features = ["borsh"] } 60 | wasm = { workspace = true } 61 | itertools = "0.10.5" 62 | 63 | [dev-dependencies] 64 | anchor-client.workspace = true 65 | anyhow.workspace = true 66 | ibc-testkit.workspace = true 67 | insta.workspace = true 68 | 69 | lib = { workspace = true, features = ["test_utils"] } 70 | solana-write-account = { workspace = true, features = ["library"] } 71 | -------------------------------------------------------------------------------- /common/guestchain/src/snapshots/guestchain__block__genesis-block.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: common/blockchain/src/block.rs 3 | expression: check(&genesis) 4 | --- 5 | [ 6 | 0, 7 | 0, 8 | 0, 9 | 0, 10 | 0, 11 | 0, 12 | 0, 13 | 0, 14 | 0, 15 | 0, 16 | 0, 17 | 0, 18 | 0, 19 | 0, 20 | 0, 21 | 0, 22 | 0, 23 | 0, 24 | 0, 25 | 0, 26 | 0, 27 | 0, 28 | 0, 29 | 0, 30 | 0, 31 | 0, 32 | 0, 33 | 0, 34 | 0, 35 | 0, 36 | 0, 37 | 0, 38 | 0, 39 | 0, 40 | 0, 41 | 0, 42 | 0, 43 | 0, 44 | 0, 45 | 0, 46 | 0, 47 | 42, 48 | 0, 49 | 0, 50 | 0, 51 | 0, 52 | 0, 53 | 0, 54 | 0, 55 | 24, 56 | 0, 57 | 0, 58 | 0, 59 | 0, 60 | 0, 61 | 0, 62 | 0, 63 | 0, 64 | 0, 65 | 0, 66 | 66, 67 | 0, 68 | 0, 69 | 0, 70 | 66, 71 | 0, 72 | 0, 73 | 0, 74 | 66, 75 | 0, 76 | 0, 77 | 0, 78 | 66, 79 | 0, 80 | 0, 81 | 0, 82 | 66, 83 | 0, 84 | 0, 85 | 0, 86 | 66, 87 | 0, 88 | 0, 89 | 0, 90 | 66, 91 | 0, 92 | 0, 93 | 0, 94 | 66, 95 | 0, 96 | 0, 97 | 0, 98 | 0, 99 | 0, 100 | 0, 101 | 0, 102 | 0, 103 | 0, 104 | 0, 105 | 0, 106 | 0, 107 | 0, 108 | 0, 109 | 0, 110 | 0, 111 | 0, 112 | 0, 113 | 0, 114 | 0, 115 | 0, 116 | 0, 117 | 0, 118 | 0, 119 | 0, 120 | 0, 121 | 0, 122 | 0, 123 | 0, 124 | 0, 125 | 0, 126 | 0, 127 | 1, 128 | 0, 129 | 2, 130 | 0, 131 | 0, 132 | 0, 133 | 0, 134 | 0, 135 | 0, 136 | 0, 137 | 0, 138 | 10, 139 | 0, 140 | 0, 141 | 0, 142 | 0, 143 | 0, 144 | 0, 145 | 0, 146 | 0, 147 | 0, 148 | 0, 149 | 0, 150 | 0, 151 | 0, 152 | 0, 153 | 0, 154 | 0, 155 | 1, 156 | 0, 157 | 0, 158 | 0, 159 | 10, 160 | 0, 161 | 0, 162 | 0, 163 | 0, 164 | 0, 165 | 0, 166 | 0, 167 | 0, 168 | 0, 169 | 0, 170 | 0, 171 | 0, 172 | 0, 173 | 0, 174 | 0, 175 | 11, 176 | 0, 177 | 0, 178 | 0, 179 | 0, 180 | 0, 181 | 0, 182 | 0, 183 | 0, 184 | 0, 185 | 0, 186 | 0, 187 | 0, 188 | 0, 189 | 0, 190 | 0, 191 | ] 192 | -------------------------------------------------------------------------------- /common/cf-solana/src/client.rs: -------------------------------------------------------------------------------- 1 | use core::num::NonZeroU64; 2 | 3 | use crate::proto; 4 | use crate::types::PubKey; 5 | 6 | pub(crate) mod impls; 7 | 8 | /// The client state of the light client for the Solana blockchain as a Rust 9 | /// object. 10 | /// 11 | /// `From` and `TryFrom` conversions define mapping between this Rust object and 12 | /// corresponding Protocol Message [`proto::ClientState`]. 13 | #[derive(Clone, Debug, PartialEq, Eq)] 14 | pub struct ClientState { 15 | /// Latest rooted slot. 16 | pub latest_slot: NonZeroU64, 17 | 18 | /// Address of the trie witness account. 19 | pub witness_account: PubKey, 20 | 21 | pub trusting_period_ns: u64, 22 | 23 | /// Whether client is frozen. 24 | pub is_frozen: bool, 25 | } 26 | 27 | impl ClientState { 28 | pub fn with_header(&self, header: &super::Header) -> Self { 29 | let latest_slot = self.latest_slot.max(header.slot); 30 | Self { latest_slot, ..self.clone() } 31 | } 32 | 33 | pub fn frozen(&self) -> Self { Self { is_frozen: true, ..self.clone() } } 34 | } 35 | 36 | impl From for proto::ClientState { 37 | fn from(state: ClientState) -> Self { Self::from(&state) } 38 | } 39 | 40 | impl From<&ClientState> for proto::ClientState { 41 | fn from(state: &ClientState) -> Self { 42 | Self { 43 | latest_slot: state.latest_slot.get(), 44 | witness_account: state.witness_account.0.to_vec(), 45 | trusting_period_ns: state.trusting_period_ns, 46 | is_frozen: state.is_frozen, 47 | } 48 | } 49 | } 50 | 51 | impl TryFrom for ClientState { 52 | type Error = proto::BadMessage; 53 | fn try_from(msg: proto::ClientState) -> Result { 54 | Self::try_from(&msg) 55 | } 56 | } 57 | 58 | impl TryFrom<&proto::ClientState> for ClientState { 59 | type Error = proto::BadMessage; 60 | fn try_from(msg: &proto::ClientState) -> Result { 61 | let latest_slot = 62 | NonZeroU64::new(msg.latest_slot).ok_or(proto::BadMessage)?; 63 | let witness_account = 64 | <&PubKey>::try_from(msg.witness_account.as_slice()) 65 | .map_err(|_| proto::BadMessage)?; 66 | Ok(Self { 67 | latest_slot, 68 | witness_account: *witness_account, 69 | trusting_period_ns: msg.trusting_period_ns, 70 | is_frozen: msg.is_frozen, 71 | }) 72 | } 73 | } 74 | 75 | proto_utils::define_wrapper! { 76 | proto: proto::ClientState, 77 | wrapper: ClientState, 78 | } 79 | -------------------------------------------------------------------------------- /common/cf-guest/proto/guest.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package lightclients.guest.v1; 4 | 5 | // The consensus state of the guest blockchain. 6 | message ConsensusState { 7 | // 32-byte block hash. 8 | bytes block_hash = 1; 9 | // Timestamp in nanoseconds. Never zero. 10 | uint64 timestamp_ns = 2; 11 | 12 | // NEXT ID: 3 13 | } 14 | 15 | // The client state of the light client for the guest blockchain. 16 | message ClientState { 17 | // 32-byte hash of the genesis block. This is used to identify instance 18 | // of the blockchain. 19 | bytes genesis_hash = 1; 20 | 21 | // Height of the latest finalised block. 22 | uint64 latest_height = 2; 23 | 24 | // Duration of the period since the last timestamp during which the 25 | // submitted headers are valid for upgrade. 26 | uint64 trusting_period_ns = 3; 27 | 28 | // Commitment of the epoch used to verify future states. 29 | bytes epoch_commitment = 4; 30 | 31 | // Commitment of the previous epoch used to verify past states. 32 | bytes prev_epoch_commitment = 6; 33 | 34 | // Whether client is frozen. 35 | bool is_frozen = 5; 36 | 37 | // NEXT ID: 7 38 | } 39 | 40 | message ClientMessage { 41 | oneof message { 42 | Header header = 1; 43 | Misbehaviour misbehaviour = 2; 44 | } 45 | 46 | // NEXT ID: 3 47 | } 48 | 49 | message Header { 50 | // 32-byte hash of the genesis block. 51 | // 52 | // This is used to identify instance of the blockchain. It’s also part 53 | // of the fingerprint that validators sign. 54 | bytes genesis_hash = 1; 55 | 56 | // Borsh-serialised block header. 57 | bytes block_header = 2; 58 | 59 | // Borsh-serialised epoch the block belongs to. 60 | // 61 | // The epoch specifies validators which sign the block. 62 | bytes epoch = 3; 63 | 64 | // List of signatures of the block. 65 | repeated Signature signatures = 4; 66 | 67 | // NEXT ID: 5 68 | } 69 | 70 | message Signature { 71 | // Index of the validator in the validators set defined in the epoch. 72 | // 73 | // The validators ore defined in the guestchain::Epoch object 74 | // Borsh-serialised in the Header::epoch field. 75 | uint32 index = 1; 76 | 77 | // 64-byte signature of the block’s fingerprint. 78 | bytes signature = 2; 79 | 80 | // NEXT ID: 3 81 | } 82 | 83 | message Misbehaviour { 84 | // First header. 85 | Header header1 = 1; 86 | 87 | // Second header. 88 | // 89 | // Note that the message may be partially filled. If `header1` and 90 | // `header2` have the same `genesis_hash` or `epoch` (which is extremely 91 | // likely), those fields can be omitted in the second header. 92 | Header header2 = 2; 93 | 94 | // NEXT ID: 3 95 | } 96 | -------------------------------------------------------------------------------- /common/lib/src/par.rs: -------------------------------------------------------------------------------- 1 | #[cfg(all(feature = "rayon", not(miri)))] 2 | use rayon::prelude::*; 3 | 4 | pub mod prelude { 5 | #[cfg(all(feature = "rayon", not(miri)))] 6 | pub use rayon::iter::ParallelIterator; 7 | } 8 | 9 | #[cfg(all(feature = "rayon", not(miri)))] 10 | pub type Chunks<'a, T> = rayon::slice::Chunks<'a, T>; 11 | #[cfg(any(not(feature = "rayon"), miri))] 12 | pub type Chunks<'a, T> = core::slice::Chunks<'a, T>; 13 | 14 | /// Splits array into `count`-element chunks. 15 | /// 16 | /// It uses conditional compilation and either uses Rayon’s `par_chunks` method 17 | /// (to allow parallelisation of the chunk processing) or standard `[T]::chunks` 18 | /// method. Specifically, if `rayon` feature is enabled and not building Miri 19 | /// tests, Rayon is used. 20 | /// 21 | /// Note that depending on compilation features and target the function is 22 | /// defined as returning `rayon::slice::Chunks` or `core::slice::Chunks`. types. 23 | /// 24 | /// # Example 25 | /// 26 | /// ``` 27 | /// #[allow(unused_imports)] 28 | /// use lib::par::prelude::*; 29 | /// 30 | /// let chunks = lib::par::chunks(&[0, 1, 2, 3, 4], 3) 31 | /// .map(|chunk| chunk.to_vec()) 32 | /// .collect::>>(); 33 | /// assert_eq!(&[vec![0, 1, 2], vec![3, 4]], chunks.as_slice()); 34 | /// ``` 35 | pub fn chunks(arr: &[T], count: usize) -> Chunks<'_, T> { 36 | #[cfg(all(feature = "rayon", not(miri)))] 37 | return arr.par_chunks(count); 38 | #[cfg(any(not(feature = "rayon"), miri))] 39 | return arr.chunks(count); 40 | } 41 | 42 | #[test] 43 | fn test_chunks() { 44 | let got = chunks(&[1u32, 2, 3, 4, 5], 3) 45 | .map(|chunk| (chunk.len(), chunk.iter().sum::())) 46 | .collect::>(); 47 | assert_eq!(&[(3, 6), (2, 9)], got.as_slice()); 48 | } 49 | 50 | 51 | /// Sorts elements of a slice using given comparator. 52 | /// 53 | /// It uses conditional compilation and either uses Rayon’s 54 | /// `par_sort_unstable_by` or standard `sort_unstable_by` method. Specifically, 55 | /// if `rayon` feature is enabled and not building Miri tests, Rayon is used. 56 | /// 57 | /// # Example 58 | /// 59 | /// ``` 60 | /// let mut arr = [5, 4, 3, 1, 2, 3]; 61 | /// lib::par::sort_unstable_by(&mut arr[..], |a, b| a.cmp(b)); 62 | /// assert_eq!(&[1, 2, 3, 3, 4, 5], &arr[..]); 63 | /// ``` 64 | pub fn sort_unstable_by( 65 | arr: &mut [T], 66 | cmp: impl (Fn(&T, &T) -> core::cmp::Ordering) + Sync, 67 | ) { 68 | #[cfg(all(feature = "rayon", not(miri)))] 69 | arr.par_sort_unstable_by(cmp); 70 | #[cfg(any(not(feature = "rayon"), miri))] 71 | arr.sort_unstable_by(cmp); 72 | } 73 | -------------------------------------------------------------------------------- /common/trie-geyser/src/api.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | use cf_solana::proof; 4 | 5 | type Result = ::core::result::Result; 6 | 7 | /// Data provided by the Witnessed Trie Geyser plugin. 8 | #[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)] 9 | pub struct SlotData { 10 | /// Proof of the accounts delta hash. 11 | pub delta_hash_proof: proof::DeltaHashProof, 12 | /// Proof of the witness trie. 13 | pub witness_proof: proof::AccountProof, 14 | /// Trie root account. 15 | pub root_account: proof::AccountHashData, 16 | } 17 | 18 | #[jsonrpc_derive::rpc] 19 | pub trait Methods { 20 | type Metadata; 21 | 22 | #[rpc(meta, name = "listSlots")] 23 | fn list_slots(&self, meta: Self::Metadata) -> Result>; 24 | 25 | #[rpc(meta, name = "getLatestSlotData")] 26 | fn get_latest_slot_data( 27 | &self, 28 | meta: Self::Metadata, 29 | ) -> Result)>>; 30 | 31 | #[rpc(meta, name = "getSlotData")] 32 | fn get_slot_data( 33 | &self, 34 | meta: Self::Metadata, 35 | slot: u64, 36 | ) -> Result>>; 37 | } 38 | 39 | #[test] 40 | fn test_slot_data_serialisation() { 41 | use cf_solana::types::PubKey; 42 | use lib::hash::CryptoHash; 43 | 44 | let account_hash_data = cf_solana::proof::AccountHashData::new( 45 | 42, 46 | &PubKey(CryptoHash::test(1).into()), 47 | false, 48 | u64::MAX, 49 | b"foo", 50 | &PubKey(CryptoHash::test(2).into()), 51 | ); 52 | 53 | let mut proof = proof::MerkleProof::default(); 54 | let level = 55 | [CryptoHash::test(10), CryptoHash::test(11), CryptoHash::test(12)]; 56 | proof.push_level(&level, 1); 57 | 58 | let data = SlotData { 59 | delta_hash_proof: proof::DeltaHashProof { 60 | parent_blockhash: CryptoHash::test(101), 61 | accounts_delta_hash: CryptoHash::test(102), 62 | num_sigs: 103, 63 | blockhash: CryptoHash::test(104), 64 | epoch_accounts_hash: None, 65 | }, 66 | witness_proof: proof::AccountProof { account_hash_data, proof }, 67 | root_account: cf_solana::proof::AccountHashData::new( 68 | 42, 69 | &PubKey(CryptoHash::test(50).into()), 70 | false, 71 | u64::MAX, 72 | b"trie", 73 | &PubKey(CryptoHash::test(51).into()), 74 | ), 75 | }; 76 | 77 | if !cfg!(miri) { 78 | insta::assert_json_snapshot!(data); 79 | } 80 | let serialised = serde_json::to_string(&data).unwrap(); 81 | 82 | let deserialised = serde_json::from_str(&serialised).unwrap(); 83 | assert_eq!(data, deserialised); 84 | } 85 | -------------------------------------------------------------------------------- /common/guestchain/src/common.rs: -------------------------------------------------------------------------------- 1 | use borsh::maybestd::io; 2 | 3 | /// A discriminant to include at the beginning of data structures which need to 4 | /// be versioned for forwards compatibility. 5 | /// 6 | /// It’s serialised as a single byte zero and when deserialising it fails if the 7 | /// single read byte isn’t zero. Since at the moment all structures in the code 8 | /// base are at version zero, no other versions are supported. 9 | /// 10 | /// In the future, the zero byte can be used to distinguish versions of data 11 | /// structures. One idea is to provide `VersionUpTo` type which will 12 | /// serialise as specified version and verify version ≤ `MAX` when 13 | /// deserialising: 14 | /// 15 | /// ```ignore 16 | /// #[derive(borsh::BorshSerialize, borsh::BorshDeserialize)] 17 | /// struct Foo { 18 | /// version: VersionZero, 19 | /// pub count: usize, 20 | /// } 21 | /// 22 | /// struct Bar { 23 | /// version: VersionUpTo<1>, 24 | /// pub drinks: Vec, 25 | /// pub dishes: Vec, 26 | /// } 27 | /// ``` 28 | /// 29 | /// With that scheme, borsh serialisation and deserialisation will need to be 30 | /// implemented manually and will have to take into account the version. 31 | /// Another approach is to use an enum with variants for each version: 32 | /// 33 | /// ```ignore 34 | /// #[derive(borsh::BorshSerialize, borsh::BorshDeserialize)] 35 | /// enum Bar { 36 | /// V1(v1::Bar), 37 | /// V2(v2::Bar), 38 | /// } 39 | /// 40 | /// mod v1 { struct Bar { pub drinks: Vec } } 41 | /// mod v2 { struct Bar { pub drinks: Vec, pub dishes: Vec } } 42 | /// ``` 43 | /// 44 | /// Whatever the case, having `version: VersionZero` field as the first one in 45 | /// a structure allows it to be versioned in the future. 46 | #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] 47 | pub(crate) struct VersionZero; 48 | 49 | impl borsh::BorshSerialize for VersionZero { 50 | fn serialize(&self, writer: &mut W) -> io::Result<()> { 51 | writer.write_all(&[0]) 52 | } 53 | } 54 | 55 | impl borsh::BorshDeserialize for VersionZero { 56 | fn deserialize_reader(reader: &mut R) -> io::Result { 57 | u8::deserialize_reader(reader).and_then(|byte| { 58 | if byte == 0 { 59 | Ok(Self) 60 | } else { 61 | let msg = alloc::format!("Invalid version: {byte}"); 62 | Err(io::Error::new(io::ErrorKind::InvalidData, msg)) 63 | } 64 | }) 65 | } 66 | } 67 | 68 | #[test] 69 | fn test_version_zero() { 70 | use borsh::BorshDeserialize; 71 | 72 | assert_eq!(&[0], borsh::to_vec(&VersionZero).unwrap().as_slice()); 73 | VersionZero::try_from_slice(&[0]).unwrap(); 74 | VersionZero::try_from_slice(&[1]).unwrap_err(); 75 | VersionZero::try_from_slice(&[]).unwrap_err(); 76 | VersionZero::try_from_slice(&[0, 0]).unwrap_err(); 77 | } 78 | -------------------------------------------------------------------------------- /common/cf-solana/src/types.rs: -------------------------------------------------------------------------------- 1 | use bytemuck::TransparentWrapper; 2 | 3 | /// Solana public key also used as account address. 4 | #[derive( 5 | Clone, 6 | Copy, 7 | Default, 8 | PartialEq, 9 | Eq, 10 | PartialOrd, 11 | Ord, 12 | Hash, 13 | bytemuck::TransparentWrapper, 14 | bytemuck::Pod, 15 | bytemuck::Zeroable, 16 | derive_more::AsRef, 17 | derive_more::AsMut, 18 | derive_more::From, 19 | derive_more::Into, 20 | )] 21 | #[into(owned, ref, ref_mut)] 22 | #[repr(transparent)] 23 | pub struct PubKey(pub [u8; 32]); 24 | 25 | 26 | impl<'a> From<&'a [u8; 32]> for &'a PubKey { 27 | fn from(bytes: &'a [u8; 32]) -> Self { ::wrap_ref(bytes) } 28 | } 29 | 30 | impl<'a> From<&'a mut [u8; 32]> for &'a mut PubKey { 31 | fn from(bytes: &'a mut [u8; 32]) -> Self { ::wrap_mut(bytes) } 32 | } 33 | 34 | impl<'a> TryFrom<&'a [u8]> for &'a PubKey { 35 | type Error = core::array::TryFromSliceError; 36 | 37 | #[inline] 38 | fn try_from(bytes: &'a [u8]) -> Result { 39 | <&[u8; 32]>::try_from(bytes).map(Into::into) 40 | } 41 | } 42 | 43 | impl<'a> TryFrom<&'a [u8]> for PubKey { 44 | type Error = core::array::TryFromSliceError; 45 | 46 | #[inline] 47 | fn try_from(bytes: &'a [u8]) -> Result { 48 | <&Self>::try_from(bytes).copied() 49 | } 50 | } 51 | 52 | 53 | #[allow(unused_macros)] 54 | macro_rules! impl_sol_conversions { 55 | ($crt:ident) => { 56 | impl From<$crt::pubkey::Pubkey> for PubKey { 57 | fn from(obj: $crt::pubkey::Pubkey) -> PubKey { 58 | obj.to_bytes().into() 59 | } 60 | } 61 | 62 | impl<'a> From<&'a $crt::pubkey::Pubkey> for &'a PubKey { 63 | fn from(obj: &'a $crt::pubkey::Pubkey) -> &'a PubKey { 64 | <&[u8; 32]>::try_from(obj.as_ref()).unwrap().into() 65 | } 66 | } 67 | 68 | impl<'a> From<&'a mut $crt::pubkey::Pubkey> for &'a mut PubKey { 69 | fn from(pk: &'a mut $crt::pubkey::Pubkey) -> &'a mut PubKey { 70 | <&mut [u8; 32]>::try_from(pk.as_mut()).unwrap().into() 71 | } 72 | } 73 | 74 | impl From for $crt::pubkey::Pubkey { 75 | fn from(obj: PubKey) -> Self { Self::from(obj.0) } 76 | } 77 | 78 | impl<'a> From<&'a PubKey> for &'a $crt::pubkey::Pubkey { 79 | fn from(obj: &'a PubKey) -> Self { 80 | let obj = 81 | &obj.0 as *const [u8; 32] as *const $crt::pubkey::Pubkey; 82 | // SAFETY: $crt::pubkey::Pubkey is repr(transparent) 83 | unsafe { &*obj } 84 | } 85 | } 86 | 87 | impl<'a> From<&'a mut PubKey> for &'a mut $crt::pubkey::Pubkey { 88 | fn from(pk: &'a mut PubKey) -> Self { 89 | let pk = 90 | &mut pk.0 as *mut [u8; 32] as *mut $crt::pubkey::Pubkey; 91 | // SAFETY: $crt::pk::PubKey is repr(transparent) 92 | unsafe { &mut *pk } 93 | } 94 | } 95 | }; 96 | } 97 | 98 | #[cfg(feature = "solana-program")] 99 | impl_sol_conversions!(solana_program); 100 | #[cfg(any(test, feature = "solana-program-2"))] 101 | impl_sol_conversions!(solana_program_2); 102 | -------------------------------------------------------------------------------- /solana/signature-verifier/src/snapshots/sigverify__ed25519_program__test__two_signatures_prefix_message__new_instruction_snapshot.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: solana/signature-verifier/src/ed25519_program.rs 3 | expression: data.as_slice() 4 | --- 5 | [ 6 | 2, 7 | 0, 8 | 33, 9 | 0, 10 | 255, 11 | 255, 12 | 97, 13 | 0, 14 | 255, 15 | 255, 16 | 30, 17 | 0, 18 | 3, 19 | 0, 20 | 255, 21 | 255, 22 | 129, 23 | 0, 24 | 255, 25 | 255, 26 | 193, 27 | 0, 28 | 255, 29 | 255, 30 | 30, 31 | 0, 32 | 2, 33 | 0, 34 | 255, 35 | 255, 36 | 102, 37 | 111, 38 | 111, 39 | 57, 40 | 226, 41 | 233, 42 | 200, 43 | 76, 44 | 159, 45 | 119, 46 | 129, 47 | 87, 48 | 122, 49 | 149, 50 | 42, 51 | 95, 52 | 121, 53 | 3, 54 | 107, 55 | 158, 56 | 191, 57 | 130, 58 | 176, 59 | 135, 60 | 136, 61 | 138, 62 | 218, 63 | 77, 64 | 104, 65 | 116, 66 | 18, 67 | 193, 68 | 63, 69 | 77, 70 | 228, 71 | 83, 72 | 74, 73 | 208, 74 | 135, 75 | 107, 76 | 23, 77 | 133, 78 | 243, 79 | 89, 80 | 252, 81 | 95, 82 | 50, 83 | 202, 84 | 117, 85 | 211, 86 | 253, 87 | 205, 88 | 242, 89 | 152, 90 | 122, 91 | 243, 92 | 56, 93 | 32, 94 | 48, 95 | 90, 96 | 201, 97 | 141, 98 | 5, 99 | 36, 100 | 150, 101 | 62, 102 | 11, 103 | 18, 104 | 10, 105 | 242, 106 | 85, 107 | 239, 108 | 109, 109 | 138, 110 | 32, 111 | 37, 112 | 117, 113 | 17, 114 | 6, 115 | 184, 116 | 125, 117 | 216, 118 | 16, 119 | 222, 120 | 201, 121 | 241, 122 | 41, 123 | 225, 124 | 95, 125 | 171, 126 | 115, 127 | 85, 128 | 114, 129 | 249, 130 | 152, 131 | 205, 132 | 71, 133 | 25, 134 | 89, 135 | 184, 136 | 138, 137 | 109, 138 | 149, 139 | 4, 140 | 147, 141 | 158, 142 | 34, 143 | 169, 144 | 255, 145 | 118, 146 | 145, 147 | 196, 148 | 206, 149 | 230, 150 | 246, 151 | 96, 152 | 240, 153 | 234, 154 | 217, 155 | 169, 156 | 142, 157 | 57, 158 | 79, 159 | 56, 160 | 235, 161 | 40, 162 | 163, 163 | 64, 164 | 36, 165 | 96, 166 | 99, 167 | 99, 168 | 4, 169 | 150, 170 | 58, 171 | 212, 172 | 48, 173 | 73, 174 | 198, 175 | 208, 176 | 80, 177 | 37, 178 | 163, 179 | 65, 180 | 210, 181 | 215, 182 | 153, 183 | 231, 184 | 78, 185 | 254, 186 | 165, 187 | 95, 188 | 16, 189 | 132, 190 | 235, 191 | 54, 192 | 253, 193 | 163, 194 | 185, 195 | 172, 196 | 140, 197 | 46, 198 | 12, 199 | 18, 200 | 10, 201 | 242, 202 | 85, 203 | 239, 204 | 109, 205 | 138, 206 | 32, 207 | 37, 208 | 117, 209 | 17, 210 | 6, 211 | 184, 212 | 125, 213 | 216, 214 | 16, 215 | 222, 216 | 201, 217 | 241, 218 | 41, 219 | 225, 220 | 95, 221 | 171, 222 | 115, 223 | 85, 224 | 114, 225 | 249, 226 | 152, 227 | 205, 228 | 71, 229 | 25, 230 | 89, 231 | ] 232 | -------------------------------------------------------------------------------- /solana/signature-verifier/src/snapshots/sigverify__ed25519_program__test__two_signatures_same_message__new_instruction_snapshot.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: solana/signature-verifier/src/ed25519_program.rs 3 | expression: data.as_slice() 4 | --- 5 | [ 6 | 2, 7 | 0, 8 | 33, 9 | 0, 10 | 255, 11 | 255, 12 | 97, 13 | 0, 14 | 255, 15 | 255, 16 | 30, 17 | 0, 18 | 3, 19 | 0, 20 | 255, 21 | 255, 22 | 129, 23 | 0, 24 | 255, 25 | 255, 26 | 193, 27 | 0, 28 | 255, 29 | 255, 30 | 30, 31 | 0, 32 | 3, 33 | 0, 34 | 255, 35 | 255, 36 | 102, 37 | 111, 38 | 111, 39 | 57, 40 | 226, 41 | 233, 42 | 200, 43 | 76, 44 | 159, 45 | 119, 46 | 129, 47 | 87, 48 | 122, 49 | 149, 50 | 42, 51 | 95, 52 | 121, 53 | 3, 54 | 107, 55 | 158, 56 | 191, 57 | 130, 58 | 176, 59 | 135, 60 | 136, 61 | 138, 62 | 218, 63 | 77, 64 | 104, 65 | 116, 66 | 18, 67 | 193, 68 | 63, 69 | 77, 70 | 228, 71 | 83, 72 | 74, 73 | 208, 74 | 135, 75 | 107, 76 | 23, 77 | 133, 78 | 243, 79 | 89, 80 | 252, 81 | 95, 82 | 50, 83 | 202, 84 | 117, 85 | 211, 86 | 253, 87 | 205, 88 | 242, 89 | 152, 90 | 122, 91 | 243, 92 | 56, 93 | 32, 94 | 48, 95 | 90, 96 | 201, 97 | 141, 98 | 5, 99 | 36, 100 | 150, 101 | 62, 102 | 11, 103 | 18, 104 | 10, 105 | 242, 106 | 85, 107 | 239, 108 | 109, 109 | 138, 110 | 32, 111 | 37, 112 | 117, 113 | 17, 114 | 6, 115 | 184, 116 | 125, 117 | 216, 118 | 16, 119 | 222, 120 | 201, 121 | 241, 122 | 41, 123 | 225, 124 | 95, 125 | 171, 126 | 115, 127 | 85, 128 | 114, 129 | 249, 130 | 152, 131 | 205, 132 | 71, 133 | 25, 134 | 89, 135 | 57, 136 | 226, 137 | 233, 138 | 200, 139 | 76, 140 | 159, 141 | 119, 142 | 129, 143 | 87, 144 | 122, 145 | 149, 146 | 42, 147 | 95, 148 | 121, 149 | 3, 150 | 107, 151 | 158, 152 | 191, 153 | 130, 154 | 176, 155 | 135, 156 | 136, 157 | 138, 158 | 218, 159 | 77, 160 | 104, 161 | 116, 162 | 18, 163 | 193, 164 | 63, 165 | 77, 166 | 228, 167 | 83, 168 | 74, 169 | 208, 170 | 135, 171 | 107, 172 | 23, 173 | 133, 174 | 243, 175 | 89, 176 | 252, 177 | 95, 178 | 50, 179 | 202, 180 | 117, 181 | 211, 182 | 253, 183 | 205, 184 | 242, 185 | 152, 186 | 122, 187 | 243, 188 | 56, 189 | 32, 190 | 48, 191 | 90, 192 | 201, 193 | 141, 194 | 5, 195 | 36, 196 | 150, 197 | 62, 198 | 11, 199 | 18, 200 | 10, 201 | 242, 202 | 85, 203 | 239, 204 | 109, 205 | 138, 206 | 32, 207 | 37, 208 | 117, 209 | 17, 210 | 6, 211 | 184, 212 | 125, 213 | 216, 214 | 16, 215 | 222, 216 | 201, 217 | 241, 218 | 41, 219 | 225, 220 | 95, 221 | 171, 222 | 115, 223 | 85, 224 | 114, 225 | 249, 226 | 152, 227 | 205, 228 | 71, 229 | 25, 230 | 89, 231 | ] 232 | -------------------------------------------------------------------------------- /solana/signature-verifier/src/snapshots/sigverify__ed25519_program__test__two_signatures__new_instruction_snapshot.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: solana/signature-verifier/src/ed25519_program.rs 3 | expression: data.as_slice() 4 | --- 5 | [ 6 | 2, 7 | 0, 8 | 33, 9 | 0, 10 | 255, 11 | 255, 12 | 97, 13 | 0, 14 | 255, 15 | 255, 16 | 30, 17 | 0, 18 | 3, 19 | 0, 20 | 255, 21 | 255, 22 | 132, 23 | 0, 24 | 255, 25 | 255, 26 | 196, 27 | 0, 28 | 255, 29 | 255, 30 | 129, 31 | 0, 32 | 3, 33 | 0, 34 | 255, 35 | 255, 36 | 102, 37 | 111, 38 | 111, 39 | 57, 40 | 226, 41 | 233, 42 | 200, 43 | 76, 44 | 159, 45 | 119, 46 | 129, 47 | 87, 48 | 122, 49 | 149, 50 | 42, 51 | 95, 52 | 121, 53 | 3, 54 | 107, 55 | 158, 56 | 191, 57 | 130, 58 | 176, 59 | 135, 60 | 136, 61 | 138, 62 | 218, 63 | 77, 64 | 104, 65 | 116, 66 | 18, 67 | 193, 68 | 63, 69 | 77, 70 | 228, 71 | 83, 72 | 74, 73 | 208, 74 | 135, 75 | 107, 76 | 23, 77 | 133, 78 | 243, 79 | 89, 80 | 252, 81 | 95, 82 | 50, 83 | 202, 84 | 117, 85 | 211, 86 | 253, 87 | 205, 88 | 242, 89 | 152, 90 | 122, 91 | 243, 92 | 56, 93 | 32, 94 | 48, 95 | 90, 96 | 201, 97 | 141, 98 | 5, 99 | 36, 100 | 150, 101 | 62, 102 | 11, 103 | 18, 104 | 10, 105 | 242, 106 | 85, 107 | 239, 108 | 109, 109 | 138, 110 | 32, 111 | 37, 112 | 117, 113 | 17, 114 | 6, 115 | 184, 116 | 125, 117 | 216, 118 | 16, 119 | 222, 120 | 201, 121 | 241, 122 | 41, 123 | 225, 124 | 95, 125 | 171, 126 | 115, 127 | 85, 128 | 114, 129 | 249, 130 | 152, 131 | 205, 132 | 71, 133 | 25, 134 | 89, 135 | 98, 136 | 97, 137 | 114, 138 | 4, 139 | 55, 140 | 4, 141 | 193, 142 | 196, 143 | 126, 144 | 123, 145 | 91, 146 | 247, 147 | 64, 148 | 65, 149 | 205, 150 | 118, 151 | 220, 152 | 201, 153 | 56, 154 | 86, 155 | 151, 156 | 169, 157 | 167, 158 | 14, 159 | 72, 160 | 67, 161 | 34, 162 | 176, 163 | 170, 164 | 36, 165 | 108, 166 | 78, 167 | 110, 168 | 155, 169 | 190, 170 | 38, 171 | 78, 172 | 15, 173 | 166, 174 | 127, 175 | 138, 176 | 127, 177 | 170, 178 | 190, 179 | 210, 180 | 205, 181 | 86, 182 | 69, 183 | 179, 184 | 21, 185 | 99, 186 | 32, 187 | 171, 188 | 220, 189 | 37, 190 | 75, 191 | 180, 192 | 157, 193 | 84, 194 | 183, 195 | 175, 196 | 244, 197 | 118, 198 | 156, 199 | 196, 200 | 113, 201 | 5, 202 | 18, 203 | 10, 204 | 242, 205 | 85, 206 | 239, 207 | 109, 208 | 138, 209 | 32, 210 | 37, 211 | 117, 212 | 17, 213 | 6, 214 | 184, 215 | 125, 216 | 216, 217 | 16, 218 | 222, 219 | 201, 220 | 241, 221 | 41, 222 | 225, 223 | 95, 224 | 171, 225 | 115, 226 | 85, 227 | 114, 228 | 249, 229 | 152, 230 | 205, 231 | 71, 232 | 25, 233 | 89, 234 | ] 235 | -------------------------------------------------------------------------------- /common/cf-guest/src/consensus.rs: -------------------------------------------------------------------------------- 1 | use core::num::NonZeroU64; 2 | 3 | use ibc_primitives::proto::Any; 4 | use ibc_proto::Protobuf; 5 | use lib::hash::CryptoHash; 6 | 7 | use crate::proto; 8 | 9 | /// The consensus state of the guest blockchain as a Rust object. 10 | /// 11 | /// `From` and `TryFrom` conversions define mapping between this Rust object and 12 | /// corresponding Protocol Message [`proto::ConsensusState`]. 13 | #[derive(Clone, Debug, PartialEq, Eq)] 14 | pub struct ConsensusState { 15 | pub block_hash: ibc_core_commitment_types::commitment::CommitmentRoot, 16 | pub timestamp_ns: NonZeroU64, 17 | } 18 | 19 | impl ConsensusState { 20 | pub fn new(block_hash: &CryptoHash, timestamp_ns: NonZeroU64) -> Self { 21 | let block_hash = block_hash.as_array().to_vec().into(); 22 | Self { block_hash, timestamp_ns } 23 | } 24 | } 25 | 26 | impl ibc_core_client_context::consensus_state::ConsensusState 27 | for ConsensusState 28 | { 29 | fn root(&self) -> &ibc_core_commitment_types::commitment::CommitmentRoot { 30 | &self.block_hash 31 | } 32 | 33 | fn timestamp(&self) -> ibc_primitives::Timestamp { 34 | ibc_primitives::Timestamp::from_nanoseconds(self.timestamp_ns.get()) 35 | .unwrap() 36 | } 37 | 38 | fn encode_vec(self) -> alloc::vec::Vec { 39 | >::encode_vec(self) 40 | } 41 | } 42 | 43 | impl Protobuf for ConsensusState {} 44 | 45 | impl From<&crate::Header> for ConsensusState { 46 | fn from(header: &crate::Header) -> Self { 47 | Self { 48 | block_hash: header.block_hash.to_vec().into(), 49 | timestamp_ns: header.block_header.timestamp_ns, 50 | } 51 | } 52 | } 53 | 54 | impl From for proto::ConsensusState { 55 | fn from(state: ConsensusState) -> Self { 56 | Self { 57 | block_hash: state.block_hash.into_vec(), 58 | timestamp_ns: state.timestamp_ns.get(), 59 | } 60 | } 61 | } 62 | 63 | impl From<&ConsensusState> for proto::ConsensusState { 64 | fn from(state: &ConsensusState) -> Self { 65 | Self { 66 | block_hash: state.block_hash.as_bytes().to_vec(), 67 | timestamp_ns: state.timestamp_ns.get(), 68 | } 69 | } 70 | } 71 | 72 | impl TryFrom for ConsensusState { 73 | type Error = proto::BadMessage; 74 | fn try_from(msg: proto::ConsensusState) -> Result { 75 | <&CryptoHash>::try_from(msg.block_hash.as_slice()) 76 | .map_err(|_| proto::BadMessage)?; 77 | let timestamp_ns = 78 | NonZeroU64::new(msg.timestamp_ns).ok_or(proto::BadMessage)?; 79 | Ok(ConsensusState { block_hash: msg.block_hash.into(), timestamp_ns }) 80 | } 81 | } 82 | 83 | impl TryFrom<&proto::ConsensusState> for ConsensusState { 84 | type Error = proto::BadMessage; 85 | fn try_from(msg: &proto::ConsensusState) -> Result { 86 | let block_hash = <&CryptoHash>::try_from(msg.block_hash.as_slice()) 87 | .map_err(|_| proto::BadMessage)? 88 | .to_vec(); 89 | let timestamp_ns = 90 | NonZeroU64::new(msg.timestamp_ns).ok_or(proto::BadMessage)?; 91 | Ok(ConsensusState { block_hash: block_hash.into(), timestamp_ns }) 92 | } 93 | } 94 | 95 | proto_utils::define_wrapper! { 96 | proto: proto::ConsensusState, 97 | wrapper: ConsensusState, 98 | } 99 | -------------------------------------------------------------------------------- /common/cf-solana/src/consensus.rs: -------------------------------------------------------------------------------- 1 | use core::num::NonZeroU64; 2 | 3 | use ibc_primitives::proto::Any; 4 | use ibc_proto::Protobuf; 5 | use lib::hash::CryptoHash; 6 | 7 | use crate::proto; 8 | 9 | /// The consensus state of the SVM rollup blockchain as a Rust object. 10 | /// 11 | /// `From` and `TryFrom` conversions define mapping between this Rust object and 12 | /// corresponding Protocol Message [`proto::ConsensusState`]. 13 | #[derive(Clone, Debug, PartialEq, Eq)] 14 | pub struct ConsensusState { 15 | pub trie_root: ibc_core_commitment_types::commitment::CommitmentRoot, 16 | pub timestamp_sec: NonZeroU64, 17 | } 18 | 19 | impl ConsensusState { 20 | pub fn new(trie_root: &CryptoHash, timestamp_sec: NonZeroU64) -> Self { 21 | let trie_root = trie_root.as_array().to_vec().into(); 22 | Self { trie_root, timestamp_sec } 23 | } 24 | } 25 | 26 | impl ibc_core_client_context::consensus_state::ConsensusState 27 | for ConsensusState 28 | { 29 | fn root(&self) -> &ibc_core_commitment_types::commitment::CommitmentRoot { 30 | &self.trie_root 31 | } 32 | 33 | fn timestamp(&self) -> ibc_primitives::Timestamp { 34 | let ns = self.timestamp_sec.get() * 1_000_000_000; 35 | ibc_primitives::Timestamp::from_nanoseconds(ns).unwrap() 36 | } 37 | 38 | fn encode_vec(self) -> alloc::vec::Vec { 39 | >::encode_vec(self) 40 | } 41 | } 42 | 43 | impl Protobuf for ConsensusState {} 44 | 45 | impl TryFrom<&crate::Header> for ConsensusState { 46 | type Error = proto::BadMessage; 47 | 48 | fn try_from(header: &crate::Header) -> Result { 49 | header.decode_witness().ok_or(proto::BadMessage).map( 50 | |(trie_root, timestamp_sec)| Self::new(trie_root, timestamp_sec), 51 | ) 52 | } 53 | } 54 | 55 | impl From for proto::ConsensusState { 56 | fn from(state: ConsensusState) -> Self { 57 | Self { 58 | trie_root: state.trie_root.into_vec(), 59 | timestamp_sec: state.timestamp_sec.get(), 60 | } 61 | } 62 | } 63 | 64 | impl From<&ConsensusState> for proto::ConsensusState { 65 | fn from(state: &ConsensusState) -> Self { 66 | Self { 67 | trie_root: state.trie_root.as_bytes().to_vec(), 68 | timestamp_sec: state.timestamp_sec.get(), 69 | } 70 | } 71 | } 72 | 73 | impl TryFrom for ConsensusState { 74 | type Error = proto::BadMessage; 75 | fn try_from(msg: proto::ConsensusState) -> Result { 76 | if msg.trie_root.len() != CryptoHash::LENGTH { 77 | return Err(proto::BadMessage); 78 | } 79 | let timestamp_sec = NonZeroU64::new(msg.timestamp_sec); 80 | Ok(Self { 81 | trie_root: msg.trie_root.into(), 82 | timestamp_sec: timestamp_sec.ok_or(proto::BadMessage)?, 83 | }) 84 | } 85 | } 86 | 87 | impl TryFrom<&proto::ConsensusState> for ConsensusState { 88 | type Error = proto::BadMessage; 89 | fn try_from(msg: &proto::ConsensusState) -> Result { 90 | let trie_root = <&CryptoHash>::try_from(msg.trie_root.as_slice()) 91 | .map_err(|_| proto::BadMessage)?; 92 | let timestamp_sec = 93 | NonZeroU64::new(msg.timestamp_sec).ok_or(proto::BadMessage)?; 94 | Ok(Self::new(trie_root, timestamp_sec)) 95 | } 96 | } 97 | 98 | proto_utils::define_wrapper! { 99 | proto: proto::ConsensusState, 100 | wrapper: ConsensusState, 101 | } 102 | -------------------------------------------------------------------------------- /solana/solana-ibc/programs/solana-ibc/src/snapshots/solana_ibc__events__snapshot_tests__borsh_new_block_with_epoch.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: solana/solana-ibc/programs/solana-ibc/src/events.rs 3 | expression: serialised 4 | --- 5 | [ 6 | 2, 7 | 0, 8 | 0, 9 | 0, 10 | 0, 11 | 0, 12 | 0, 13 | 0, 14 | 0, 15 | 0, 16 | 0, 17 | 0, 18 | 0, 19 | 0, 20 | 0, 21 | 0, 22 | 0, 23 | 0, 24 | 0, 25 | 0, 26 | 0, 27 | 0, 28 | 0, 29 | 0, 30 | 0, 31 | 0, 32 | 0, 33 | 0, 34 | 0, 35 | 0, 36 | 0, 37 | 0, 38 | 0, 39 | 0, 40 | 0, 41 | 0, 42 | 0, 43 | 0, 44 | 0, 45 | 0, 46 | 0, 47 | 0, 48 | 42, 49 | 0, 50 | 0, 51 | 0, 52 | 0, 53 | 0, 54 | 0, 55 | 0, 56 | 24, 57 | 0, 58 | 0, 59 | 0, 60 | 0, 61 | 0, 62 | 0, 63 | 0, 64 | 0, 65 | 0, 66 | 0, 67 | 66, 68 | 0, 69 | 0, 70 | 0, 71 | 66, 72 | 0, 73 | 0, 74 | 0, 75 | 66, 76 | 0, 77 | 0, 78 | 0, 79 | 66, 80 | 0, 81 | 0, 82 | 0, 83 | 66, 84 | 0, 85 | 0, 86 | 0, 87 | 66, 88 | 0, 89 | 0, 90 | 0, 91 | 66, 92 | 0, 93 | 0, 94 | 0, 95 | 66, 96 | 0, 97 | 0, 98 | 0, 99 | 0, 100 | 0, 101 | 0, 102 | 0, 103 | 0, 104 | 0, 105 | 0, 106 | 0, 107 | 0, 108 | 0, 109 | 0, 110 | 0, 111 | 0, 112 | 0, 113 | 0, 114 | 0, 115 | 0, 116 | 0, 117 | 0, 118 | 0, 119 | 0, 120 | 0, 121 | 0, 122 | 0, 123 | 0, 124 | 0, 125 | 0, 126 | 0, 127 | 0, 128 | 1, 129 | 219, 130 | 192, 131 | 172, 132 | 39, 133 | 119, 134 | 107, 135 | 149, 136 | 47, 137 | 168, 138 | 161, 139 | 165, 140 | 238, 141 | 123, 142 | 171, 143 | 147, 144 | 83, 145 | 100, 146 | 62, 147 | 216, 148 | 182, 149 | 211, 150 | 163, 151 | 202, 152 | 167, 153 | 194, 154 | 157, 155 | 67, 156 | 41, 157 | 2, 158 | 87, 159 | 139, 160 | 43, 161 | 1, 162 | 0, 163 | 2, 164 | 0, 165 | 0, 166 | 0, 167 | 0, 168 | 0, 169 | 0, 170 | 0, 171 | 80, 172 | 0, 173 | 0, 174 | 0, 175 | 80, 176 | 0, 177 | 0, 178 | 0, 179 | 80, 180 | 0, 181 | 0, 182 | 0, 183 | 80, 184 | 0, 185 | 0, 186 | 0, 187 | 80, 188 | 0, 189 | 0, 190 | 0, 191 | 80, 192 | 0, 193 | 0, 194 | 0, 195 | 80, 196 | 0, 197 | 0, 198 | 0, 199 | 80, 200 | 10, 201 | 0, 202 | 0, 203 | 0, 204 | 0, 205 | 0, 206 | 0, 207 | 0, 208 | 0, 209 | 0, 210 | 0, 211 | 0, 212 | 0, 213 | 0, 214 | 0, 215 | 0, 216 | 0, 217 | 0, 218 | 0, 219 | 0, 220 | 81, 221 | 0, 222 | 0, 223 | 0, 224 | 81, 225 | 0, 226 | 0, 227 | 0, 228 | 81, 229 | 0, 230 | 0, 231 | 0, 232 | 81, 233 | 0, 234 | 0, 235 | 0, 236 | 81, 237 | 0, 238 | 0, 239 | 0, 240 | 81, 241 | 0, 242 | 0, 243 | 0, 244 | 81, 245 | 0, 246 | 0, 247 | 0, 248 | 81, 249 | 10, 250 | 0, 251 | 0, 252 | 0, 253 | 0, 254 | 0, 255 | 0, 256 | 0, 257 | 0, 258 | 0, 259 | 0, 260 | 0, 261 | 0, 262 | 0, 263 | 0, 264 | 0, 265 | 11, 266 | 0, 267 | 0, 268 | 0, 269 | 0, 270 | 0, 271 | 0, 272 | 0, 273 | 0, 274 | 0, 275 | 0, 276 | 0, 277 | 0, 278 | 0, 279 | 0, 280 | 0, 281 | ] 282 | -------------------------------------------------------------------------------- /solana/restaking/programs/restaking/src/validation.rs: -------------------------------------------------------------------------------- 1 | use anchor_lang::prelude::*; 2 | 3 | use crate::ErrorCodes; 4 | 5 | pub(crate) struct RemainingAccounts<'a, 'info> { 6 | pub chain: &'a AccountInfo<'info>, 7 | pub trie: &'a AccountInfo<'info>, 8 | #[cfg(feature = "witness")] 9 | pub witness: &'a AccountInfo<'info>, 10 | pub program: &'a AccountInfo<'info>, 11 | } 12 | 13 | /// Validates accounts needed for CPI call to the guest chain. 14 | /// 15 | /// Right now, this method would only validate accounts for calling `set_stake` 16 | /// method in the guest chain. Later when we expand to other services, we could 17 | /// extend this method below to do the validation for those accounts as well. 18 | /// 19 | /// Accounts needed for calling `set_stake` 20 | /// - chain: PDA with seeds ["chain"]. Must be writable. 21 | /// - trie: PDA with seeds ["trie"]. Must be writable. 22 | /// - witness: Only if compiled with `witness` Cargo feature. PDA with seeds 23 | /// `["witness", trie.key()]`. Must be writable. 24 | /// - guest chain program ID: Should match the expected guest chain program ID 25 | /// 26 | /// Note: The accounts should be sent in above order. 27 | pub(crate) fn validate_remaining_accounts<'a, 'info>( 28 | accounts: &'a [AccountInfo<'info>], 29 | expected_guest_chain_program_id: &Pubkey, 30 | ) -> Result> { 31 | let accounts = &mut accounts.iter(); 32 | 33 | // Chain account 34 | let chain = next_pda_account( 35 | accounts, 36 | [solana_ibc::CHAIN_SEED].as_ref(), 37 | expected_guest_chain_program_id, 38 | true, 39 | "chain", 40 | )?; 41 | 42 | // Trie account 43 | let trie = next_pda_account( 44 | accounts, 45 | [solana_ibc::TRIE_SEED].as_ref(), 46 | expected_guest_chain_program_id, 47 | true, 48 | "trie", 49 | )?; 50 | 51 | // Trie account 52 | #[cfg(feature = "witness")] 53 | let witness = next_pda_account( 54 | accounts, 55 | [solana_ibc::WITNESS_SEED, trie.key().as_ref()].as_ref(), 56 | expected_guest_chain_program_id, 57 | true, 58 | "witness", 59 | )?; 60 | 61 | // Guest chain program ID 62 | let program = next_account_info(accounts) 63 | .ok() 64 | .filter(|info| expected_guest_chain_program_id == info.key) 65 | .ok_or_else(|| error!(ErrorCodes::AccountValidationFailedForCPI))?; 66 | 67 | Ok(RemainingAccounts { 68 | chain, 69 | trie, 70 | program, 71 | #[cfg(feature = "witness")] 72 | witness, 73 | }) 74 | } 75 | 76 | fn next_pda_account<'a, 'info>( 77 | accounts: &mut impl core::iter::Iterator>, 78 | seeds: &[&[u8]], 79 | program_id: &Pubkey, 80 | must_be_mut: bool, 81 | account_name: &str, 82 | ) -> Result<&'a AccountInfo<'info>> { 83 | (|| { 84 | let info = next_account_info(accounts).ok()?; 85 | let addr = Pubkey::try_find_program_address(seeds, program_id)?.0; 86 | if &addr == info.key && (!must_be_mut || info.is_writable) { 87 | Some(info) 88 | } else { 89 | None 90 | } 91 | })() 92 | .ok_or_else(|| { 93 | error!(ErrorCodes::AccountValidationFailedForCPI) 94 | .with_account_name(account_name) 95 | }) 96 | } 97 | 98 | 99 | /// Verifies that given account is the Instruction sysvars and returns it if it 100 | /// is. 101 | pub(crate) fn check_instructions_sysvar<'info>( 102 | account: &AccountInfo<'info>, 103 | ) -> Result> { 104 | if solana_program::sysvar::instructions::check_id(account.key) { 105 | Ok(account.clone()) 106 | } else { 107 | Err(error!(ErrorCodes::AccountValidationFailedForCPI)) 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /common/sealable-trie/src/trie/seal.rs: -------------------------------------------------------------------------------- 1 | use super::{Error, Result}; 2 | use crate::bits; 3 | use crate::nodes::{Node, NodeRef, RawNode, Reference, ValueRef}; 4 | 5 | /// Context for [`super::Trie::seal`] operation. 6 | pub(super) struct Context<'a, A> { 7 | /// Part of the key yet to be traversed. 8 | /// 9 | /// It starts as the key user provided and as trie is traversed bits are 10 | /// removed from its front. 11 | key: bits::Slice<'a>, 12 | 13 | /// Allocator used to retrieve and free nodes. 14 | alloc: &'a mut A, 15 | } 16 | 17 | impl<'a, A: memory::Allocator> Context<'a, A> { 18 | pub(super) fn new(alloc: &'a mut A, key: bits::Slice<'a>) -> Self { 19 | Self { key, alloc } 20 | } 21 | 22 | /// Traverses the trie starting from node `ptr` to find node at context’s 23 | /// key and seals it. 24 | /// 25 | /// Returns `true` if node at `ptr` has been sealed. This lets caller know 26 | /// that `ptr` has been freed and it has to update references to it. 27 | pub(super) fn seal(&mut self, nref: NodeRef) -> Result { 28 | let ptr = nref.ptr.ok_or(Error::Sealed)?; 29 | let node = *self.alloc.get(ptr); 30 | let node = node.decode()?; 31 | debug_assert_eq!(*nref.hash, node.hash()); 32 | 33 | let result = match node { 34 | Node::Branch { children } => self.seal_branch(children), 35 | Node::Extension { key, child } => self.seal_extension(key, child), 36 | }?; 37 | 38 | match result { 39 | SealResult::Replace(node) => { 40 | self.alloc.set(ptr, node); 41 | Ok(false) 42 | } 43 | SealResult::Free => { 44 | self.alloc.free(ptr); 45 | Ok(true) 46 | } 47 | SealResult::Done => Ok(false), 48 | } 49 | } 50 | 51 | fn seal_branch( 52 | &mut self, 53 | mut children: [Reference; 2], 54 | ) -> Result { 55 | let side = usize::from(self.key.pop_front().ok_or(Error::NotFound)?); 56 | match self.seal_child(children[side])? { 57 | None => Ok(SealResult::Done), 58 | Some(_) if children[1 - side].is_sealed() => Ok(SealResult::Free), 59 | Some(child) => { 60 | children[side] = child; 61 | let node = RawNode::branch(children[0], children[1]); 62 | Ok(SealResult::Replace(node)) 63 | } 64 | } 65 | } 66 | 67 | fn seal_extension( 68 | &mut self, 69 | ext_key: bits::ExtKey, 70 | child: Reference, 71 | ) -> Result { 72 | if !self.key.strip_prefix(ext_key.into()) { 73 | Err(Error::NotFound) 74 | } else if let Some(child) = self.seal_child(child)? { 75 | Ok(SealResult::Replace(RawNode::extension(ext_key, child))) 76 | } else { 77 | Ok(SealResult::Done) 78 | } 79 | } 80 | 81 | fn seal_child<'b>( 82 | &mut self, 83 | child: Reference<'b>, 84 | ) -> Result>> { 85 | match child { 86 | Reference::Node(node) => Ok(if self.seal(node)? { 87 | Some(NodeRef::new(None, node.hash).into()) 88 | } else { 89 | None 90 | }), 91 | Reference::Value(value) => { 92 | if value.is_sealed { 93 | Err(Error::Sealed) 94 | } else if self.key.is_empty() { 95 | Ok(Some(ValueRef::new(true, value.hash).into())) 96 | } else { 97 | Err(Error::NotFound) 98 | } 99 | } 100 | } 101 | } 102 | } 103 | 104 | enum SealResult { 105 | Free, 106 | Replace(RawNode), 107 | Done, 108 | } 109 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | ## Composable Finance Business License 1.0 2 | 3 | ### Parameters 4 | 5 | **Licensor:** Composable Finance Ltd. 6 | **Licensed Work:** Emulated Light Client 7 | **Date of License Change:** August 20, 2024 8 | **Changed License:** GNU General Public License v2.0 or later 9 | **Other Permitted Use:** N/A 10 | 11 | ### Notice 12 | 13 | Under the Composable Finance Business License 1.0 (the "License"), use of any code, text, file or anything found within this repository in relation to the Licensed Work, may be granted to a Licensee under the terms of this notice and other applicable agreements and documents (the "Notice"). 14 | 15 | The License is not open source in nature but it is intended to eventually become open source under the terms set forth herein. 16 | 17 | ### Terms 18 | 19 | 1. Unauthorized use, copying, modification, creation of derivative works, and redistribution of the Licensed Work by third parties is prohibited without obtaining a License from the Licensor. 20 | 21 | 1. A License shall be granted to you which shall come with certain rights and obligations under a licensing agreement entered or to be entered by you and the Licensor (the "Licensing Agreement"). The License shall be a commercial, non-exclusive, non-sublicensable, and non-transferable license to use the Licensed Work, subject to all the terms, conditions, duration, and restrictions under the underlying Licensing Agreement. Any use of the Licensed Work in violation of the License will automatically terminate your rights under the License for the current and all other versions of the Licensed Work. 22 | 23 | 1. These Terms shall be subject to the Parameters above which are specifically described below as follows: 24 | 25 | 1. Licensor: The author, inventor, assignee, or owner or of the Licensed Work. 26 | 2. Licensed Work: The licensed software or work of the Licensor subject to the License. 27 | 3. Date of License Change: The date when the License is converted to the Changed License. 28 | 4. Changed License: The license type to which the License will be converted to on the Date of License Change. 29 | 5. Other Permitted Use: The uses or rights specifically granted to you beyond those stated in this Notice and as may be allowed under the Licensing Agreement. 30 | 31 | 1. Effective on the Date of License Change, your rights and obligations shall be governed by the terms and conditions of the Changed License, and the rights granted to you under this License shall terminate. 32 | 33 | 1. All copies of the original and modified Licensed Work, and derivative work of the Licensed Work, shall be subject to this License. This License shall apply separately for each version of the Licensed Work and the Date of License Change may vary for each version of the Licensed Work released by the Licensor. 34 | 35 | 1. The License does not grant you any right in any trademark or logo of Licensor or its affiliates. Provided that, you may use a trademark or logo of the Licensor if expressly allowed or required by the Licensing Agreement. 36 | 37 | 1. TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK SHALL BE PROVIDED ON AN "AS IS" BASIS. THE LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND TITLE. 38 | 39 | 1. You shall be required to conspicuously display this Notice on each original or modified copy of the Licensed Work. 40 | 41 | 1. The Terms in this Notice shall be consistent with the more comprehensive set of terms, conditions, restrictions and limitations of the Licensing Agreement executed or to be executed between you and the Licensor. In case of conflict, the terms of the License Agreement shall prevail over this Notice. 42 | 43 | ### Copyright on License Text 44 | 45 | Composable Finance shall grant you the permission to use this Notice's text for your works that make use of the Licensed Work, and to refer to it using the trademark "Composable Finance Business License 1.0" for the limited purpose of referring to the License and complying with the requirements of its display. -------------------------------------------------------------------------------- /common/cf-solana/src/snapshots/cf_solana__proto__header.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: common/cf-solana/src/proto.rs 3 | expression: any.value 4 | --- 5 | [ 6 | 8, 7 | 164, 8 | 3, 9 | 18, 10 | 32, 11 | 157, 12 | 243, 13 | 27, 14 | 218, 15 | 35, 16 | 225, 17 | 81, 18 | 184, 19 | 17, 20 | 215, 21 | 213, 22 | 30, 23 | 103, 24 | 31, 25 | 41, 26 | 142, 27 | 149, 28 | 250, 29 | 32, 30 | 35, 31 | 236, 32 | 143, 33 | 22, 34 | 40, 35 | 55, 36 | 112, 37 | 43, 38 | 152, 39 | 16, 40 | 240, 41 | 240, 42 | 236, 43 | 26, 44 | 104, 45 | 5, 46 | 5, 47 | 5, 48 | 5, 49 | 5, 50 | 5, 51 | 5, 52 | 5, 53 | 5, 54 | 5, 55 | 5, 56 | 5, 57 | 5, 58 | 5, 59 | 5, 60 | 5, 61 | 5, 62 | 5, 63 | 5, 64 | 5, 65 | 5, 66 | 5, 67 | 5, 68 | 5, 69 | 5, 70 | 5, 71 | 5, 72 | 5, 73 | 5, 74 | 5, 75 | 5, 76 | 5, 77 | 46, 78 | 136, 79 | 74, 80 | 227, 81 | 226, 82 | 95, 83 | 156, 84 | 84, 85 | 212, 86 | 15, 87 | 100, 88 | 22, 89 | 107, 90 | 113, 91 | 141, 92 | 233, 93 | 97, 94 | 30, 95 | 251, 96 | 214, 97 | 34, 98 | 15, 99 | 3, 100 | 29, 101 | 140, 102 | 222, 103 | 178, 104 | 184, 105 | 220, 106 | 237, 107 | 139, 108 | 173, 109 | 164, 110 | 1, 111 | 0, 112 | 0, 113 | 0, 114 | 0, 115 | 0, 116 | 0, 117 | 6, 118 | 6, 119 | 6, 120 | 6, 121 | 6, 122 | 6, 123 | 6, 124 | 6, 125 | 6, 126 | 6, 127 | 6, 128 | 6, 129 | 6, 130 | 6, 131 | 6, 132 | 6, 133 | 6, 134 | 6, 135 | 6, 136 | 6, 137 | 6, 138 | 6, 139 | 6, 140 | 6, 141 | 6, 142 | 6, 143 | 6, 144 | 6, 145 | 6, 146 | 6, 147 | 6, 148 | 6, 149 | 34, 150 | 81, 151 | 42, 152 | 0, 153 | 0, 154 | 0, 155 | 0, 156 | 0, 157 | 0, 158 | 0, 159 | 255, 160 | 255, 161 | 255, 162 | 255, 163 | 255, 164 | 255, 165 | 255, 166 | 255, 167 | 0, 168 | 69, 169 | 69, 170 | 69, 171 | 69, 172 | 69, 173 | 69, 174 | 69, 175 | 69, 176 | 69, 177 | 69, 178 | 69, 179 | 69, 180 | 69, 181 | 69, 182 | 69, 183 | 69, 184 | 69, 185 | 69, 186 | 69, 187 | 69, 188 | 69, 189 | 69, 190 | 69, 191 | 69, 192 | 69, 193 | 69, 194 | 69, 195 | 69, 196 | 69, 197 | 69, 198 | 69, 199 | 69, 200 | 10, 201 | 10, 202 | 10, 203 | 10, 204 | 10, 205 | 10, 206 | 10, 207 | 10, 208 | 10, 209 | 10, 210 | 10, 211 | 10, 212 | 10, 213 | 10, 214 | 10, 215 | 10, 216 | 10, 217 | 10, 218 | 10, 219 | 10, 220 | 10, 221 | 10, 222 | 10, 223 | 10, 224 | 10, 225 | 10, 226 | 10, 227 | 10, 228 | 10, 229 | 10, 230 | 10, 231 | 10, 232 | 42, 233 | 66, 234 | 1, 235 | 18, 236 | 42, 237 | 42, 238 | 42, 239 | 42, 240 | 42, 241 | 42, 242 | 42, 243 | 42, 244 | 42, 245 | 42, 246 | 42, 247 | 42, 248 | 42, 249 | 42, 250 | 42, 251 | 42, 252 | 42, 253 | 42, 254 | 42, 255 | 42, 256 | 42, 257 | 42, 258 | 42, 259 | 42, 260 | 42, 261 | 42, 262 | 42, 263 | 42, 264 | 42, 265 | 42, 266 | 42, 267 | 42, 268 | 69, 269 | 69, 270 | 69, 271 | 69, 272 | 69, 273 | 69, 274 | 69, 275 | 69, 276 | 69, 277 | 69, 278 | 69, 279 | 69, 280 | 69, 281 | 69, 282 | 69, 283 | 69, 284 | 69, 285 | 69, 286 | 69, 287 | 69, 288 | 69, 289 | 69, 290 | 69, 291 | 69, 292 | 69, 293 | 69, 294 | 69, 295 | 69, 296 | 69, 297 | 69, 298 | 69, 299 | 69, 300 | ] 301 | -------------------------------------------------------------------------------- /common/cf-solana/src/snapshots/cf_solana__proto__client_message.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: common/cf-solana/src/proto.rs 3 | expression: any.value 4 | --- 5 | [ 6 | 10, 7 | 166, 8 | 2, 9 | 8, 10 | 164, 11 | 3, 12 | 18, 13 | 32, 14 | 157, 15 | 243, 16 | 27, 17 | 218, 18 | 35, 19 | 225, 20 | 81, 21 | 184, 22 | 17, 23 | 215, 24 | 213, 25 | 30, 26 | 103, 27 | 31, 28 | 41, 29 | 142, 30 | 149, 31 | 250, 32 | 32, 33 | 35, 34 | 236, 35 | 143, 36 | 22, 37 | 40, 38 | 55, 39 | 112, 40 | 43, 41 | 152, 42 | 16, 43 | 240, 44 | 240, 45 | 236, 46 | 26, 47 | 104, 48 | 5, 49 | 5, 50 | 5, 51 | 5, 52 | 5, 53 | 5, 54 | 5, 55 | 5, 56 | 5, 57 | 5, 58 | 5, 59 | 5, 60 | 5, 61 | 5, 62 | 5, 63 | 5, 64 | 5, 65 | 5, 66 | 5, 67 | 5, 68 | 5, 69 | 5, 70 | 5, 71 | 5, 72 | 5, 73 | 5, 74 | 5, 75 | 5, 76 | 5, 77 | 5, 78 | 5, 79 | 5, 80 | 46, 81 | 136, 82 | 74, 83 | 227, 84 | 226, 85 | 95, 86 | 156, 87 | 84, 88 | 212, 89 | 15, 90 | 100, 91 | 22, 92 | 107, 93 | 113, 94 | 141, 95 | 233, 96 | 97, 97 | 30, 98 | 251, 99 | 214, 100 | 34, 101 | 15, 102 | 3, 103 | 29, 104 | 140, 105 | 222, 106 | 178, 107 | 184, 108 | 220, 109 | 237, 110 | 139, 111 | 173, 112 | 164, 113 | 1, 114 | 0, 115 | 0, 116 | 0, 117 | 0, 118 | 0, 119 | 0, 120 | 6, 121 | 6, 122 | 6, 123 | 6, 124 | 6, 125 | 6, 126 | 6, 127 | 6, 128 | 6, 129 | 6, 130 | 6, 131 | 6, 132 | 6, 133 | 6, 134 | 6, 135 | 6, 136 | 6, 137 | 6, 138 | 6, 139 | 6, 140 | 6, 141 | 6, 142 | 6, 143 | 6, 144 | 6, 145 | 6, 146 | 6, 147 | 6, 148 | 6, 149 | 6, 150 | 6, 151 | 6, 152 | 34, 153 | 81, 154 | 42, 155 | 0, 156 | 0, 157 | 0, 158 | 0, 159 | 0, 160 | 0, 161 | 0, 162 | 255, 163 | 255, 164 | 255, 165 | 255, 166 | 255, 167 | 255, 168 | 255, 169 | 255, 170 | 0, 171 | 69, 172 | 69, 173 | 69, 174 | 69, 175 | 69, 176 | 69, 177 | 69, 178 | 69, 179 | 69, 180 | 69, 181 | 69, 182 | 69, 183 | 69, 184 | 69, 185 | 69, 186 | 69, 187 | 69, 188 | 69, 189 | 69, 190 | 69, 191 | 69, 192 | 69, 193 | 69, 194 | 69, 195 | 69, 196 | 69, 197 | 69, 198 | 69, 199 | 69, 200 | 69, 201 | 69, 202 | 69, 203 | 10, 204 | 10, 205 | 10, 206 | 10, 207 | 10, 208 | 10, 209 | 10, 210 | 10, 211 | 10, 212 | 10, 213 | 10, 214 | 10, 215 | 10, 216 | 10, 217 | 10, 218 | 10, 219 | 10, 220 | 10, 221 | 10, 222 | 10, 223 | 10, 224 | 10, 225 | 10, 226 | 10, 227 | 10, 228 | 10, 229 | 10, 230 | 10, 231 | 10, 232 | 10, 233 | 10, 234 | 10, 235 | 42, 236 | 66, 237 | 1, 238 | 18, 239 | 42, 240 | 42, 241 | 42, 242 | 42, 243 | 42, 244 | 42, 245 | 42, 246 | 42, 247 | 42, 248 | 42, 249 | 42, 250 | 42, 251 | 42, 252 | 42, 253 | 42, 254 | 42, 255 | 42, 256 | 42, 257 | 42, 258 | 42, 259 | 42, 260 | 42, 261 | 42, 262 | 42, 263 | 42, 264 | 42, 265 | 42, 266 | 42, 267 | 42, 268 | 42, 269 | 42, 270 | 42, 271 | 69, 272 | 69, 273 | 69, 274 | 69, 275 | 69, 276 | 69, 277 | 69, 278 | 69, 279 | 69, 280 | 69, 281 | 69, 282 | 69, 283 | 69, 284 | 69, 285 | 69, 286 | 69, 287 | 69, 288 | 69, 289 | 69, 290 | 69, 291 | 69, 292 | 69, 293 | 69, 294 | 69, 295 | 69, 296 | 69, 297 | 69, 298 | 69, 299 | 69, 300 | 69, 301 | 69, 302 | 69, 303 | ] 304 | -------------------------------------------------------------------------------- /solana/trie/src/data_ref.rs: -------------------------------------------------------------------------------- 1 | /// Access to the account data underlying the trie. 2 | pub trait DataRef { 3 | /// Returns size of the referenced data in bytes. 4 | fn len(&self) -> usize; 5 | 6 | /// Returns whether the data is empty. 7 | fn is_empty(&self) -> bool { self.len() == 0 } 8 | 9 | /// Returns a shared reference to a byte or subslice depending on the type 10 | /// of index. 11 | /// 12 | /// Returns `None` if index is out of bounds. 13 | fn get>( 14 | &self, 15 | index: I, 16 | ) -> Option<&I::Output>; 17 | 18 | /// Returns a shared reference to a byte or subslice depending on the type 19 | /// of index. 20 | /// 21 | /// Returns `None` if index is out of bounds. 22 | fn get_mut>( 23 | &mut self, 24 | index: I, 25 | ) -> Option<&mut I::Output>; 26 | 27 | /// Increases the size of the data to at least given size; returns whether 28 | /// resizing was successful. 29 | fn enlarge(&mut self, min_size: usize) -> bool; 30 | } 31 | 32 | impl DataRef for [u8] { 33 | #[inline] 34 | fn len(&self) -> usize { (*self).len() } 35 | 36 | fn get>( 37 | &self, 38 | index: I, 39 | ) -> Option<&I::Output> { 40 | self.get(index) 41 | } 42 | 43 | fn get_mut>( 44 | &mut self, 45 | index: I, 46 | ) -> Option<&mut I::Output> { 47 | self.get_mut(index) 48 | } 49 | 50 | #[inline] 51 | fn enlarge(&mut self, _min_size: usize) -> bool { false } 52 | } 53 | 54 | impl DataRef for [u8; N] { 55 | #[inline] 56 | fn len(&self) -> usize { N } 57 | 58 | fn get>( 59 | &self, 60 | index: I, 61 | ) -> Option<&I::Output> { 62 | self[..].get(index) 63 | } 64 | 65 | fn get_mut>( 66 | &mut self, 67 | index: I, 68 | ) -> Option<&mut I::Output> { 69 | self[..].get_mut(index) 70 | } 71 | 72 | #[inline] 73 | fn enlarge(&mut self, _min_size: usize) -> bool { false } 74 | } 75 | 76 | impl DataRef for Vec { 77 | #[inline] 78 | fn len(&self) -> usize { (**self).len() } 79 | 80 | fn get>( 81 | &self, 82 | index: I, 83 | ) -> Option<&I::Output> { 84 | (**self).get(index) 85 | } 86 | 87 | fn get_mut>( 88 | &mut self, 89 | index: I, 90 | ) -> Option<&mut I::Output> { 91 | (**self).get_mut(index) 92 | } 93 | 94 | #[inline] 95 | fn enlarge(&mut self, min_size: usize) -> bool { 96 | let additional = min_size.saturating_sub(self.len()); 97 | if additional == 0 { 98 | true 99 | } else if self.try_reserve(additional).is_ok() { 100 | self.resize(min_size, 0); 101 | true 102 | } else { 103 | false 104 | } 105 | } 106 | } 107 | 108 | impl DataRef for &'_ mut D { 109 | fn len(&self) -> usize { (**self).len() } 110 | 111 | fn get>( 112 | &self, 113 | index: I, 114 | ) -> Option<&I::Output> { 115 | (**self).get(index) 116 | } 117 | 118 | fn get_mut>( 119 | &mut self, 120 | index: I, 121 | ) -> Option<&mut I::Output> { 122 | (**self).get_mut(index) 123 | } 124 | 125 | #[inline] 126 | fn enlarge(&mut self, min_size: usize) -> bool { 127 | (**self).enlarge(min_size) 128 | } 129 | } 130 | 131 | impl DataRef for core::cell::RefMut<'_, D> { 132 | #[inline] 133 | fn len(&self) -> usize { (**self).len() } 134 | 135 | fn get>( 136 | &self, 137 | index: I, 138 | ) -> Option<&I::Output> { 139 | (**self).get(index) 140 | } 141 | 142 | fn get_mut>( 143 | &mut self, 144 | index: I, 145 | ) -> Option<&mut I::Output> { 146 | (**self).get_mut(index) 147 | } 148 | 149 | #[inline] 150 | fn enlarge(&mut self, _min_size: usize) -> bool { false } 151 | } 152 | -------------------------------------------------------------------------------- /common/stdx/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Crate contains polyfills which should really be in standard library, but 2 | //! currently aren't. 3 | //! 4 | //! Unstable features of the standard library are good candidates to be included 5 | //! in this crate. Once such features stabilise they should be removed from 6 | //! this crate and clients updated to use newly stabilised functions instead. 7 | //! 8 | //! For other functions `lib` crate might be a better fit. 9 | 10 | #![allow(clippy::let_unit_value)] 11 | 12 | /// Splits `&[u8; L + R]` into `(&[u8; L], &[u8; R])`. 13 | pub fn split_array_ref( 14 | xs: &[u8; N], 15 | ) -> (&[u8; L], &[u8; R]) { 16 | let () = AssertEqSum::::OK; 17 | 18 | let (left, right) = xs.split_at(L); 19 | (left.try_into().unwrap(), right.try_into().unwrap()) 20 | } 21 | 22 | /// Splits `&mut [u8; L + R]` into `(&mut [u8; L], &mut [u8; R])`. 23 | pub fn split_array_mut( 24 | xs: &mut [u8; N], 25 | ) -> (&mut [u8; L], &mut [u8; R]) { 26 | let () = AssertEqSum::::OK; 27 | 28 | let (left, right) = xs.split_at_mut(L); 29 | (left.try_into().unwrap(), right.try_into().unwrap()) 30 | } 31 | 32 | /// Divides one slice into two at an index, returning None if the slice is too 33 | /// short. 34 | // TODO(mina86): Use [T]::split_at_checked once that stabilises. 35 | pub fn split_at_checked(slice: &[T], mid: usize) -> Option<(&[T], &[T])> { 36 | (mid <= slice.len()).then(|| slice.split_at(mid)) 37 | } 38 | 39 | /// Divides one slice into two at an index, returning None if the slice is too 40 | /// short. 41 | // TODO(mina86): Use [T]::split_at_mut_checked once that stabilises. 42 | pub fn split_at_mut_checked( 43 | slice: &mut [T], 44 | mid: usize, 45 | ) -> Option<(&mut [T], &mut [T])> { 46 | (mid <= slice.len()).then(|| slice.split_at_mut(mid)) 47 | } 48 | 49 | /// Splits `&[T]` into `(&[T; L], &[T])`. Returns `None` if input is too 50 | /// shorter. 51 | pub fn split_at(xs: &[T]) -> Option<(&[T; L], &[T])> { 52 | split_at_checked(xs, L).map(|(head, tail)| (head.try_into().unwrap(), tail)) 53 | } 54 | 55 | /// Splits `&mut [T]` into `(&mut [T; L], &mut [T])`. Returns `None` if input is too 56 | /// shorter. 57 | pub fn split_at_mut( 58 | xs: &mut [T], 59 | ) -> Option<(&mut [T; L], &mut [T])> { 60 | split_at_mut_checked(xs, L) 61 | .map(|(head, tail)| (head.try_into().unwrap(), tail)) 62 | } 63 | 64 | /// Splits `&[u8]` into `(&[u8], &[u8; R])`. Returns `None` if input is too 65 | /// shorter. 66 | #[allow(dead_code)] 67 | pub fn rsplit_at(xs: &[u8]) -> Option<(&[u8], &[u8; R])> { 68 | let (head, tail) = xs.split_at(xs.len().checked_sub(R)?); 69 | Some((head, tail.try_into().unwrap())) 70 | } 71 | 72 | /// Splits a slice into a slice of N-element arrays. 73 | pub fn as_chunks(slice: &[T]) -> (&[[T; N]], &[T]) { 74 | let () = AssertNonZero::::OK; 75 | 76 | let len = slice.len() / N; 77 | let (head, tail) = slice.split_at(len * N); 78 | 79 | // SAFETY: We cast a slice of `len * N` elements into a slice of `len` many 80 | // `N` elements chunks. 81 | let head = unsafe { std::slice::from_raw_parts(head.as_ptr().cast(), len) }; 82 | (head, tail) 83 | } 84 | 85 | /// Splits a slice into a slice of N-element arrays. 86 | pub fn as_chunks_mut( 87 | slice: &mut [T], 88 | ) -> (&mut [[T; N]], &mut [T]) { 89 | let () = AssertNonZero::::OK; 90 | 91 | let len = slice.len() / N; 92 | let (head, tail) = slice.split_at_mut(len * N); 93 | 94 | // SAFETY: We cast a slice of `len * N` elements into a slice of `len` many 95 | // `N` elements chunks. 96 | let head = unsafe { 97 | std::slice::from_raw_parts_mut(head.as_mut_ptr().cast(), len) 98 | }; 99 | (head, tail) 100 | } 101 | 102 | /// Asserts, at compile time, that `A + B == S`. 103 | struct AssertEqSum; 104 | impl AssertEqSum { 105 | const OK: () = assert!(S == A + B); 106 | } 107 | 108 | /// Asserts, at compile time, that `N` is non-zero. 109 | struct AssertNonZero; 110 | impl AssertNonZero { 111 | const OK: () = assert!(N != 0); 112 | } 113 | -------------------------------------------------------------------------------- /solana/witnessed-trie/src/contract.rs: -------------------------------------------------------------------------------- 1 | use solana_program::account_info::AccountInfo; 2 | use solana_program::program_error::ProgramError; 3 | use solana_program::pubkey::Pubkey; 4 | 5 | use crate::{accounts, api, utils}; 6 | 7 | type Result = core::result::Result; 8 | 9 | /// Smart contract’s entrypoint. 10 | /// 11 | /// Performs specified operations on the specified trie and updates witness’ 12 | /// account to store the new trie commitment hash. Data stored in the witness 13 | /// account is 14 | /// 15 | /// `accounts`: 16 | /// 1. The payer account which will pay rent for the accounts if they need to be 17 | /// created or resized. Must be a signer and writable. 18 | /// 2. The trie root account. Must be a PDA with seed `["root", root_seed]` and 19 | /// bump `root_bump` (where `root_seed` and `root_bump` are taken from 20 | /// `instruction` data. Must be writable if any changes are made to the 21 | /// trie. 22 | /// 3. The witness account. Must be a PDA with seed `["witness", root]` 23 | /// where `root` is the address of the root account. Must be writable. 24 | /// 4. System program. Needed to initialise and resize trie accounts. Smart 25 | /// contract doesn’t check for this account but if it’s not passed when 26 | /// required cross-program invocations will fail with unknown program error. 27 | /// 28 | /// `instruction`: 29 | /// | root_seed_len | u8 | Length of the root PDA seed. 30 | /// | root_seed | [u8; root_seed_len] | The root PDA seed. 31 | /// | root_bump | u8 | The root PDA bump. 32 | /// | data_accounts | u8 | Currently always one. 33 | /// | operations | [Op] | Operations to perform on the 34 | /// | | | trie. 35 | pub(crate) fn process_instruction( 36 | program_id: &Pubkey, 37 | accounts: &[AccountInfo], 38 | instruction: &[u8], 39 | ) -> Result { 40 | let data = api::Data::from_slice(instruction)?; 41 | 42 | // Get the accounts (trie root and witness) 43 | let (mut trie, witness) = { 44 | let accounts = &mut accounts.iter(); 45 | let payer = accounts::get_payer(accounts)?; 46 | let root = accounts::get_root( 47 | payer, 48 | accounts, 49 | program_id, 50 | data.root_seed, 51 | data.root_bump, 52 | )?; 53 | let witness = accounts::get_witness(payer, accounts, program_id, root)?; 54 | let trie = solana_trie::TrieAccount::new(root.try_borrow_mut_data()?) 55 | .ok_or(ProgramError::InvalidAccountData)? 56 | .with_witness_account(witness, program_id)?; 57 | 58 | (trie, witness) 59 | }; 60 | 61 | // Process operations 62 | for op in data.ops { 63 | match op { 64 | api::Op::Set(key, hash) => trie.set(key, hash), 65 | api::Op::Del(key) => trie.del(key).map(|_| ()), 66 | api::Op::Seal(key) => trie.seal(key), 67 | } 68 | .map_err(|err| { 69 | solana_program::msg!("0x{}: {}", hex::display(&op.key()), err); 70 | ProgramError::Custom(1) 71 | })?; 72 | } 73 | 74 | // Drop the trie so that witness is updated. 75 | core::mem::drop(trie); 76 | 77 | // Return enough information so that witness account can be hashed. 78 | let ret = api::ReturnData { 79 | lamports: witness.lamports().to_le_bytes(), 80 | rent_epoch: witness.rent_epoch.to_le_bytes(), 81 | data: api::WitnessData::try_from(&**witness.try_borrow_data()?) 82 | .unwrap(), 83 | }; 84 | solana_program::program::set_return_data(bytemuck::bytes_of(&ret)); 85 | 86 | Ok(()) 87 | } 88 | 89 | impl From for ProgramError { 90 | fn from(err: utils::DataTooShort) -> Self { 91 | solana_program::log::sol_log(&err.to_string()); 92 | Self::InvalidInstructionData 93 | } 94 | } 95 | 96 | impl From for ProgramError { 97 | fn from(err: api::ParseError) -> Self { 98 | solana_program::log::sol_log(&err.to_string()); 99 | Self::InvalidInstructionData 100 | } 101 | } 102 | 103 | solana_program::entrypoint!(start); 104 | 105 | fn start( 106 | program_id: &solana_program::pubkey::Pubkey, 107 | accounts: &[solana_program::account_info::AccountInfo], 108 | instruction: &[u8], 109 | ) -> Result<(), solana_program::program_error::ProgramError> { 110 | process_instruction(program_id, accounts, instruction) 111 | } 112 | -------------------------------------------------------------------------------- /solana/signature-verifier/src/ed25519.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "guest")] 2 | extern crate alloc; 3 | 4 | use core::fmt; 5 | 6 | /// An Ed25519 public key used by guest validators to sign guest blocks. 7 | #[derive( 8 | Clone, 9 | PartialEq, 10 | Eq, 11 | PartialOrd, 12 | Ord, 13 | Hash, 14 | bytemuck::TransparentWrapper, 15 | derive_more::AsRef, 16 | derive_more::From, 17 | derive_more::Into, 18 | )] 19 | #[cfg_attr( 20 | feature = "borsh", 21 | derive(borsh::BorshSerialize, borsh::BorshDeserialize) 22 | )] 23 | #[repr(transparent)] 24 | pub struct PubKey([u8; 32]); 25 | 26 | impl PubKey { 27 | pub const LENGTH: usize = 32; 28 | } 29 | 30 | impl<'a> TryFrom<&'a [u8]> for &'a PubKey { 31 | type Error = core::array::TryFromSliceError; 32 | fn try_from(bytes: &'a [u8]) -> Result { 33 | <&[u8; PubKey::LENGTH]>::try_from(bytes) 34 | .map(bytemuck::TransparentWrapper::wrap_ref) 35 | } 36 | } 37 | 38 | impl From for PubKey { 39 | fn from(pubkey: solana_program::pubkey::Pubkey) -> Self { 40 | Self(pubkey.to_bytes()) 41 | } 42 | } 43 | 44 | impl From for solana_program::pubkey::Pubkey { 45 | fn from(pubkey: PubKey) -> Self { Self::from(pubkey.0) } 46 | } 47 | 48 | impl PartialEq for PubKey { 49 | fn eq(&self, other: &solana_program::pubkey::Pubkey) -> bool { 50 | &self.0[..] == other.as_ref() 51 | } 52 | } 53 | 54 | impl PartialEq for solana_program::pubkey::Pubkey { 55 | fn eq(&self, other: &PubKey) -> bool { self.as_ref() == &other.0[..] } 56 | } 57 | 58 | #[cfg(feature = "guest")] 59 | impl guestchain::PubKey for PubKey { 60 | type Signature = Signature; 61 | 62 | #[inline] 63 | fn as_bytes(&self) -> alloc::borrow::Cow<'_, [u8]> { (&self.0[..]).into() } 64 | #[inline] 65 | fn from_bytes(bytes: &[u8]) -> Result { 66 | Ok(Self(bytes.try_into()?)) 67 | } 68 | } 69 | 70 | /// A Ed25519 signature of a guest block. 71 | #[derive( 72 | Clone, 73 | PartialEq, 74 | Eq, 75 | PartialOrd, 76 | Ord, 77 | Hash, 78 | bytemuck::TransparentWrapper, 79 | derive_more::AsRef, 80 | derive_more::From, 81 | derive_more::Into, 82 | )] 83 | #[cfg_attr( 84 | feature = "borsh", 85 | derive(borsh::BorshSerialize, borsh::BorshDeserialize) 86 | )] 87 | #[repr(transparent)] 88 | pub struct Signature([u8; 64]); 89 | 90 | impl Signature { 91 | pub const LENGTH: usize = 64; 92 | } 93 | 94 | impl<'a> TryFrom<&'a [u8]> for &'a Signature { 95 | type Error = core::array::TryFromSliceError; 96 | fn try_from(bytes: &'a [u8]) -> Result { 97 | <&[u8; Signature::LENGTH]>::try_from(bytes) 98 | .map(bytemuck::TransparentWrapper::wrap_ref) 99 | } 100 | } 101 | 102 | #[cfg(feature = "guest")] 103 | impl guestchain::Signature for Signature { 104 | #[inline] 105 | fn as_bytes(&self) -> alloc::borrow::Cow<'_, [u8]> { (&self.0[..]).into() } 106 | #[inline] 107 | fn from_bytes(bytes: &[u8]) -> Result { 108 | Ok(Self(bytes.try_into()?)) 109 | } 110 | } 111 | 112 | macro_rules! fmt_impl { 113 | (impl $trait:ident for $ty:ident, $func_name:ident) => { 114 | impl fmt::$trait for $ty { 115 | #[inline] 116 | fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result { 117 | $func_name(&self.0, fmtr) 118 | } 119 | } 120 | }; 121 | } 122 | 123 | fmt_impl!(impl Display for PubKey, base58_display); 124 | fmt_impl!(impl Debug for PubKey, base58_display); 125 | fmt_impl!(impl Display for Signature, base64_display); 126 | fmt_impl!(impl Debug for Signature, base64_display); 127 | 128 | /// Displays slice using base64 encoding. Slice must be at most 64 bytes 129 | /// (i.e. length of a signature). 130 | fn base64_display(bytes: &[u8; 64], fmtr: &mut fmt::Formatter) -> fmt::Result { 131 | use base64::engine::general_purpose::STANDARD as BASE64_ENGINE; 132 | use base64::Engine; 133 | 134 | let mut buf = [0u8; (64 + 2) / 3 * 4]; 135 | let len = BASE64_ENGINE.encode_slice(bytes, &mut buf[..]).unwrap(); 136 | // SAFETY: base64 fills the buffer with ASCII characters only. 137 | fmtr.write_str(unsafe { core::str::from_utf8_unchecked(&buf[..len]) }) 138 | } 139 | 140 | /// Displays slice using base58 encoding. 141 | fn base58_display(bytes: &[u8; 32], fmtr: &mut fmt::Formatter) -> fmt::Result { 142 | <&lib::hash::CryptoHash>::from(bytes).fmt_bs58(fmtr) 143 | } 144 | -------------------------------------------------------------------------------- /solana/solana-ibc/programs/solana-ibc/src/allocator.rs: -------------------------------------------------------------------------------- 1 | //! Defines custom allocator (when necessary) and wraps access to global state. 2 | //! 3 | //! This module serves two purposes. First of all, when running on Solana, it 4 | //! defines a custom allocator which can handle heap sizes larger than 32 KiB. 5 | //! Default allocator defined by solana_program assumes heap is 32 KiB. We’re 6 | //! replacing it with a custom one which can handle heaps of arbitrary size. 7 | //! 8 | //! Second of all, Solana doesn’t allow mutable global variables. We’re working 9 | //! around that by allocating global state on the heap. This is done by the 10 | //! custom allocator. This module than provides a [`global`] function which 11 | //! returns `Global` type with all the available global variables. While the 12 | //! returned reference is static, the variables may use inner mutability. 13 | 14 | #[cfg(all( 15 | target_os = "solana", 16 | feature = "custom-heap", 17 | not(feature = "no-entrypoint"), 18 | not(test), 19 | ))] 20 | mod imp { 21 | #[allow(unused_imports)] // needed for nightly 22 | use alloc::boxed::Box; 23 | use core::cell::Cell; 24 | 25 | use sigverify::Verifier; 26 | 27 | /// The global state available to the smart contract. 28 | #[derive(bytemuck::Zeroable)] 29 | pub(crate) struct Global { 30 | verifier: Cell>>, 31 | } 32 | 33 | impl Global { 34 | /// Returns global verifier, if initialised. 35 | pub fn verifier(&self) -> Option<&'static Verifier<'static>> { 36 | self.verifier.get() 37 | } 38 | 39 | /// Takes ownership of the verifier and sets it as the global verifier. 40 | /// 41 | /// This operation leaks memory thus it shouldn’t be called multiple 42 | /// times. It’s intended to be called at most once at the start of the 43 | /// program. 44 | pub fn set_verifier(&self, verifier: Verifier<'static>) { 45 | // Allocate the verifier on heap so it has fixed address, then leak 46 | // so it has static lifetime. 47 | self.verifier.set(Some(Box::leak(Box::new(verifier)))) 48 | } 49 | } 50 | 51 | // SAFETY: Global is in fact not Sync. However, Solana is single-threaded 52 | // so we don’t need to worry about thread safety. Since this implementation 53 | // is used when building for Solana, we can safely lie to the compiler about 54 | // Global being Sync. 55 | // 56 | // We need Global to be Sync because it’s !Sync status percolates to 57 | // BumpAllocator and since that’s a static variable, Rust requires 58 | // that it’s Sync. 59 | unsafe impl core::marker::Sync for Global {} 60 | 61 | #[global_allocator] 62 | static ALLOCATOR: solana_allocator::BumpAllocator = { 63 | // SAFETY: We’re only instantiating the BumpAllocator once and setting 64 | // it as global allocator. 65 | unsafe { solana_allocator::BumpAllocator::new() } 66 | }; 67 | 68 | /// Returns reference to the global state. 69 | pub(crate) fn global() -> &'static Global { ALLOCATOR.global() } 70 | } 71 | 72 | #[cfg(any( 73 | not(target_os = "solana"), 74 | not(feature = "custom-heap"), 75 | feature = "no-entrypoint", 76 | test, 77 | ))] 78 | mod imp { 79 | use sigverify::Verifier; 80 | 81 | /// The global state available to the smart contract. 82 | /// 83 | /// Note that we don’t support the global state in tests or CPI. None of 84 | /// the unit tests will use code which relies on global state. Similarly, 85 | /// we don’t expose any types of functions which use global state so crates 86 | /// which depend on us for CPI won’t need the global state. 87 | pub(crate) enum Global {} 88 | 89 | impl Global { 90 | /// Returns global verifier, if initialised. 91 | pub fn verifier(&self) -> Option<&'static Verifier<'static>> { 92 | match *self {} 93 | } 94 | 95 | /// Takes ownership of the verifier and sets it as the global verifier. 96 | /// 97 | /// This operation leaks memory thus it shouldn’t be called multiple 98 | /// times. It’s intended to be called at most once at the start of the 99 | /// program. 100 | pub fn set_verifier(&self, _verifier: Verifier<'static>) { 101 | match *self {} 102 | } 103 | } 104 | 105 | pub(crate) fn global() -> &'static Global { 106 | unimplemented!("global should never be called in tests or CPI") 107 | } 108 | } 109 | 110 | pub(crate) use imp::global; 111 | -------------------------------------------------------------------------------- /solana/trie/src/header.rs: -------------------------------------------------------------------------------- 1 | use lib::hash::CryptoHash; 2 | use memory::Ptr; 3 | 4 | use crate::data_ref::DataRef; 5 | 6 | /// Data stored at the beginning of the account describing the trie. 7 | /// 8 | /// As written in the account, the header occupies [`Header::ENCODED_SIZE`] 9 | /// bytes which is equal to single allocation block. To decode and encode the 10 | /// data uses [`Header::decode`] and [`Header::encode`] methods respectively. 11 | #[derive(Clone, Debug, PartialEq)] 12 | pub(crate) struct Header { 13 | pub(crate) root_ptr: Option, 14 | pub(crate) root_hash: CryptoHash, 15 | pub(crate) next_block: u32, 16 | pub(crate) first_free: u32, 17 | } 18 | 19 | /// Header as stored in at the beginning of the account. 20 | #[derive(Clone, Copy, bytemuck::Zeroable, bytemuck::Pod)] 21 | #[repr(C)] 22 | struct RawHeader { 23 | magic: [u8; 8], 24 | root_ptr: [u8; 4], 25 | root_hash: [u8; 32], 26 | next_block: [u8; 4], 27 | first_free: [u8; 4], 28 | _padding: [u8; 20], 29 | } 30 | 31 | impl Header { 32 | /// Size of the encoded header. 33 | pub(crate) const ENCODED_SIZE: usize = sealable_trie::nodes::RawNode::SIZE; 34 | 35 | /// Magic number indicating account data has not been initialised yet. 36 | const MAGIC_UNINITIALISED: [u8; 8] = [0; 8]; 37 | 38 | /// Magic number indicating version 1 of the trie. This is a random 64-bit 39 | /// number. 40 | // To be perfectly honest, I’m not sure if the magic numbers are that 41 | // important. Should we just have a regular increasing number? My idea 42 | // here is to avoid accidentally interpreting other account data as a trie 43 | // but is that really a concern? — mina86 44 | const MAGIC_V1: [u8; 8] = [0xd2, 0x97, 0x1f, 0x41, 0x20, 0x4a, 0xd6, 0xed]; 45 | 46 | /// Decodes the header from given block of memory. 47 | /// 48 | /// Returns `None` if the block is shorter than length of encoded header or 49 | /// encoded data is invalid. 50 | pub(crate) fn decode(data: &impl DataRef) -> Option { 51 | let raw: &RawHeader = 52 | bytemuck::from_bytes(data.get(..Self::ENCODED_SIZE)?); 53 | match raw.magic { 54 | Self::MAGIC_UNINITIALISED => Some(Self { 55 | root_ptr: None, 56 | root_hash: sealable_trie::trie::EMPTY_TRIE_ROOT, 57 | next_block: Self::ENCODED_SIZE as u32, 58 | first_free: 0, 59 | }), 60 | Self::MAGIC_V1 => Some(Self { 61 | root_ptr: Ptr::new(u32::from_ne_bytes(raw.root_ptr)).ok()?, 62 | root_hash: CryptoHash::from(raw.root_hash), 63 | next_block: u32::from_ne_bytes(raw.next_block), 64 | first_free: u32::from_ne_bytes(raw.first_free), 65 | }), 66 | _ => None, 67 | } 68 | } 69 | 70 | /// Returns encoded representation of values in the header. 71 | pub(crate) fn encode(&self) -> [u8; Self::ENCODED_SIZE] { 72 | let root_ptr = self.root_ptr.map_or(0, |ptr| ptr.get()); 73 | bytemuck::must_cast(RawHeader { 74 | magic: Self::MAGIC_V1, 75 | root_ptr: root_ptr.to_ne_bytes(), 76 | root_hash: *self.root_hash.as_array(), 77 | next_block: self.next_block.to_ne_bytes(), 78 | first_free: self.first_free.to_ne_bytes(), 79 | _padding: [0; 20], 80 | }) 81 | } 82 | } 83 | 84 | 85 | #[test] 86 | fn test_header_encoding() { 87 | const ONE: CryptoHash = CryptoHash([1; 32]); 88 | 89 | assert_eq!( 90 | Some(Header { 91 | root_ptr: None, 92 | root_hash: sealable_trie::trie::EMPTY_TRIE_ROOT, 93 | next_block: Header::ENCODED_SIZE as u32, 94 | first_free: 0, 95 | }), 96 | Header::decode(&[0; 72]) 97 | ); 98 | 99 | let hdr = Header { 100 | root_ptr: Ptr::new(420).unwrap(), 101 | root_hash: ONE, 102 | next_block: 42, 103 | first_free: 24, 104 | }; 105 | let got_bytes = hdr.encode(); 106 | let got_hdr = Header::decode(&got_bytes); 107 | 108 | #[rustfmt::skip] 109 | assert_eq!([ 110 | /* magic: */ 0xd2, 0x97, 0x1f, 0x41, 0x20, 0x4a, 0xd6, 0xed, 111 | /* root_ptr: */ 164, 1, 0, 0, 112 | /* root_hash: */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 113 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 114 | /* next_block: */ 42, 0, 0, 0, 115 | /* first_free: */ 24, 0, 0, 0, 116 | /* padding: */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 117 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118 | ], got_bytes); 119 | assert_eq!(Some(hdr), got_hdr); 120 | } 121 | -------------------------------------------------------------------------------- /common/sealable-trie/src/nodes/stress_tests.rs: -------------------------------------------------------------------------------- 1 | //! Random stress tests. They generate random data and perform round-trip 2 | //! conversion checking if they result in the same output. 3 | //! 4 | //! The test may be slow, especially when run under MIRI. Number of iterations 5 | //! it performs can be controlled by STRESS_TEST_ITERATIONS environment 6 | //! variable. 7 | 8 | use lib::test_utils::get_iteration_count; 9 | use lib::u3::U3; 10 | use memory::Ptr; 11 | use pretty_assertions::assert_eq; 12 | 13 | use crate::bits; 14 | use crate::nodes::{self, Node, RawNode, Reference}; 15 | 16 | /// Generates random raw representation and checks decode→encode round-trip. 17 | #[test] 18 | fn stress_test_raw_encoding_round_trip() { 19 | let mut rng = rand::thread_rng(); 20 | let mut raw = RawNode([0; RawNode::SIZE]); 21 | for _ in 0..get_iteration_count(1) { 22 | gen_random_raw_node(&mut rng, &mut raw.0); 23 | let node = raw.decode().unwrap(); 24 | // Test RawNode→Node→RawNode round trip conversion. 25 | assert_eq!(raw, node.encode(), "node: {node:?}"); 26 | } 27 | } 28 | 29 | /// Generates a random raw node representation in canonical representation. 30 | fn gen_random_raw_node( 31 | rng: &mut impl rand::Rng, 32 | bytes: &mut [u8; RawNode::SIZE], 33 | ) { 34 | fn make_ref_canonical(bytes: &mut [u8]) { 35 | if bytes[0] & 0x40 == 0 { 36 | // Node reference. Pointer can be non-zero. 37 | bytes[0] &= !0x80; 38 | } else { 39 | // Value reference. Pointer must be zero but key is_sealed flag: 40 | // 0b01s0_0000 41 | bytes[..4].copy_from_slice(&0x6000_0000_u32.to_be_bytes()); 42 | } 43 | } 44 | 45 | rng.fill(&mut bytes[..]); 46 | bytes[0] &= !0x40; 47 | if bytes[0] & 0x80 == 0 { 48 | // Branch. 49 | make_ref_canonical(&mut bytes[..36]); 50 | make_ref_canonical(&mut bytes[36..]); 51 | } else { 52 | // Extension. Key must be valid and the most significant bit of 53 | // the child must be zero. For the former it’s easiest to just 54 | // regenerate random data. 55 | 56 | // Random length and offset for the key. 57 | let offset = U3::wrap(rng.gen::()); 58 | let max_length = (nodes::MAX_EXTENSION_KEY_SIZE * 8) as u16; 59 | let length = rng.gen_range(1..=max_length - u16::from(offset)); 60 | let tag = 0x8000 | (length << 3) | u16::from(offset); 61 | bytes[..2].copy_from_slice(&tag.to_be_bytes()[..]); 62 | 63 | // Clear unused bits in the key. The easiest way to do it is by using 64 | // bits::Slice. 65 | let mut tmp = [0; 36]; 66 | bits::ExtKey::new(&bytes[2..36], offset, length) 67 | .unwrap() 68 | .encode_into(&mut tmp, 0); 69 | bytes[0..36].copy_from_slice(&tmp); 70 | 71 | make_ref_canonical(&mut bytes[36..]); 72 | } 73 | } 74 | 75 | // ============================================================================= 76 | 77 | /// Generates random node and tests encode→decode round trips. 78 | #[test] 79 | fn stress_test_node_encoding_round_trip() { 80 | let mut rng = rand::thread_rng(); 81 | let mut buf = [0; 66]; 82 | for _ in 0..get_iteration_count(1) { 83 | let node = gen_random_node(&mut rng, &mut buf); 84 | 85 | let raw = super::tests::raw_from_node(&node); 86 | assert_eq!(Ok(node), raw.decode(), "Failed decoding Raw: {raw:?}"); 87 | } 88 | } 89 | 90 | /// Generates a random Node. 91 | fn gen_random_node<'a>( 92 | rng: &mut impl rand::Rng, 93 | buf: &'a mut [u8; 66], 94 | ) -> Node<'a> { 95 | fn rand_ref<'a>( 96 | rng: &mut impl rand::Rng, 97 | hash: &'a [u8; 32], 98 | ) -> Reference<'a> { 99 | let num = rng.gen::(); 100 | if num < 0x8000_0000 { 101 | Reference::node(Ptr::new(num).ok().flatten(), hash.into()) 102 | } else { 103 | Reference::value(num & 1 != 0, hash.into()) 104 | } 105 | } 106 | 107 | rng.fill(&mut buf[..]); 108 | let (key, right) = stdx::split_array_ref::<34, 32, 66>(buf); 109 | let (_, left) = stdx::split_array_ref::<2, 32, 34>(key); 110 | if rng.gen::() & 1 == 0 { 111 | let children = [rand_ref(rng, left), rand_ref(rng, right)]; 112 | Node::Branch { children } 113 | } else { 114 | let offset = U3::wrap(rng.gen::()); 115 | let max_length = (nodes::MAX_EXTENSION_KEY_SIZE * 8) as u16; 116 | let length = rng.gen_range(1..=max_length - u16::from(offset)); 117 | Node::Extension { 118 | key: bits::ExtKey::new(key, offset, length).unwrap(), 119 | child: rand_ref(rng, right), 120 | } 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /solana/solana-ibc/programs/solana-ibc/src/mocks.rs: -------------------------------------------------------------------------------- 1 | use anchor_lang::prelude::*; 2 | 3 | use crate::ibc::ExecutionContext; 4 | use crate::{ibc, storage, MockDeliver}; 5 | 6 | 7 | pub(crate) fn mock_deliver<'a, 'info>( 8 | ctx: Context<'a, 'a, 'a, 'info, MockDeliver<'info>>, 9 | port_id: ibc::PortId, 10 | commitment_prefix: ibc::CommitmentPrefix, 11 | client_id: ibc::ClientId, 12 | counterparty_client_id: ibc::ClientId, 13 | ) -> Result<()> { 14 | let mut store = storage::IbcStorage::new(storage::IbcStorageInner { 15 | private: &mut ctx.accounts.storage, 16 | provable: storage::get_provable_from( 17 | &ctx.accounts.trie, 18 | #[cfg(feature = "witness")] 19 | &ctx.accounts.witness, 20 | &ctx.accounts.sender, 21 | )?, 22 | chain: &mut ctx.accounts.chain, 23 | accounts: Default::default(), 24 | }); 25 | 26 | let connection_id_on_a = ibc::ConnectionId::new(0); 27 | let connection_id_on_b = ibc::ConnectionId::new(1); 28 | let delay_period = core::time::Duration::from_nanos(0); 29 | let connection_counterparty = ibc::conn::Counterparty::new( 30 | counterparty_client_id.clone(), 31 | Some(connection_id_on_b.clone()), 32 | commitment_prefix, 33 | ); 34 | let connection_end_on_a = ibc::ConnectionEnd::new( 35 | ibc::conn::State::Open, 36 | client_id.clone(), 37 | connection_counterparty.clone(), 38 | vec![ibc::conn::Version::default()], 39 | delay_period, 40 | ) 41 | .unwrap(); 42 | let connection_end_on_b = ibc::ConnectionEnd::new( 43 | ibc::conn::State::Open, 44 | client_id, 45 | connection_counterparty, 46 | vec![ibc::conn::Version::default()], 47 | delay_period, 48 | ) 49 | .unwrap(); 50 | 51 | let channel_id_on_a = ibc::ChannelId::new(0); 52 | let channel_id_on_b = ibc::ChannelId::new(1); 53 | let counterparty_for_a = ibc::chan::Counterparty::new( 54 | port_id.clone(), 55 | Some(channel_id_on_b.clone()), 56 | ); 57 | let counterparty_for_b = ibc::chan::Counterparty::new( 58 | port_id.clone(), 59 | Some(channel_id_on_a.clone()), 60 | ); 61 | 62 | let channel_end_on_a = ibc::ChannelEnd::new( 63 | ibc::chan::State::Open, 64 | ibc::chan::Order::Unordered, 65 | counterparty_for_a.clone(), 66 | vec![connection_id_on_a.clone()], 67 | ibc::chan::Version::new( 68 | ibc::apps::transfer::types::VERSION.to_string(), 69 | ), 70 | ) 71 | .unwrap(); 72 | let channel_end_on_b = ibc::ChannelEnd::new( 73 | ibc::chan::State::Open, 74 | ibc::chan::Order::Unordered, 75 | counterparty_for_b.clone(), 76 | vec![connection_id_on_b.clone()], 77 | ibc::chan::Version::new( 78 | ibc::apps::transfer::types::VERSION.to_string(), 79 | ), 80 | ) 81 | .unwrap(); 82 | 83 | 84 | // For Client on Chain A 85 | store 86 | .store_connection( 87 | &ibc::path::ConnectionPath(connection_id_on_a), 88 | connection_end_on_a, 89 | ) 90 | .unwrap(); 91 | store 92 | .store_channel( 93 | &ibc::path::ChannelEndPath( 94 | port_id.clone(), 95 | channel_id_on_a.clone(), 96 | ), 97 | channel_end_on_a, 98 | ) 99 | .unwrap(); 100 | store 101 | .store_next_sequence_send( 102 | &ibc::path::SeqSendPath(port_id.clone(), channel_id_on_a.clone()), 103 | 1.into(), 104 | ) 105 | .unwrap(); 106 | store 107 | .store_next_sequence_recv( 108 | &ibc::path::SeqRecvPath(port_id.clone(), channel_id_on_a), 109 | 1.into(), 110 | ) 111 | .unwrap(); 112 | 113 | // For Client on chain b 114 | store 115 | .store_connection( 116 | &ibc::path::ConnectionPath(connection_id_on_b), 117 | connection_end_on_b, 118 | ) 119 | .unwrap(); 120 | store 121 | .store_channel( 122 | &ibc::path::ChannelEndPath( 123 | port_id.clone(), 124 | channel_id_on_b.clone(), 125 | ), 126 | channel_end_on_b, 127 | ) 128 | .unwrap(); 129 | store 130 | .store_next_sequence_send( 131 | &ibc::path::SeqSendPath(port_id.clone(), channel_id_on_b.clone()), 132 | 1.into(), 133 | ) 134 | .unwrap(); 135 | store 136 | .store_next_sequence_recv( 137 | &ibc::path::SeqRecvPath(port_id, channel_id_on_b), 138 | 1.into(), 139 | ) 140 | .unwrap(); 141 | 142 | Ok(()) 143 | } 144 | -------------------------------------------------------------------------------- /common/cf-solana/src/message.rs: -------------------------------------------------------------------------------- 1 | use crate::proto::client_message::Message; 2 | use crate::{proto, Header, Misbehaviour}; 3 | 4 | #[derive( 5 | Clone, PartialEq, Eq, Debug, derive_more::From, derive_more::TryInto, 6 | )] 7 | #[allow(clippy::large_enum_variant)] 8 | pub enum ClientMessage { 9 | Header(Header), 10 | Misbehaviour(Misbehaviour), 11 | } 12 | 13 | 14 | // Conversions directly to and from the Message enum. 15 | 16 | impl From for Message { 17 | fn from(msg: ClientMessage) -> Self { Self::from(&msg) } 18 | } 19 | 20 | impl From<&ClientMessage> for Message { 21 | fn from(msg: &ClientMessage) -> Self { 22 | match msg { 23 | ClientMessage::Header(msg) => Self::Header(msg.into()), 24 | ClientMessage::Misbehaviour(msg) => Self::Misbehaviour(msg.into()), 25 | } 26 | } 27 | } 28 | 29 | impl TryFrom for ClientMessage { 30 | type Error = proto::BadMessage; 31 | fn try_from(msg: Message) -> Result { 32 | Self::try_from(&msg) 33 | } 34 | } 35 | 36 | impl TryFrom<&Message> for ClientMessage { 37 | type Error = proto::BadMessage; 38 | fn try_from(msg: &Message) -> Result { 39 | match msg { 40 | Message::Header(msg) => msg.try_into().map(Self::Header), 41 | Message::Misbehaviour(mb) => mb.try_into().map(Self::Misbehaviour), 42 | } 43 | } 44 | } 45 | 46 | 47 | // Conversions directly into the Message enum from variant types. 48 | 49 | impl From
for Message { 50 | fn from(msg: Header) -> Self { Self::Header(msg.into()) } 51 | } 52 | 53 | impl From<&Header> for Message { 54 | fn from(msg: &Header) -> Self { Self::Header(msg.into()) } 55 | } 56 | 57 | impl From for Message { 58 | fn from(msg: Misbehaviour) -> Self { Self::Misbehaviour(msg.into()) } 59 | } 60 | 61 | impl From<&Misbehaviour> for Message { 62 | fn from(msg: &Misbehaviour) -> Self { Self::Misbehaviour(msg.into()) } 63 | } 64 | 65 | 66 | // Conversion into ClientMessage proto from variant types. 67 | 68 | impl From
for proto::ClientMessage { 69 | fn from(msg: Header) -> Self { Self { message: Some(msg.into()) } } 70 | } 71 | 72 | impl From<&Header> for proto::ClientMessage { 73 | fn from(msg: &Header) -> Self { Self { message: Some(msg.into()) } } 74 | } 75 | 76 | impl From for proto::ClientMessage { 77 | fn from(msg: Misbehaviour) -> Self { Self { message: Some(msg.into()) } } 78 | } 79 | 80 | impl From<&Misbehaviour> for proto::ClientMessage { 81 | fn from(msg: &Misbehaviour) -> Self { Self { message: Some(msg.into()) } } 82 | } 83 | 84 | 85 | // And finally, conversions between proto and Rust type 86 | 87 | impl From for proto::ClientMessage { 88 | fn from(msg: ClientMessage) -> Self { Self::from(&msg) } 89 | } 90 | 91 | impl From<&ClientMessage> for proto::ClientMessage { 92 | fn from(msg: &ClientMessage) -> Self { 93 | let message = Some(match msg { 94 | ClientMessage::Header(msg) => msg.into(), 95 | ClientMessage::Misbehaviour(msg) => msg.into(), 96 | }); 97 | Self { message } 98 | } 99 | } 100 | 101 | impl TryFrom for ClientMessage { 102 | type Error = proto::BadMessage; 103 | fn try_from(msg: proto::ClientMessage) -> Result { 104 | Self::try_from(&msg) 105 | } 106 | } 107 | 108 | impl TryFrom<&proto::ClientMessage> for ClientMessage { 109 | type Error = proto::BadMessage; 110 | fn try_from(msg: &proto::ClientMessage) -> Result { 111 | msg.message.as_ref().ok_or(proto::BadMessage).and_then(Self::try_from) 112 | } 113 | } 114 | 115 | 116 | proto_utils::define_wrapper! { 117 | proto: proto::ClientMessage, 118 | wrapper: ClientMessage, 119 | custom_any 120 | } 121 | 122 | impl proto_utils::AnyConvert for ClientMessage { 123 | fn to_any(&self) -> (&'static str, alloc::vec::Vec) { 124 | match self { 125 | Self::Header(msg) => msg.to_any(), 126 | Self::Misbehaviour(msg) => msg.to_any(), 127 | } 128 | } 129 | 130 | fn try_from_any( 131 | type_url: &str, 132 | value: &[u8], 133 | ) -> Result { 134 | if type_url.ends_with(proto::ClientMessage::IBC_TYPE_URL) { 135 | Self::decode(value) 136 | } else if type_url.ends_with(proto::Header::IBC_TYPE_URL) { 137 | Header::decode(value).map(Self::Header) 138 | } else if type_url.ends_with(proto::Misbehaviour::IBC_TYPE_URL) { 139 | Misbehaviour::decode(value).map(Self::Misbehaviour) 140 | } else { 141 | Err(crate::proto::DecodeError::BadType) 142 | } 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /common/guestchain/src/height.rs: -------------------------------------------------------------------------------- 1 | use core::{cmp, fmt}; 2 | 3 | use borsh::maybestd::io; 4 | 5 | /// Block height. 6 | /// 7 | /// The generic argument allows the value to be tagged to distinguish it from 8 | /// host blockchain height and guest blockchain height. 9 | pub struct Height(u64, core::marker::PhantomData); 10 | 11 | /// Delta between two host heights. 12 | /// 13 | /// Always expressed as positive value. 14 | /// 15 | /// The generic argument allows the value to be tagged to distinguish it from 16 | /// host blockchain height and guest blockchain height. 17 | pub struct Delta(u64, core::marker::PhantomData); 18 | 19 | /// Tag for use with [`Height`] and [`Delta`] to indicate it’s host blockchain 20 | /// height. 21 | pub enum Host {} 22 | 23 | /// Tag for use with [`Height`] and [`Delta`] to indicate it’s guest blockchain 24 | /// height. 25 | pub enum Block {} 26 | 27 | pub type HostHeight = Height; 28 | pub type HostDelta = Delta; 29 | pub type BlockHeight = Height; 30 | pub type BlockDelta = Delta; 31 | 32 | impl Height { 33 | /// Returns the next height, i.e. `self + 1`. 34 | pub fn next(self) -> Self { Self(self.0.checked_add(1).unwrap(), self.1) } 35 | 36 | /// Checks whether delta between two heights is at least `min`. 37 | /// 38 | /// In essence, returns `self - past_height >= min`. 39 | pub fn check_delta_from(self, past_height: Self, min: Delta) -> bool { 40 | self.checked_sub(past_height).map_or(false, |age| age >= min) 41 | } 42 | 43 | /// Performs checked integer subtraction returning `None` on overflow. 44 | pub fn checked_sub(self, rhs: Self) -> Option> { 45 | self.0.checked_sub(rhs.0).map(|d| Delta(d, Default::default())) 46 | } 47 | } 48 | 49 | // Implement everything explicitly because derives create implementations which 50 | // include bounds on type T. We don’t want that. 51 | macro_rules! impls { 52 | ($ty:ident) => { 53 | impl Clone for $ty { 54 | fn clone(&self) -> Self { *self } 55 | } 56 | 57 | impl Copy for $ty {} 58 | 59 | impl From for $ty { 60 | fn from(value: u64) -> Self { Self(value, Default::default()) } 61 | } 62 | 63 | impl From<$ty> for u64 { 64 | fn from(value: $ty) -> u64 { value.0 } 65 | } 66 | 67 | impl fmt::Debug for $ty { 68 | fn fmt(&self, fmtr: &mut fmt::Formatter<'_>) -> fmt::Result { 69 | self.0.fmt(fmtr) 70 | } 71 | } 72 | 73 | impl fmt::Display for $ty { 74 | fn fmt(&self, fmtr: &mut fmt::Formatter<'_>) -> fmt::Result { 75 | self.0.fmt(fmtr) 76 | } 77 | } 78 | 79 | impl PartialEq for $ty { 80 | fn eq(&self, rhs: &Self) -> bool { self.0 == rhs.0 } 81 | } 82 | 83 | impl Eq for $ty {} 84 | 85 | impl PartialOrd for $ty { 86 | fn partial_cmp(&self, rhs: &Self) -> Option { 87 | Some(self.cmp(rhs)) 88 | } 89 | } 90 | 91 | impl Ord for $ty { 92 | fn cmp(&self, rhs: &Self) -> cmp::Ordering { self.0.cmp(&rhs.0) } 93 | } 94 | 95 | impl borsh::BorshSerialize for $ty { 96 | fn serialize(&self, wr: &mut W) -> io::Result<()> { 97 | self.0.serialize(wr) 98 | } 99 | } 100 | 101 | impl borsh::BorshDeserialize for $ty { 102 | fn deserialize_reader(rd: &mut R) -> io::Result { 103 | u64::deserialize_reader(rd).map(|x| Self(x, Default::default())) 104 | } 105 | } 106 | }; 107 | } 108 | 109 | impls!(Height); 110 | impls!(Delta); 111 | 112 | #[test] 113 | fn test_sanity() { 114 | assert!(HostHeight::from(42) == HostHeight::from(42)); 115 | assert!(HostHeight::from(42) <= HostHeight::from(42)); 116 | assert!(HostHeight::from(42) != HostHeight::from(24)); 117 | assert!(HostHeight::from(42) > HostHeight::from(24)); 118 | 119 | assert!(HostDelta::from(42) == HostDelta::from(42)); 120 | assert!(HostDelta::from(42) <= HostDelta::from(42)); 121 | assert!(HostDelta::from(42) != HostDelta::from(24)); 122 | assert!(HostDelta::from(42) > HostDelta::from(24)); 123 | 124 | assert_eq!(HostHeight::from(43), HostHeight::from(42).next()); 125 | 126 | let old = HostHeight::from(24); 127 | let new = HostHeight::from(42); 128 | assert!(new.check_delta_from(old, HostDelta::from(17))); 129 | assert!(new.check_delta_from(old, HostDelta::from(18))); 130 | assert!(!new.check_delta_from(old, HostDelta::from(19))); 131 | assert!(!old.check_delta_from(new, HostDelta::from(0))); 132 | } 133 | --------------------------------------------------------------------------------