diff --git a/README.md b/README.md index f80194d0..6356f854 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,7 @@ +[![Internet Computer portal](https://img.shields.io/badge/InternetComputer-grey?logo=internet%20computer&style=for-the-badge)](https://internetcomputer.org) +[![DFinity Forum](https://img.shields.io/badge/help-post%20on%20forum.dfinity.org-blue?style=for-the-badge)](https://forum.dfinity.org/t/sol-rpc-canister/41896) +[![GitHub license](https://img.shields.io/badge/license-Apache%202.0-blue.svg?logo=apache&style=for-the-badge)](LICENSE) + # SOL RPC canister > [!IMPORTANT] @@ -7,3 +11,130 @@ Interact with the [Solana](https://solana.com/) blockchain from the [Internet Computer](https://internetcomputer.org/). + +## Table of Contents + +* [Features](#features) +* [Usage](#usage) + * [From the command line](#from-the-command-line) + * [From within a Rust canister](#from-within-a-rust-canister) +* [Limitations](#limitations) +* [Reproducible build](#reproducible-build) +* [Related projects](#related-projects) +* [Contributing](#contributing) +* [License](#license) + +## Features + +* **No single point of failure**: Each request will by default query 3 distinct Solana JSON-RPC providers and aggregate their results. +* **Configurable consensus strategy**: Choose how responses from multiple providers are aggregated depending on the needs of your application, e.g., 3-out-of-5 meaning that 5 providers will be queried and the overall response will be successful if at least 3 do agree (equality). +* **Pay directly in cycles**: No need to take care of API keys, each request can be paid for by attaching cycles. +* **Bring your own**: + * A Solana RPC method is not supported? There is an endpoint (`jsonRequest`) to send any JSON-RPC request. + * Missing your favorite Solana JSON-RPC provider? You can specify your own providers (`RpcSources::Custom`). + +## Usage + +The SOL RPC canister runs on the [fiduciary subnet](https://internetcomputer.org/docs/building-apps/developing-canisters/deploy-specific-subnet#fiduciary-subnets) with the following principal: [`tghme-zyaaa-aaaar-qarca-cai`](https://dashboard.internetcomputer.org/canister/tghme-zyaaa-aaaar-qarca-cai). + +Refer to the [Reproducible Build](#reproducible-build) section for information on how to verify the hash of the deployed WebAssembly module. + +### From the command line + +#### Prerequisites: + +* [Install](https://internetcomputer.org/docs/building-apps/developer-tools/dev-tools-overview#dfx) `dfx`. +* [Cycles wallet](https://internetcomputer.org/docs/building-apps/canister-management/cycles-wallet) with some cycles to pay for requests. +* Commands are executed in [`canister/prod`](canister/prod). + +#### Example with [`getSlot`](https://solana.com/de/docs/rpc/http/getslot) + +To get the last `finalized` slot on Solana Mainnet + +```bash +dfx canister call --ic sol_rpc --wallet $(dfx identity get-wallet --ic) --with-cycles 2B getSlot \ +' +( + variant { Default = variant { Mainnet } }, + opt record { + responseConsensus = opt variant { Equality }; + }, + opt record { commitment = opt variant { finalized } }, +)' +``` + +More examples are available [here](canister/scripts/examples.sh). + +### From within a Rust Canister + +#### Prerequisites: + +* Add the `sol_rpc_client` library as a dependency in your `Cargo.toml`. + +#### Example with [`getSlot`](https://solana.com/de/docs/rpc/http/getslot) + +To get the last `finalized` slot on Solana Mainnet: + +```rust,ignore +use sol_rpc_client::SolRpcClient; +use sol_rpc_types::{ + CommitmentLevel, ConsensusStrategy, GetSlotParams, RpcConfig, RpcSources, SolanaCluster, +}; + +let client = SolRpcClient::builder_for_ic() + .with_rpc_sources(RpcSources::Default(SolanaCluster::Mainnet)) + .with_rpc_config(RpcConfig { + response_consensus: Some(ConsensusStrategy::Equality), + ..Default::default() + }) + .build(); + +let slot = client + .get_slot() + .with_params(GetSlotParams { + commitment: Some(CommitmentLevel::Finalized), + ..Default::default() + }) + .send() + .await; +``` + +Full examples are available in the [examples](examples) folder and additional code snippets are also available in the [`sol_rpc_client`](libs/client/README.md) crate. + +## Limitations + +The SOL RPC canister reaches the Solana JSON-RPC providers using [HTTPS outcalls](https://internetcomputer.org/https-outcalls) and are therefore subject to the following limitations: +1. The contacted providers must support IPv6. +2. Some Solana RPC endpoint cannot be supported. This is the case for example for [`getLatestBlockhash`](https://solana.com/de/docs/rpc/http/getlatestblockhash). + The reason is that an HTTPs outcalls involves an HTTP request from each node in the subnet and has therefore a latency in the order of a few seconds. + This can be problematic for endpoints with fast changing responses, such as [`getLatestBlockhash`](https://solana.com/de/docs/rpc/http/getlatestblockhash) (which changes roughly every 400ms), + since in this case nodes will not be able to reach a consensus. +3. Note that in some cases, the use of a [response transformation](https://internetcomputer.org/docs/building-apps/network-features/using-http/https-outcalls/overview) + to canonicalize the response seen by each node before doing consensus may alleviate the problem. + For example, `getSlot` rounds by default the received slot by 20, therefore artificially increasing the slot time seen by each node to 8s to allow them reaching consensus with some significantly higher probability. + The reason why such a canonicalization strategy does not work for [`getLatestBlockhash`](https://solana.com/de/docs/rpc/http/getlatestblockhash) is that the result is basically a random-looking string of fixed length. +4. There are therefore two options to send a transaction on Solana using the SOL RPC canister + 1. Use a [durable nonce](https://solana.com/de/developers/guides/advanced/introduction-to-durable-nonces) instead of a blockhash. + 2. Retrieve a recent blockhash by first retrieving a recent slot with `getSlot` and then getting the block (which includes the blockhash) with `getBlock`. + +## Reproducible Build + +The SOL RPC canister supports [reproducible builds](https://internetcomputer.org/docs/current/developer-docs/smart-contracts/test/reproducible-builds): + +1. Ensure [Docker](https://www.docker.com/get-started/) is installed on your machine. +2. Run [`docker-build`](scripts/docker-build) in your terminal. +3. Run `sha256sum sol_rpc_canister.wasm.gz` on the generated file to view the SHA-256 hash. + +In order to verify the latest SOL RPC Wasm file, please make sure to download the corresponding version of the source code from the latest GitHub release. + +## Related Projects + +* [`ic-solana`](https://github.com/mfactory-lab/ic-solana) + +## Contributing + +At this point we do not accept external contributions yet. External contributions will be accepted after the initial release. + +## License + +This project is licensed under the [Apache License 2.0](https://opensource.org/licenses/Apache-2.0). \ No newline at end of file diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000..1301ba07 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,37 @@ +# Security Policy + +DFINITY takes the security of our software products seriously, which includes all source code repositories under the [DFINITY](https://github.com/dfinity) GitHub organization. + +> [!IMPORTANT] +> [DFINITY Foundation](https://dfinity.org) has a [Internet Computer (ICP) Bug Bounty program](https://dfinity.org/bug-bounty/) that rewards researchers for finding and reporting vulnerabilities in the Internet Computer. Please check the scope and eligibility criteria outlined in the policy to see if the vulnerability you found qualifies for a reward. + +## How to report a vulnerability + +We appreciate your help in keeping our projects secure. +If you believe you have found a security vulnerability in any of our repositories, please report it resonsibly to us as described below: + +1. **Do not disclose the vulnerability publicly.** Public disclosure could be exploited by attackers before it can be fixed. +2. **Send an email to securitybugs@dfinity.org.** Please include the following information in your email: + * A description of the vulnerability + * Steps to reproduce the vulnerability + * Risk rating of the vulnerability + * Any other relevant information + +We will respond to your report within 72 hours and work with you to fix the vulnerability as soon as possible. + +### Security Updates + +We are committed to fixing security vulnerabilities in a timely manner. Once a security vulnerability is reported, we will: + +* Investigate the report and confirm the vulnerability. +* Develop a fix for the vulnerability. +* Release a new version of the project that includes the fix. +* Announce the security fix in the project's release notes. + +## Preferred Language + +We prefer all communications to be in English. + +## Disclaimer + +This security policy is subject to change at any time. \ No newline at end of file diff --git a/libs/client/README.md b/libs/client/README.md index a215e84c..1a5dba00 100644 --- a/libs/client/README.md +++ b/libs/client/README.md @@ -1,2 +1,9 @@ +[![Internet Computer portal](https://img.shields.io/badge/InternetComputer-grey?logo=internet%20computer&style=for-the-badge)](https://internetcomputer.org) +[![DFinity Forum](https://img.shields.io/badge/help-post%20on%20forum.dfinity.org-blue?style=for-the-badge)](https://forum.dfinity.org/t/sol-rpc-canister/41896) +[![GitHub license](https://img.shields.io/badge/license-Apache%202.0-blue.svg?logo=apache&style=for-the-badge)](LICENSE) + # Crate `sol_rpc_client` +Library to interact with the [SOL RPC canister](https://github.com/dfinity/sol-rpc-canister/) from a canister running on +the Internet Computer. +See the Rust [documentation](https://docs.rs/sol_rpc_client) for more details. \ No newline at end of file diff --git a/libs/client/src/request/mod.rs b/libs/client/src/request/mod.rs index 93133082..38d89197 100644 --- a/libs/client/src/request/mod.rs +++ b/libs/client/src/request/mod.rs @@ -203,6 +203,12 @@ impl *self.request.params_mut() = params.into(); self } + + /// Change the RPC configuration to use for that request. + pub fn with_rpc_config(mut self, rpc_config: impl Into>) -> Self { + *self.request.rpc_config_mut() = rpc_config.into(); + self + } } impl @@ -230,12 +236,10 @@ impl config.rounding_error = Some(rounding_error); return self; } - let config = GetSlotRpcConfig { + self.with_rpc_config(GetSlotRpcConfig { rounding_error: Some(rounding_error), ..Default::default() - }; - *self.request.rpc_config_mut() = Some(config); - self + }) } } diff --git a/libs/types/README.md b/libs/types/README.md index c513cf54..7766920f 100644 --- a/libs/types/README.md +++ b/libs/types/README.md @@ -1,2 +1,8 @@ +[![Internet Computer portal](https://img.shields.io/badge/InternetComputer-grey?logo=internet%20computer&style=for-the-badge)](https://internetcomputer.org) +[![DFinity Forum](https://img.shields.io/badge/help-post%20on%20forum.dfinity.org-blue?style=for-the-badge)](https://forum.dfinity.org/t/sol-rpc-canister/41896) +[![GitHub license](https://img.shields.io/badge/license-Apache%202.0-blue.svg?logo=apache&style=for-the-badge)](LICENSE) + # Crate `sol_rpc_types` +Library defining the types for interacting with the [SOL RPC canister](https://github.com/dfinity/sol-rpc-canister/). +See the Rust [documentation](https://docs.rs/sol_rpc_types) for more details.