Skip to content

Commit

Permalink
[gql][indexer] index chain identifier into its own table (MystenLabs#…
Browse files Browse the repository at this point in the history
…18825)

This PR puts chain identifier into its own table so that queries of
chain identifier does not depend on the existence of checkpoint 0 in the
db, which may be pruned away.

Tested against devnet locally and added a gql e2e test.

---

Check each box that your changes affect. If none of the boxes relate to
your changes, release notes aren't required.

For each box you select, include information after the relevant heading
that describes the impact of your changes that a user might notice and
any actions they must take to implement updates.

- [ ] Protocol:
- [ ] Nodes (Validators and Full nodes):
- [ ] Indexer:
- [ ] JSON-RPC:
- [x] GraphQL: Added a way to always have `chainIdentifier` query return
the correct chain ID even when pruning is enabled.
- [ ] CLI:
- [ ] Rust SDK:
- [ ] REST API:

---------

Co-authored-by: stefan-mysten <135084671+stefan-mysten@users.noreply.github.com>
Co-authored-by: Ashok Menon <ashok@mystenlabs.com>
  • Loading branch information
3 people committed Jul 30, 2024
1 parent f4cef69 commit 16c31d6
Show file tree
Hide file tree
Showing 8 changed files with 78 additions and 13 deletions.
16 changes: 16 additions & 0 deletions crates/sui-graphql-e2e-tests/tests/epoch/chain_identifier.exp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
processed 3 tasks

init:
C: object(0,0)

task 1, line 7:
//# create-checkpoint
Checkpoint created: 1

task 2, lines 9-12:
//# run-graphql
Response: {
"data": {
"chainIdentifier": "8f58ad28"
}
}
12 changes: 12 additions & 0 deletions crates/sui-graphql-e2e-tests/tests/epoch/chain_identifier.move
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

//# init --protocol-version 48 --simulator --accounts C


//# create-checkpoint

//# run-graphql
{
chainIdentifier
}
12 changes: 4 additions & 8 deletions crates/sui-graphql-rpc/src/types/chain_identifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ use crate::{
error::Error,
};
use async_graphql::*;
use diesel::{ExpressionMethods, QueryDsl};
use sui_indexer::schema::checkpoints;
use diesel::QueryDsl;
use sui_indexer::schema::chain_identifier;
use sui_types::{
digests::ChainIdentifier as NativeChainIdentifier, messages_checkpoint::CheckpointDigest,
};
Expand All @@ -17,15 +17,11 @@ pub(crate) struct ChainIdentifier;
impl ChainIdentifier {
/// Query the Chain Identifier from the DB.
pub(crate) async fn query(db: &Db) -> Result<NativeChainIdentifier, Error> {
use checkpoints::dsl;
use chain_identifier::dsl;

let digest_bytes = db
.execute(move |conn| {
conn.first(move || {
dsl::checkpoints
.select(dsl::checkpoint_digest)
.order_by(dsl::sequence_number.asc())
})
conn.first(move || dsl::chain_identifier.select(dsl::checkpoint_digest))
})
.await
.map_err(|e| Error::Internal(format!("Failed to fetch genesis digest: {e}")))?;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- This file should undo anything in `up.sql`
DROP TABLE IF EXISTS chain_identifier;
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
-- Your SQL goes here
CREATE TABLE chain_identifier
(
checkpoint_digest BYTEA NOT NULL,
PRIMARY KEY(checkpoint_digest)
);
8 changes: 7 additions & 1 deletion crates/sui-indexer/src/models/checkpoints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,15 @@ use sui_types::digests::CheckpointDigest;
use sui_types::gas::GasCostSummary;

use crate::errors::IndexerError;
use crate::schema::checkpoints;
use crate::schema::{chain_identifier, checkpoints};
use crate::types::IndexedCheckpoint;

#[derive(Queryable, Insertable, Selectable, Debug, Clone, Default)]
#[diesel(table_name = chain_identifier)]
pub struct StoredChainIdentifier {
pub checkpoint_digest: Vec<u8>,
}

#[derive(Queryable, Insertable, Selectable, Debug, Clone, Default)]
#[diesel(table_name = checkpoints)]
pub struct StoredCheckpoint {
Expand Down
7 changes: 7 additions & 0 deletions crates/sui-indexer/src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@
// SPDX-License-Identifier: Apache-2.0
// @generated automatically by Diesel CLI.

diesel::table! {
chain_identifier (checkpoint_digest) {
checkpoint_digest -> Bytea,
}
}

diesel::table! {
checkpoints (sequence_number) {
sequence_number -> Int8,
Expand Down Expand Up @@ -276,6 +282,7 @@ diesel::table! {
macro_rules! for_all_tables {
($action:path) => {
$action!(
chain_identifier,
checkpoints,
epochs,
events,
Expand Down
28 changes: 24 additions & 4 deletions crates/sui-indexer/src/store/pg_indexer_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ use crate::errors::{Context, IndexerError};
use crate::handlers::EpochToCommit;
use crate::handlers::TransactionObjectChangesToCommit;
use crate::metrics::IndexerMetrics;
use crate::models::checkpoints::StoredChainIdentifier;
use crate::models::checkpoints::StoredCheckpoint;
use crate::models::display::StoredDisplay;
use crate::models::epoch::StoredEpochInfo;
Expand All @@ -39,9 +40,9 @@ use crate::models::objects::{
use crate::models::packages::StoredPackage;
use crate::models::transactions::StoredTransaction;
use crate::schema::{
checkpoints, display, epochs, events, objects, objects_history, objects_snapshot, packages,
transactions, tx_calls, tx_changed_objects, tx_digests, tx_input_objects, tx_recipients,
tx_senders,
chain_identifier, checkpoints, display, epochs, events, objects, objects_history,
objects_snapshot, packages, transactions, tx_calls, tx_changed_objects, tx_digests,
tx_input_objects, tx_recipients, tx_senders,
};
use crate::types::{IndexedCheckpoint, IndexedEvent, IndexedPackage, IndexedTransaction, TxIndex};
use crate::{read_only_blocking, transactional_blocking_with_retry};
Expand Down Expand Up @@ -468,8 +469,27 @@ impl<T: R2D2Connection + 'static> PgIndexerStore<T> {
}

fn persist_checkpoints(&self, checkpoints: Vec<IndexedCheckpoint>) -> Result<(), IndexerError> {
if checkpoints.is_empty() {
let Some(first_checkpoint) = checkpoints.first() else {
return Ok(());
};

// If the first checkpoint has sequence number 0, we need to persist the digest as
// chain identifier.
if first_checkpoint.sequence_number == 0 {
transactional_blocking_with_retry!(
&self.blocking_cp,
|conn| {
let checkpoint_digest =
first_checkpoint.checkpoint_digest.into_inner().to_vec();
insert_or_ignore_into!(
chain_identifier::table,
StoredChainIdentifier { checkpoint_digest },
conn
);
Ok::<(), IndexerError>(())
},
PG_DB_COMMIT_SLEEP_DURATION
)?;
}
let guard = self
.metrics
Expand Down

0 comments on commit 16c31d6

Please sign in to comment.