Skip to content

Commit

Permalink
jsonrpc-alt: initial scaffolding
Browse files Browse the repository at this point in the history
## Description

Basic structure of a JSONRPC service, that we can add modules to.
Initially only supporting `sui_getReferenceGasPrice`. The following
features will be added in a follow-up PRs:

- Configuring the database to be read-only
- Configuring RPC max connection size
- Metrics
- Graceful shutdown
- `"rpc.discover"` JSON-RPC method
- E2E testing support
- ...more JSON-RPC methods

## Test plan

Run the service:

```
sui$ RUST_LOG="INFO,sui_indexer_alt_jsonrpc=DEBUG" cargo run -p sui-indexer-alt-jsonrpc -- \
  --database-url $DB_URL --listen-address 127.0.0.1:5000
```

And query the method:

```
sui$ curl -LX POST  "http://localhost:5000" \
    --header 'Content-Type: application/json' \
    --data '{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "suix_getReferenceGasPrice",
  "params": []
}' | jq .
{
  "jsonrpc": "2.0",
  "result": "750",
  "id": 1
}
```
  • Loading branch information
amnn committed Dec 19, 2024
1 parent 4fdaf64 commit bc7a3f8
Show file tree
Hide file tree
Showing 9 changed files with 449 additions and 1 deletion.
21 changes: 21 additions & 0 deletions Cargo.lock

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

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ members = [
"crates/sui-indexer",
"crates/sui-indexer-alt",
"crates/sui-indexer-alt-framework",
"crates/sui-indexer-alt-jsonrpc",
"crates/sui-indexer-alt-schema",
"crates/sui-indexer-builder",
"crates/sui-json",
Expand Down Expand Up @@ -641,6 +642,7 @@ sui-graphql-rpc-headers = { path = "crates/sui-graphql-rpc-headers" }
sui-genesis-builder = { path = "crates/sui-genesis-builder" }
sui-indexer = { path = "crates/sui-indexer" }
sui-indexer-alt-framework = { path = "crates/sui-indexer-alt-framework" }
sui-indexer-alt-jsonrpc = { path = "crates/sui-indexer-alt-jsonrpc" }
sui-indexer-alt-schema = { path = "crates/sui-indexer-alt-schema" }
sui-indexer-builder = { path = "crates/sui-indexer-builder" }
sui-json = { path = "crates/sui-json" }
Expand Down
29 changes: 29 additions & 0 deletions crates/sui-indexer-alt-jsonrpc/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
[package]
name = "sui-indexer-alt-jsonrpc"
version.workspace = true
authors = ["Mysten Labs <build@mystenlabs.com>"]
license = "Apache-2.0"
publish = false
edition = "2021"

[[bin]]
name = "sui-indexer-alt-jsonrpc"
path = "src/main.rs"

[dependencies]
anyhow.workspace = true
async-trait.workspace = true
axum.workspace = true
clap.workspace = true
diesel = { workspace = true, features = ["chrono"] }
diesel-async = { workspace = true, features = ["bb8", "postgres", "async-connection-wrapper"] }
jsonrpsee = { workspace = true, features = ["macros", "server"] }
telemetry-subscribers.workspace = true
thiserror.workspace = true
tokio.workspace = true
tracing.workspace = true
url.workspace = true

sui-indexer-alt-schema.workspace = true
sui-pg-db.workspace = true
sui-types.workspace = true
38 changes: 38 additions & 0 deletions crates/sui-indexer-alt-jsonrpc/src/api/governance.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

use diesel::{ExpressionMethods, QueryDsl};

use jsonrpsee::{core::RpcResult, proc_macros::rpc};
use sui_indexer_alt_schema::schema::kv_epoch_starts;
use sui_pg_db::Db;
use sui_types::sui_serde::BigInt;

use super::Connection;

#[rpc(server, namespace = "suix")]
trait Governance {
/// Return the reference gas price for the network as of the latest epoch.
#[method(name = "getReferenceGasPrice")]
async fn get_reference_gas_price(&self) -> RpcResult<BigInt<u64>>;
}

pub(crate) struct GovernanceImpl(pub Db);

#[async_trait::async_trait]
impl GovernanceServer for GovernanceImpl {
async fn get_reference_gas_price(&self) -> RpcResult<BigInt<u64>> {
use kv_epoch_starts::dsl as e;

let mut conn = Connection::get(&self.0).await?;
let rgp: i64 = conn
.first(
e::kv_epoch_starts
.select(e::reference_gas_price)
.order(e::epoch.desc()),
)
.await?;

Ok((rgp as u64).into())
}
}
69 changes: 69 additions & 0 deletions crates/sui-indexer-alt-jsonrpc/src/api/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

use diesel::dsl::Limit;
use diesel::pg::Pg;
use diesel::query_builder::QueryFragment;
use diesel::query_dsl::methods::LimitDsl;
use diesel::result::Error as DieselError;
use diesel_async::methods::LoadQuery;
use diesel_async::pooled_connection::bb8::RunError;
use diesel_async::RunQueryDsl;
use jsonrpsee::core::Error as RpcError;
use jsonrpsee::types::{
error::{CallError, INTERNAL_ERROR_CODE},
ErrorObject,
};
use sui_pg_db as db;
use tracing::debug;

pub(crate) mod governance;

/// This wrapper type exists to perform error conversion between the data fetching layer and the
/// RPC layer, and to handle debug logging of database queries.
struct Connection<'p>(db::Connection<'p>);

#[derive(thiserror::Error, Debug)]
enum DbError {
#[error(transparent)]
Connect(#[from] RunError),

#[error(transparent)]
RunQuery(#[from] DieselError),
}

impl<'p> Connection<'p> {
async fn get(db: &'p db::Db) -> Result<Self, DbError> {
Ok(Self(db.connect().await?))
}

async fn first<'q, Q, U>(&mut self, query: Q) -> Result<U, DbError>
where
U: Send,
Q: RunQueryDsl<db::ManagedConnection> + 'q,
Q: LimitDsl,
Limit<Q>: LoadQuery<'q, db::ManagedConnection, U> + QueryFragment<Pg> + Send,
{
let query = query.limit(1);
debug!("{}", diesel::debug_query(&query));
Ok(query.get_result(&mut self.0).await?)
}
}

impl From<DbError> for RpcError {
fn from(err: DbError) -> RpcError {
match err {
DbError::Connect(err) => RpcError::Call(CallError::Custom(ErrorObject::owned(
INTERNAL_ERROR_CODE,
err.to_string(),
None::<()>,
))),

DbError::RunQuery(err) => RpcError::Call(CallError::Custom(ErrorObject::owned(
INTERNAL_ERROR_CODE,
err.to_string(),
None::<()>,
))),
}
}
}
15 changes: 15 additions & 0 deletions crates/sui-indexer-alt-jsonrpc/src/args.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

use sui_pg_db::DbArgs;

use crate::RpcArgs;

#[derive(clap::Parser, Debug, Clone)]
pub struct Args {
#[command(flatten)]
pub db_args: DbArgs,

#[command(flatten)]
pub rpc_args: RpcArgs,
}
Loading

0 comments on commit bc7a3f8

Please sign in to comment.