Skip to content

Commit 48ed6fb

Browse files
committed
cardano-rpc: Add quickstart
1 parent 81a2c40 commit 48ed6fb

12 files changed

Lines changed: 536 additions & 1 deletion

File tree

cardano-rpc/README.md

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,143 @@
55
The `cardano-rpc` package provides client and server haskell modules for gRPC interface of `cardano-node`.
66
It implements [UTxO RPC](https://utxorpc.org/introduction) protobuf communication protocol specification.
77

8+
## Quickstart
9+
10+
cardano-rpc is cardano-node's built-in gRPC interface, implementing the [UTxO RPC](https://utxorpc.org) spec.
11+
It is part of cardano-node itself: you enable it with a configuration flag, there is no extra service to run, and it is built, tested, and released together with cardano-node.
12+
Because UTxO RPC is a standard, the same client code also works against other servers that implement it, such as Dolos.
13+
It serves live chain data: the tip, UTxO queries, protocol parameters, and transaction evaluation and submission.
14+
It is not an indexer: there are no address-history queries; see [UTxO RPC v1beta spec coverage](#utxo-rpc-v1beta-spec-coverage) below for the full method status.
15+
The same configuration works against any network, from the local cluster used here to mainnet.
16+
17+
### Prerequisites
18+
19+
1. [Nix](https://nixos.org/download/) with flakes enabled; every command below fetches its tools through it.
20+
The first invocations download the toolchain, which can take several minutes and a few gigabytes.
21+
2. A checkout of this repository, for the vendored proto files the CLI example and the TypeScript quickstart load:
22+
23+
```bash
24+
git clone https://github.com/IntersectMBO/cardano-api
25+
cd cardano-api
26+
```
27+
28+
Work through "Start a local cluster" and "Make your first call" below, then follow whichever quickstart in "Language examples" matches your stack.
29+
30+
### Start a local cluster
31+
32+
The cardano-testnet command below bundles the matching cardano-node and cardano-cli binaries, so one command is enough:
33+
34+
```bash
35+
nix run github:IntersectMBO/cardano-node#cardano-testnet -- \
36+
cardano --num-pool-nodes 1 --enable-grpc --output-dir /tmp/demo-cluster
37+
```
38+
39+
This starts a testnet with a single block-producing cardano-node and its gRPC server enabled, and keeps running in the foreground until you press Ctrl+C.
40+
The cluster is ready once it logs `Testnet started`; open a second terminal for everything below.
41+
The cluster comes with funded test wallets, created at startup under `/tmp/demo-cluster/utxo-keys/utxo1` to `utxo3` (`utxo.skey`, `utxo.vkey`, `utxo.addr`); the transaction example below spends from `utxo1`.
42+
43+
The RPC endpoint is a Unix socket at `/tmp/demo-cluster/socket/node1/rpc.sock`, next to cardano-node's IPC socket.
44+
Most gRPC tooling expects a TCP endpoint, so bridge the socket to `localhost:50051` with socat and leave it running (a second background process, alongside the cluster):
45+
46+
```bash
47+
socat TCP-LISTEN:50051,fork,reuseaddr UNIX-CONNECT:/tmp/demo-cluster/socket/node1/rpc.sock
48+
```
49+
50+
Every example below talks to `localhost:50051`.
51+
Connecting to a cardano-node that listens on TCP directly (`--grpc-listen-port`, see the configuration reference) works the same way, without the bridge; cardano-testnet gets the same ability with `--enable-grpc-http` in [#6685](https://github.com/IntersectMBO/cardano-node/pull/6685).
52+
53+
> [!TIP]
54+
> To use your own binaries instead of the bundled ones, export `CARDANO_NODE` and `CARDANO_CLI` with their paths before running.
55+
56+
> [!NOTE]
57+
> Flag names differ between the two CLIs: `cardano-testnet` takes `--enable-grpc`, `cardano-node` itself takes `--grpc-enable`.
58+
59+
> [!WARNING]
60+
> The output directory must not exist from a previous run; genesis creation fails on leftovers (`Genesis output directory already exists`).
61+
> Run `rm -rf /tmp/demo-cluster` first when retrying, and make sure no cardano-node processes from an earlier attempt are still alive.
62+
>
63+
> Unix socket paths are capped at 108 bytes on Linux, and cardano-testnet fails at startup (`pokeSockAddr: path is too long`) when the output directory is nested too deep.
64+
> Keep `--output-dir` shallow, e.g. under `/tmp`.
65+
66+
### Make your first call
67+
68+
The CLI examples use the proto files vendored in this repository, so run them from the repository root.
69+
First enter a subshell that puts the tools on PATH (your prompt changes; run the commands below inside it).
70+
`.#quickstart` bundles every tool the whole quickstart needs, including both language examples below; the per-language shells (`.#quickstart-rust`, `.#quickstart-typescript`) are minimal alternatives if you only want one:
71+
72+
```bash
73+
nix develop .#quickstart
74+
```
75+
76+
or with `nix-shell` (using `cardano-rpc/quickstart/shell.nix`):
77+
78+
```bash
79+
nix-shell cardano-rpc/quickstart/shell.nix
80+
```
81+
82+
or fetch them ad hoc:
83+
84+
```bash
85+
nix shell nixpkgs#buf nixpkgs#grpcurl nixpkgs#socat
86+
```
87+
88+
Read the chain tip (the most recently adopted block) with [buf](https://buf.build/docs/installation):
89+
90+
```bash
91+
buf curl \
92+
--schema cardano-rpc/proto --protocol grpc --http2-prior-knowledge \
93+
http://localhost:50051/utxorpc.v1beta.sync.SyncService/ReadTip
94+
```
95+
96+
It prints the tip as JSON: slot, hash, height, and timestamp.
97+
Your values differ per run, and the tip advances between calls.
98+
99+
Then read the protocol parameters (the chain's current fee, size, and cost limits):
100+
101+
```bash
102+
buf curl \
103+
--schema cardano-rpc/proto --protocol grpc --http2-prior-knowledge -d '{}' \
104+
http://localhost:50051/utxorpc.v1beta.query.QueryService/ReadParams
105+
```
106+
107+
With grpcurl instead:
108+
109+
```bash
110+
grpcurl -plaintext \
111+
-import-path cardano-rpc/proto -proto utxorpc/v1beta/sync/sync.proto \
112+
localhost:50051 \
113+
utxorpc.v1beta.sync.SyncService/ReadTip
114+
```
115+
116+
### Language examples
117+
118+
- **Rust**: first calls via the `utxorpc-spec` crate. See [quickstart/rust/README.md](quickstart/rust/README.md).
119+
- **TypeScript**: build and submit a transaction with MeshJS. See [quickstart/typescript/README.md](quickstart/typescript/README.md).
120+
121+
### Clean up
122+
123+
Stop the cluster and the socat bridge with Ctrl+C in their terminals, then remove the cluster directory:
124+
125+
```bash
126+
rm -rf /tmp/demo-cluster
127+
```
128+
129+
### Configuration reference
130+
131+
The gRPC server is off by default.
132+
Enable it with `--grpc-enable` or `EnableRpc: true` in the cardano-node configuration; a node socket path must also be configured.
133+
134+
Exactly one transport is active at a time:
135+
136+
1. Unix socket (default): `rpc.sock` next to the node socket, or `--grpc-socket-path` / `RpcSocketPath`.
137+
2. HTTP/2 cleartext: `--grpc-listen-port` / `RpcListenPort`, optionally `--grpc-listen-address` / `RpcListenAddress` (default `127.0.0.1`).
138+
3. HTTP/2 with TLS: add `--grpc-tls-certificate` and `--grpc-tls-private-key` (`RpcTlsCertificateFile`, `RpcTlsPrivateKeyFile`), optionally repeatable `--grpc-tls-chain-certificate` (`RpcTlsChainCertificateFiles`).
139+
140+
The three transports are mutually exclusive.
141+
TLS additionally requires a listen port, and its certificate and key must be set together; see the [Security](#security) section below before exposing an endpoint beyond localhost.
142+
143+
Clients connect over TCP the same way as in the examples above: replace the Unix-socket connector or `unix://` target with the node's address and port.
144+
8145
## UTxO RPC v1beta spec coverage
9146

10147
Methods marked ⬜ or ❌ are exposed by the server but respond with the `UNIMPLEMENTED` gRPC status.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[package]
2+
name = "cardano-rpc-quickstart"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[dependencies]
7+
utxorpc-spec = { version = "0.19.2", default-features = false, features = [
8+
"utxorpc-v1beta-sync",
9+
"utxorpc-v1beta-query",
10+
] }
11+
tonic = "0.12.3"
12+
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
13+
hex = "0.4"
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Rust quickstart
2+
3+
The Rust path is the simplest one: the published [`utxorpc-spec`](https://crates.io/crates/utxorpc-spec) crate already ships tonic-generated v1beta bindings, so no proto files and no protoc are needed.
4+
The files below are already in this directory; no `cargo new` needed.
5+
6+
> [!IMPORTANT]
7+
> Use `utxorpc-spec` directly, not the higher-level `utxorpc` SDK crate: that wrapper is hardwired to the older `utxorpc.v1alpha` services and cannot talk to cardano-rpc, which serves `v1beta` (v1beta packaging for the SDKs is tracked in utxorpc/spec#209).
8+
9+
## Prerequisites
10+
11+
Start a local cluster and the socat bridge as described in the main [Quickstart](../../README.md#quickstart).
12+
`Cargo.toml` and `src/main.rs` here connect to `localhost:50051`, the socat bridge address; no repository checkout is required otherwise, the project can live anywhere.
13+
14+
## Run it
15+
16+
Get `cargo`, `rustc` and `gcc` from the repository's flake (run from the repository root; it only provides the toolchain, so `cd` into this directory before running `cargo run` below):
17+
18+
```bash
19+
nix develop .#quickstart-rust
20+
```
21+
22+
or with `nix-shell` (using the `shell.nix` in this directory):
23+
24+
```bash
25+
nix-shell
26+
```
27+
28+
or fetch them ad hoc:
29+
30+
```bash
31+
nix shell nixpkgs#cargo nixpkgs#rustc nixpkgs#gcc
32+
```
33+
34+
Then, from this directory:
35+
36+
```bash
37+
cargo run
38+
```
39+
40+
Sample output (your values will differ):
41+
42+
```
43+
Tip: slot 834 height 37 hash d76df679ffa93ca9d1224cff29b3479c7535a84ed3eb8c17ce1d34aaeb4e774d
44+
Protocol parameters: max_tx_size 16384 max_block_body_size 65536
45+
```
46+
47+
tonic can also connect straight to the Unix socket through a custom connector (`Endpoint::connect_with_connector` with a `tokio::net::UnixStream`), skipping the socat bridge; the TCP form used here is the simpler one.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{ pkgs ? import <nixpkgs> {} }: pkgs.mkShell { packages = with pkgs; [ cargo rustc gcc ]; }
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
use tonic::transport::Endpoint;
2+
3+
use utxorpc_spec::utxorpc::v1beta::query::{
4+
any_chain_params::Params as AnyChainParamsVariant, query_service_client::QueryServiceClient,
5+
ReadParamsRequest,
6+
};
7+
use utxorpc_spec::utxorpc::v1beta::sync::{sync_service_client::SyncServiceClient, ReadTipRequest};
8+
9+
const RPC_URL: &str = "http://localhost:50051";
10+
11+
#[tokio::main]
12+
async fn main() -> Result<(), Box<dyn std::error::Error>> {
13+
let channel = Endpoint::try_from(RPC_URL)?.connect().await?;
14+
15+
let mut sync_client = SyncServiceClient::new(channel.clone());
16+
let mut query_client = QueryServiceClient::new(channel);
17+
18+
let tip = sync_client
19+
.read_tip(ReadTipRequest {})
20+
.await?
21+
.into_inner()
22+
.tip
23+
.expect("ReadTip response always carries a tip");
24+
println!(
25+
"Tip: slot {} height {} hash {}",
26+
tip.slot,
27+
tip.height,
28+
hex::encode(&tip.hash)
29+
);
30+
31+
let params = query_client
32+
.read_params(ReadParamsRequest { field_mask: None })
33+
.await?
34+
.into_inner()
35+
.values
36+
.and_then(|v| v.params)
37+
.expect("cardano-rpc always returns Cardano parameters");
38+
match params {
39+
AnyChainParamsVariant::Cardano(pparams) => println!(
40+
"Protocol parameters: max_tx_size {} max_block_body_size {}",
41+
pparams.max_tx_size, pparams.max_block_body_size
42+
),
43+
}
44+
45+
Ok(())
46+
}

cardano-rpc/quickstart/shell.nix

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Covers every tool the cardano-rpc quickstart uses: the CLI examples plus both language examples.
2+
{ pkgs ? import <nixpkgs> {} }: pkgs.mkShell { packages = with pkgs; [ buf grpcurl socat cargo rustc gcc nodejs ]; }
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# TypeScript quickstart
2+
3+
Build and submit a transaction with [MeshJS](https://meshjs.dev), using cardano-rpc for UTxO queries, protocol parameters, and submission.
4+
The example sends 5 ADA from the cluster's `utxo1` wallet to the `utxo2` address.
5+
6+
> [!IMPORTANT]
7+
> `@meshsdk/provider`'s off-the-shelf `U5CProvider` does not work against cardano-rpc: it is pinned to `@utxorpc/sdk` 0.6.x, which speaks the older `utxorpc.v1alpha` services, while cardano-rpc serves `v1beta` (v1beta packaging for the SDKs is tracked in utxorpc/spec#209).
8+
> Until the SDKs move to v1beta, [`cardano-rpc-provider.mjs`](cardano-rpc-provider.mjs) talks v1beta directly by loading the proto files at runtime.
9+
>
10+
> The provider is demo scaffolding for plain ADA and native-asset payments: it maps oversized numeric values onto the `int` variant only, and it does not surface datums, inline datums, or reference scripts.
11+
> Do not lift it unchanged into a dApp that touches script-locked UTxOs.
12+
13+
## Prerequisites
14+
15+
Start a local cluster and the socat bridge as described in the main [Quickstart](../../README.md#quickstart).
16+
It talks to the socat bridge at `localhost:50051`; `@grpc/grpc-js` can also target the Unix socket directly with a `unix://` address, skipping the bridge.
17+
18+
## Run it
19+
20+
Get Node.js from the repository's flake (run from the repository root; it only provides the toolchain, so `cd` into this directory before running the commands below):
21+
22+
```bash
23+
nix develop .#quickstart-typescript
24+
```
25+
26+
or with `nix-shell` (using the `shell.nix` in this directory):
27+
28+
```bash
29+
nix-shell
30+
```
31+
32+
or fetch it ad hoc:
33+
34+
```bash
35+
nix shell nixpkgs#nodejs
36+
```
37+
38+
Install the dependencies (pinned versions are in `package.json`):
39+
40+
```bash
41+
npm install
42+
```
43+
44+
[`cardano-rpc-provider.mjs`](cardano-rpc-provider.mjs) loads the proto files vendored in this repository, from `../../proto` relative to the current directory by default.
45+
Run the command below from this directory, or set `CARDANO_RPC_PROTO` to point at a `cardano-rpc/proto` directory elsewhere:
46+
47+
```bash
48+
node send-lovelace.mjs
49+
```
50+
51+
Sample output (your addresses and hashes will differ):
52+
53+
```
54+
Sender address: addr_test1vp0cg0r2w9xczav4g0txn6suy9z0g24er7h25eqk639hwfgcmtj72
55+
Recipient address: addr_test1vp0fsh3r9t3zmsfkv27qkwh66vudurnttpy80f8yjagxqyqz27px0
56+
Spendable UTxOs: 1
57+
Submitted tx: c8f9332364a81e687599a0b1c4599cd8bff0213c3a4c23a45a7d525ccc124018
58+
Confirmed: 5000000 lovelace landed at addr_test1vp0fsh3r9t3zmsfkv27qkwh66vudurnttpy80f8yjagxqyqz27px0 (c8f9332364a81e687599a0b1c4599cd8bff0213c3a4c23a45a7d525ccc124018#0)
59+
```
60+
61+
See [`send-lovelace.mjs`](send-lovelace.mjs) for the full script: building the transaction with `MeshTxBuilder`, then confirming by polling the recipient's UTxOs for the new output.

0 commit comments

Comments
 (0)