Skip to content

Commit 5d95cd4

Browse files
committed
graphql-alt: Epoch
## Description Add support for query epochs (getting and multi-getting epochs by their IDs, and getting a checkpoint's epoch). ## Test plan ``` sui$ cargo nextest run -p sui-indexer-alt-e2e-tests ```
1 parent a924b45 commit 5d95cd4

File tree

17 files changed

+860
-2
lines changed

17 files changed

+860
-2
lines changed
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Copyright (c) Mysten Labs, Inc.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
//# init --protocol-version 70 --accounts A --simulator
5+
6+
//# create-checkpoint
7+
8+
//# advance-epoch
9+
10+
//# create-checkpoint
11+
12+
//# create-checkpoint
13+
14+
//# advance-epoch
15+
16+
//# create-checkpoint
17+
18+
//# run-graphql
19+
{
20+
c0: checkpoint(sequenceNumber: 0) { epoch { epochId } }
21+
c1: checkpoint(sequenceNumber: 1) { epoch { epochId } }
22+
c2: checkpoint(sequenceNumber: 2) { epoch { epochId } }
23+
c3: checkpoint(sequenceNumber: 3) { epoch { epochId } }
24+
c4: checkpoint(sequenceNumber: 4) { epoch { epochId } }
25+
c5: checkpoint(sequenceNumber: 5) { epoch { epochId } }
26+
c6: checkpoint(sequenceNumber: 6) { epoch { epochId } }
27+
c7: checkpoint(sequenceNumber: 7) { epoch { epochId } }
28+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
---
2+
source: external-crates/move/crates/move-transactional-test-runner/src/framework.rs
3+
---
4+
processed 8 tasks
5+
6+
init:
7+
A: object(0,0)
8+
9+
task 1, line 6:
10+
//# create-checkpoint
11+
Checkpoint created: 1
12+
13+
task 2, line 8:
14+
//# advance-epoch
15+
Epoch advanced: 0
16+
17+
task 3, line 10:
18+
//# create-checkpoint
19+
Checkpoint created: 3
20+
21+
task 4, line 12:
22+
//# create-checkpoint
23+
Checkpoint created: 4
24+
25+
task 5, line 14:
26+
//# advance-epoch
27+
Epoch advanced: 1
28+
29+
task 6, line 16:
30+
//# create-checkpoint
31+
Checkpoint created: 6
32+
33+
task 7, lines 18-28:
34+
//# run-graphql
35+
Response: {
36+
"data": {
37+
"c0": {
38+
"epoch": {
39+
"epochId": 0
40+
}
41+
},
42+
"c1": {
43+
"epoch": {
44+
"epochId": 0
45+
}
46+
},
47+
"c2": {
48+
"epoch": {
49+
"epochId": 0
50+
}
51+
},
52+
"c3": {
53+
"epoch": {
54+
"epochId": 1
55+
}
56+
},
57+
"c4": {
58+
"epoch": {
59+
"epochId": 1
60+
}
61+
},
62+
"c5": {
63+
"epoch": {
64+
"epochId": 1
65+
}
66+
},
67+
"c6": {
68+
"epoch": {
69+
"epochId": 2
70+
}
71+
},
72+
"c7": null
73+
}
74+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Copyright (c) Mysten Labs, Inc.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
//# init --protocol-version 70 --accounts A --simulator
5+
6+
//# advance-clock --duration-ns 123000000
7+
8+
//# advance-epoch
9+
10+
//# advance-clock --duration-ns 321000000
11+
12+
//# advance-epoch
13+
14+
//# advance-epoch
15+
16+
//# run-graphql
17+
{
18+
e0: epoch(epochId: 0) { ...E }
19+
e1: epoch(epochId: 1) { ...E }
20+
e2: epoch(epochId: 2) { ...E }
21+
22+
# This epoch doesn't exist yet
23+
e3: epoch(epochId: 3) { ...E }
24+
}
25+
26+
fragment E on Epoch {
27+
epochId
28+
referenceGasPrice
29+
startTimestamp
30+
endTimestamp
31+
}
32+
33+
//# run-graphql
34+
{ # This checkpoint is half way through the epoch, so the epoch should return
35+
# its starting information, but not its ending information.
36+
checkpoint(sequenceNumber: 2) {
37+
query {
38+
epoch(epochId: 1) {
39+
epochId
40+
referenceGasPrice
41+
startTimestamp
42+
endTimestamp
43+
}
44+
}
45+
}
46+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
---
2+
source: external-crates/move/crates/move-transactional-test-runner/src/framework.rs
3+
---
4+
processed 8 tasks
5+
6+
init:
7+
A: object(0,0)
8+
9+
task 2, line 8:
10+
//# advance-epoch
11+
Epoch advanced: 0
12+
13+
task 4, line 12:
14+
//# advance-epoch
15+
Epoch advanced: 1
16+
17+
task 5, line 14:
18+
//# advance-epoch
19+
Epoch advanced: 2
20+
21+
task 6, lines 16-31:
22+
//# run-graphql
23+
Response: {
24+
"data": {
25+
"e0": {
26+
"epochId": 0,
27+
"referenceGasPrice": "1000",
28+
"startTimestamp": "1970-01-01T00:00:00Z",
29+
"endTimestamp": "1970-01-01T00:00:00.123Z"
30+
},
31+
"e1": {
32+
"epochId": 1,
33+
"referenceGasPrice": "1000",
34+
"startTimestamp": "1970-01-01T00:00:00.123Z",
35+
"endTimestamp": "1970-01-01T00:00:00.444Z"
36+
},
37+
"e2": {
38+
"epochId": 2,
39+
"referenceGasPrice": "1000",
40+
"startTimestamp": "1970-01-01T00:00:00.444Z",
41+
"endTimestamp": null
42+
},
43+
"e3": null
44+
}
45+
}
46+
47+
task 7, lines 33-46:
48+
//# run-graphql
49+
Response: {
50+
"data": {
51+
"checkpoint": {
52+
"query": {
53+
"epoch": {
54+
"epochId": 1,
55+
"referenceGasPrice": "1000",
56+
"startTimestamp": "1970-01-01T00:00:00.123Z",
57+
"endTimestamp": null
58+
}
59+
}
60+
}
61+
}
62+
}

crates/sui-indexer-alt-graphql/schema.graphql

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ String containing Base64-encoded binary data.
1010
"""
1111
scalar Base64
1212

13+
"""
14+
String representation of an arbitrary width, possibly signed integer
15+
"""
16+
scalar BigInt
17+
1318

1419
"""
1520
Checkpoints contain finalized transactions and are used for node synchronization and global transaction ordering.
@@ -24,6 +29,10 @@ type Checkpoint {
2429
"""
2530
query: Query
2631
"""
32+
The epoch that this checkpoint is part of.
33+
"""
34+
epoch: Epoch
35+
"""
2736
The timestamp at which the checkpoint is agreed to have happened according to consensus. Transactions that access time in this checkpoint will observe this timestamp.
2837
"""
2938
timestamp: DateTime
@@ -34,6 +43,37 @@ ISO-8601 Date and Time: RFC3339 in UTC with format: YYYY-MM-DDTHH:MM:SS.mmmZ. No
3443
"""
3544
scalar DateTime
3645

46+
"""
47+
Activity on Sui is partitioned in time, into epochs.
48+
49+
Epoch changes are opportunities for the network to reconfigure itself (perform protocol or system package upgrades, or change the committee) and distribute staking rewards. The network aims to keep epochs roughly the same duration as each other.
50+
51+
During a particular epoch the following data is fixed:
52+
53+
- protocol version,
54+
- reference gas price,
55+
- system package versions,
56+
- validators in the committee.
57+
"""
58+
type Epoch {
59+
"""
60+
The epoch's id as a sequence number that starts at 0 and is incremented by one at every epoch change.
61+
"""
62+
epochId: UInt53!
63+
"""
64+
The minimum gas price that a quorum of validators are guaranteed to sign a transaction for in this epoch.
65+
"""
66+
referenceGasPrice: BigInt
67+
"""
68+
The timestamp associated with the first checkpoint in the epoch.
69+
"""
70+
startTimestamp: DateTime
71+
"""
72+
The timestamp associated with the last checkpoint in the epoch (or `null` if the epoch has not finished yet).
73+
"""
74+
endTimestamp: DateTime
75+
}
76+
3777

3878
"""
3979
Interface implemented by GraphQL types representing entities that are identified by an address.
@@ -270,12 +310,24 @@ type Query {
270310
"""
271311
checkpoint(sequenceNumber: UInt53): Checkpoint
272312
"""
313+
Fetch an epoch by its ID.
314+
315+
Returns `null` if the epoch does not exist yet, or was pruned.
316+
"""
317+
epoch(epochId: UInt53!): Epoch
318+
"""
273319
Fetch checkpoints by their sequence numbers.
274320
275321
Returns a list of checkpoints that is guaranteed to be the same length as `keys`. If a checkpoint in `keys` could not be found in the store, its corresponding entry in the result will be `null`. This could be because the checkpoint does not exist yet, or because it was pruned.
276322
"""
277323
multiGetCheckpoints(keys: [UInt53!]!): [Checkpoint]!
278324
"""
325+
Fetch epochs by their IDs.
326+
327+
Returns a list of epochs that is guaranteed to be the same length as `keys`. If an epoch in `keys` could not be found in the store, its corresponding entry in the result will be `null`. This could be because the epoch does not exist yet, or because it was pruned.
328+
"""
329+
multiGetEpochs(keys: [UInt53!]!): [Epoch]!
330+
"""
279331
Fetch objects by their keys.
280332
281333
Returns a list of objects that is guaranteed to be the same length as `keys`. If an object in `keys` could not be found in the store, its corresponding entry in the result will be `null`. This could be because the object never existed, or because it was pruned.

crates/sui-indexer-alt-graphql/src/api/query.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use super::{
1111
scalars::{digest::Digest, sui_address::SuiAddress, uint53::UInt53},
1212
types::{
1313
checkpoint::Checkpoint,
14+
epoch::Epoch,
1415
move_package::{self, MovePackage, PackageKey},
1516
object::{self, Object, ObjectKey},
1617
service_config::ServiceConfig,
@@ -50,6 +51,14 @@ impl Query {
5051
Ok(Checkpoint::with_sequence_number(scope, sequence_number))
5152
}
5253

54+
/// Fetch an epoch by its ID.
55+
///
56+
/// Returns `null` if the epoch does not exist yet, or was pruned.
57+
async fn epoch(&self, ctx: &Context<'_>, epoch_id: UInt53) -> Result<Option<Epoch>, RpcError> {
58+
let scope = self.scope(ctx)?;
59+
Epoch::fetch(ctx, scope, epoch_id).await
60+
}
61+
5362
/// Fetch checkpoints by their sequence numbers.
5463
///
5564
/// Returns a list of checkpoints that is guaranteed to be the same length as `keys`. If a checkpoint in `keys` could not be found in the store, its corresponding entry in the result will be `null`. This could be because the checkpoint does not exist yet, or because it was pruned.
@@ -65,6 +74,22 @@ impl Query {
6574
.collect())
6675
}
6776

77+
/// Fetch epochs by their IDs.
78+
///
79+
/// Returns a list of epochs that is guaranteed to be the same length as `keys`. If an epoch in `keys` could not be found in the store, its corresponding entry in the result will be `null`. This could be because the epoch does not exist yet, or because it was pruned.
80+
async fn multi_get_epochs(
81+
&self,
82+
ctx: &Context<'_>,
83+
keys: Vec<UInt53>,
84+
) -> Result<Vec<Option<Epoch>>, RpcError> {
85+
let scope = self.scope(ctx)?;
86+
let epochs = keys
87+
.into_iter()
88+
.map(|k| Epoch::fetch(ctx, scope.clone(), k));
89+
90+
try_join_all(epochs).await
91+
}
92+
6893
/// Fetch objects by their keys.
6994
///
7095
/// Returns a list of objects that is guaranteed to be the same length as `keys`. If an object in `keys` could not be found in the store, its corresponding entry in the result will be `null`. This could be because the object never existed, or because it was pruned.

0 commit comments

Comments
 (0)