Skip to content

Commit

Permalink
expose chain identifier in rpc (MystenLabs#12064)
Browse files Browse the repository at this point in the history
## Description 

Sometimes it's easy to mistake two networks (testnet v.s. mainnet), this
adds a way to query the rpc to see which network the node is in. Also
add a CLI option.

## Test Plan 

tested locally.

---
If your changes are not user-facing and not a breaking change, you can
skip the following section. Otherwise, please indicate what changed, and
then add to the Release Notes section as highlighted during the release
process.

### Type of Change (Check all that apply)

- [ ] user-visible impact
- [ ] breaking change for a client SDKs
- [ ] breaking change for FNs (FN binary must upgrade)
- [ ] breaking change for validators or node operators (must upgrade
binaries)
- [ ] breaking change for on-chain data layout
- [ ] necessitate either a data wipe or data migration

### Release notes
  • Loading branch information
longbowlu authored May 19, 2023
1 parent 012dfba commit 5231444
Show file tree
Hide file tree
Showing 10 changed files with 92 additions and 13 deletions.
9 changes: 5 additions & 4 deletions crates/sui-core/src/authority.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ use sui_types::crypto::{
default_hash, AggregateAuthoritySignature, AuthorityKeyPair, AuthoritySignInfo, NetworkKeyPair,
Signer,
};
use sui_types::digests::ChainIdentifier;
use sui_types::digests::TransactionEventsDigest;
use sui_types::dynamic_field::{DynamicFieldInfo, DynamicFieldName, DynamicFieldType, Field};
use sui_types::effects::{
Expand Down Expand Up @@ -162,7 +163,7 @@ pub mod test_authority_builder;
pub(crate) mod authority_notify_read;
pub(crate) mod authority_store;

static CHAIN_IDENTIFIER: OnceCell<CheckpointDigest> = OnceCell::new();
static CHAIN_IDENTIFIER: OnceCell<ChainIdentifier> = OnceCell::new();

pub type ReconfigConsensusMessage = (
AuthorityKeyPair,
Expand Down Expand Up @@ -2297,7 +2298,7 @@ impl AuthorityState {
}

/// Chain Identifier is the digest of the genesis checkpoint.
pub fn get_chain_identifier(&self) -> Option<CheckpointDigest> {
pub fn get_chain_identifier(&self) -> Option<ChainIdentifier> {
if let Some(digest) = CHAIN_IDENTIFIER.get() {
return Some(*digest);
}
Expand All @@ -2308,8 +2309,8 @@ impl AuthorityState {
.ok()?
.tap_none(|| error!("Genesis checkpoint is missing from DB"))?;
// It's ok if the value is already set due to data races.
let _ = CHAIN_IDENTIFIER.set(*checkpoint.digest());
Some(*checkpoint.digest())
let _ = CHAIN_IDENTIFIER.set(ChainIdentifier::from(*checkpoint.digest()));
Some(ChainIdentifier::from(*checkpoint.digest()))
}

pub fn get_move_object<T>(&self, object_id: &ObjectID) -> SuiResult<T>
Expand Down
11 changes: 10 additions & 1 deletion crates/sui-indexer/src/apis/read_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use sui_json_rpc_types::{
};
use sui_open_rpc::Module;
use sui_types::base_types::{ObjectID, SequenceNumber};
use sui_types::digests::TransactionDigest;
use sui_types::digests::{ChainIdentifier, TransactionDigest};
use sui_types::sui_serde::BigInt;

use crate::errors::IndexerError;
Expand Down Expand Up @@ -367,6 +367,15 @@ where
protocol_config_guard.stop_and_record();
protocol_config_resp
}

async fn get_chain_identifier(&self) -> RpcResult<String> {
let ci = self
.state
.get_checkpoint(CheckpointId::SequenceNumber(0))
.await?
.digest;
Ok(ChainIdentifier::from(ci).to_string())
}
}

impl<S> SuiRpcModule for ReadApi<S>
Expand Down
4 changes: 4 additions & 0 deletions crates/sui-json-rpc/src/api/read.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,4 +148,8 @@ pub trait ReadApi {
/// An optional protocol version specifier. If omitted, the latest protocol config table for the node will be returned.
version: Option<BigInt<u64>>,
) -> RpcResult<ProtocolConfigResponse>;

/// Return the chain's identifier
#[method(name = "getChainIdentifier")]
async fn get_chain_identifier(&self) -> RpcResult<String>;
}
11 changes: 11 additions & 0 deletions crates/sui-json-rpc/src/read_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -935,6 +935,17 @@ impl ReadApiServer for ReadApi {
.map(ProtocolConfigResponse::from)?)
})
}

#[instrument(skip(self))]
async fn get_chain_identifier(&self) -> RpcResult<String> {
with_tracing!(async move {
let ci = self
.state
.get_chain_identifier()
.ok_or(anyhow!("Chain identifier not found"))?;
Ok(ci.to_string())
})
}
}

