Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Gateway API to query transaction history #1310

Merged
merged 2 commits into from
Apr 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 19 additions & 2 deletions sui/src/rest_gateway.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ use serde::Serialize;
use serde_json::json;

use sui_core::gateway_state::gateway_responses::TransactionResponse;
use sui_core::gateway_state::GatewayAPI;
use sui_types::base_types::{encode_bytes_hex, ObjectID, ObjectRef, SuiAddress};
use sui_core::gateway_state::{GatewayAPI, GatewayTxSeqNumber};
use sui_types::base_types::{encode_bytes_hex, ObjectID, ObjectRef, SuiAddress, TransactionDigest};
use sui_types::messages::{Transaction, TransactionData};
use sui_types::object::ObjectRead;

Expand Down Expand Up @@ -213,6 +213,23 @@ impl GatewayAPI for RestGatewayClient {
// TODO: Implement this.
Ok(0)
}

fn get_transactions_in_range(
&self,
start: GatewayTxSeqNumber,
end: GatewayTxSeqNumber,
) -> Result<Vec<(GatewayTxSeqNumber, TransactionDigest)>, anyhow::Error> {
// TODO: Implement this.
Ok(vec![])
}

fn get_recent_transactions(
&self,
count: u64,
) -> Result<Vec<(GatewayTxSeqNumber, TransactionDigest)>, anyhow::Error> {
// TODO: Implement this.
Ok(vec![])
}
}

impl RestGatewayClient {
Expand Down
16 changes: 15 additions & 1 deletion sui_core/src/authority/authority_store.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) 2022, Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0
use super::*;
use crate::gateway_state::GatewayTxSeqNumber;

use rocksdb::Options;
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -575,7 +576,7 @@ impl<const ALL_OBJ_VER: bool, S: Eq + Serialize + for<'de> Deserialize<'de>>
mutated_objects: HashMap<ObjectRef, Object>,
certificate: CertifiedTransaction,
effects: TransactionEffects,
sequence_number: TxSequenceNumber,
sequence_number: GatewayTxSeqNumber,
) -> SuiResult {
let transaction_digest = certificate.digest();
let mut temporary_store =
Expand Down Expand Up @@ -854,6 +855,19 @@ impl<const ALL_OBJ_VER: bool, S: Eq + Serialize + for<'de> Deserialize<'de>>
write_batch.write().map_err(SuiError::from)
}

pub fn transactions_in_seq_range(
&self,
start: GatewayTxSeqNumber,
end: GatewayTxSeqNumber,
) -> SuiResult<Vec<(GatewayTxSeqNumber, TransactionDigest)>> {
Ok(self
.executed_sequence
.iter()
.skip_to(&start)?
.take_while(|(seq, _tx)| *seq < end)
.collect())
}

/// Retrieves batches including transactions within a range.
///
/// This function returns all signed batches that enclose the requested transaction
Expand Down
66 changes: 66 additions & 0 deletions sui_core/src/gateway_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ pub type AsyncResult<'a, T, E> = future::BoxFuture<'a, Result<T, E>>;

pub type GatewayClient = Box<dyn GatewayAPI + Sync + Send>;

pub type GatewayTxSeqNumber = u64;

const MAX_TX_RANGE_SIZE: u64 = 4096;

pub struct GatewayState<A> {
authorities: AuthorityAggregator<A>,
store: Arc<GatewayStore>,
Expand Down Expand Up @@ -179,6 +183,20 @@ pub trait GatewayAPI {

/// Get the total number of transactions ever happened in history.
fn get_total_transaction_number(&self) -> Result<u64, anyhow::Error>;

/// Return the list of transactions with sequence number in range [`start`, end).
/// `start` is included, `end` is excluded.
fn get_transactions_in_range(
&self,
start: GatewayTxSeqNumber,
end: GatewayTxSeqNumber,
) -> Result<Vec<(GatewayTxSeqNumber, TransactionDigest)>, anyhow::Error>;

/// Return the most recent `count` transactions.
fn get_recent_transactions(
&self,
count: u64,
) -> Result<Vec<(GatewayTxSeqNumber, TransactionDigest)>, anyhow::Error>;
}

impl<A> GatewayState<A>
Expand Down Expand Up @@ -725,4 +743,52 @@ where
fn get_total_transaction_number(&self) -> Result<u64, anyhow::Error> {
Ok(self.store.next_sequence_number()?)
}

fn get_transactions_in_range(
&self,
start: GatewayTxSeqNumber,
end: GatewayTxSeqNumber,
) -> Result<Vec<(GatewayTxSeqNumber, TransactionDigest)>, anyhow::Error> {
fp_ensure!(
start <= end,
SuiError::GatewayInvalidTxRangeQuery {
error: format!(
"start must not exceed end, (start={}, end={}) given",
start, end
),
}
.into()
);
fp_ensure!(
end - start <= MAX_TX_RANGE_SIZE,
SuiError::GatewayInvalidTxRangeQuery {
error: format!(
"Number of transactions queried must not exceed {}, {} queried",
MAX_TX_RANGE_SIZE,
end - start
),
}
.into()
);
Ok(self.store.transactions_in_seq_range(start, end)?)
}

fn get_recent_transactions(
&self,
count: u64,
) -> Result<Vec<(GatewayTxSeqNumber, TransactionDigest)>, anyhow::Error> {
fp_ensure!(
count <= MAX_TX_RANGE_SIZE,
SuiError::GatewayInvalidTxRangeQuery {
error: format!(
"Number of transactions queried must not exceed {}, {} queried",
MAX_TX_RANGE_SIZE, count
),
}
.into()
);
let end = self.get_total_transaction_number()?;
let start = if end >= count { end - count } else { 0 };
self.get_transactions_in_range(start, end)
}
}
19 changes: 16 additions & 3 deletions sui_core/src/unit_tests/gateway_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2103,7 +2103,7 @@ async fn test_coin_merge() {
}

#[tokio::test]
async fn test_get_total_transaction_number() -> Result<(), anyhow::Error> {
async fn test_recent_transactions() -> Result<(), anyhow::Error> {
let (mut client, authority_clients) = make_address_manager(4).await;
let (addr1, key1) = get_key_pair();
let (addr2, _) = get_key_pair();
Expand All @@ -2122,20 +2122,33 @@ async fn test_get_total_transaction_number() -> Result<(), anyhow::Error> {
)
.await;

assert_eq!(client.get_total_transaction_number()?, 0);
let mut cnt = 0;
let mut digests = vec![];
for obj_id in [object_id1, object_id2, object_id3] {
assert_eq!(client.get_total_transaction_number()?, cnt);
let data = client
.transfer_coin(addr1, obj_id, gas_object, 50000, addr2)
.await
.unwrap();
let signature = key1.sign(&data.to_bytes());
client
let response = client
.execute_transaction(Transaction::new(data, signature))
.await?;
digests.push((cnt, *response.to_effect_response()?.0.digest()));
cnt += 1;
assert_eq!(client.get_total_transaction_number()?, cnt);
}
// start must <= end.
assert!(client.get_transactions_in_range(2, 1).is_err());
assert!(client.get_transactions_in_range(1, 1).unwrap().is_empty());
// Extends max range allowed.
assert!(client.get_transactions_in_range(1, 100000).is_err());
let txs = client.get_recent_transactions(10)?;
assert_eq!(txs.len(), 3);
assert_eq!(txs, digests);
let txs = client.get_transactions_in_range(0, 10)?;
assert_eq!(txs.len(), 3);
assert_eq!(txs, digests);

Ok(())
}
Expand Down
4 changes: 4 additions & 0 deletions sui_core/tests/staged/sui.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -755,6 +755,10 @@ SuiError:
STRUCT:
- error: STR
92:
GatewayInvalidTxRangeQuery:
STRUCT:
- error: STR
93:
OnlyOneConsensusClientPermitted: UNIT
TransactionData:
STRUCT:
Expand Down
2 changes: 2 additions & 0 deletions sui_types/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,8 @@ pub enum SuiError {
},
#[error("Inconsistent results observed in the Gateway. This should not happen and typically means there is a bug in the Sui implementation. Details: {error:?}")]
InconsistentGatewayResult { error: String },
#[error("Invalid transactiojn range query to the gateway: {:?}", error)]
GatewayInvalidTxRangeQuery { error: String },

// Errors related to the authority-consensus interface.
#[error("Authority state can be modified by a single consensus client at the time")]
Expand Down