impl SuiRpcModule for ReadApi {
Expand Down
4 changes: 1 addition & 3 deletions crates/sui-node/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// SPDX-License-Identifier: Apache-2.0

use clap::Parser;
use fastcrypto::encoding::{Encoding, Hex};
use mysten_common::sync::async_once_cell::AsyncOnceCell;
use std::path::PathBuf;
use std::sync::Arc;
Expand Down Expand Up @@ -126,8 +125,7 @@ fn main() {
runtimes.metrics.spawn(async move {
let node = node_once_cell_clone.get().await;
let chain_identifier = match node.state().get_chain_identifier() {
// Unwrap safe: Checkpoint Digest is 32 bytes long
Some(chain_identifier) => Hex::encode(chain_identifier.into_inner().get(0..4).unwrap()),
Some(chain_identifier) => chain_identifier.to_string(),
None => "Unknown".to_string(),
};

Expand Down
17 changes: 17 additions & 0 deletions crates/sui-open-rpc/spec/openrpc.json
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,23 @@
}
]
},
{
"name": "sui_getChainIdentifier",
"tags": [
{
"name": "Read API"
}
],
"description": "Return the chain's identifier",
"params": [],
"result": {
"name": "String",
"required": true,
"schema": {
"type": "string"
}
}
},
{
"name": "sui_getCheckpoint",
"tags": [
Expand Down
4 changes: 4 additions & 0 deletions crates/sui-sdk/src/apis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,10 @@ impl ReadApi {
.await?)
}

pub async fn get_chain_identifier(&self) -> SuiRpcResult<String> {
Ok(self.api.http.get_chain_identifier().await?)
}

/// Return a checkpoint
pub async fn get_checkpoint(&self, id: CheckpointId) -> SuiRpcResult<Checkpoint> {
Ok(self.api.http.get_checkpoint(id).await?)
Expand Down
6 changes: 1 addition & 5 deletions crates/sui-telemetry/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@ use std::time::{SystemTime, UNIX_EPOCH};
use sui_core::authority::AuthorityState;
use tracing::trace;

use fastcrypto::encoding::Encoding;
use fastcrypto::encoding::Hex;

pub(crate) const GA_API_SECRET: &str = "zeq-aYEzS0aGdRJ8kNZTEg";
pub(crate) const GA_EVENT_NAME: &str = "node_telemetry_event";
pub(crate) const GA_MEASUREMENT_ID: &str = "G-96DM59YK2F";
Expand Down Expand Up @@ -45,8 +42,7 @@ pub async fn send_telemetry_event(state: Arc<AuthorityState>, is_validator: bool
let git_rev = env!("CARGO_PKG_VERSION").to_string();
let ip_address = get_ip().await;
let chain_identifier = match state.get_chain_identifier() {
// Unwrap safe: Checkpoint Digest is 32 bytes long
Some(chain_identifier) => Hex::encode(chain_identifier.into_inner().get(0..4).unwrap()),
Some(chain_identifier) => chain_identifier.to_string(),
None => "Unknown".to_string(),
};
let since_the_epoch = SystemTime::now()
Expand Down
22 changes: 22 additions & 0 deletions crates/sui-types/src/digests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,28 @@ impl fmt::UpperHex for Digest {
}
}

/// Representation of a network's identifier by the genesis checkpoint's digest
#[derive(
Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema,
)]
pub struct ChainIdentifier(CheckpointDigest);

impl fmt::Display for ChainIdentifier {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for byte in self.0 .0 .0[0..4].iter() {
write!(f, "{:02x}", byte)?;
}

Ok(())
}
}

impl From<CheckpointDigest> for ChainIdentifier {
fn from(digest: CheckpointDigest) -> Self {
Self(digest)
}
}

/// Representation of a Checkpoint's digest
#[derive(
Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema,
Expand Down
17 changes: 17 additions & 0 deletions crates/sui/src/client_commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -613,6 +613,10 @@ pub enum SuiClientCommands {
#[clap(long)]
signatures: Vec<String>,
},

/// Query the chain identifier from the rpc endpoint.
#[clap(name = "chain-identifier")]
ChainIdentifier,
}

impl SuiClientCommands {
Expand Down Expand Up @@ -1069,6 +1073,15 @@ impl SuiClientCommands {
.collect();
SuiClientCommandResult::Gas(coins)
}
SuiClientCommands::ChainIdentifier => {
let ci = context
.get_client()
.await?
.read_api()
.get_chain_identifier()
.await?;
SuiClientCommandResult::ChainIdentifier(ci)
}
SuiClientCommands::SplitCoin {
coin_id,
amounts,
Expand Down Expand Up @@ -1501,6 +1514,9 @@ impl Display for SuiClientCommandResult {
writeln!(writer, " {0: ^66} | {1: ^11}", gas.id(), gas.value())?;
}
}
SuiClientCommandResult::ChainIdentifier(ci) => {
writeln!(writer, "{}", ci)?;
}
SuiClientCommandResult::SplitCoin(response) => {
write!(writer, "{}", write_transaction_response(response)?)?;
}
Expand Down Expand Up @@ -1746,6 +1762,7 @@ pub enum SuiClientCommandResult {
SyncClientState,
NewAddress((SuiAddress, String, SignatureScheme)),
Gas(Vec<GasCoin>),
ChainIdentifier(String),
SplitCoin(SuiTransactionBlockResponse),
MergeCoin(SuiTransactionBlockResponse),
Switch(SwitchResponse),
Expand Down

0 comments on commit 5231444

Please sign in to comment.